remove user-secrets approach & prepare a pilot deploy

This commit is contained in:
hamid
2026-07-28 23:18:54 +03:30
parent 630c7907ec
commit 5885280b49
28 changed files with 639 additions and 142 deletions
@@ -6,8 +6,6 @@
<IsPackable>true</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<!-- Enables `dotnet user-secrets` for the local-dev connection string (never a committed secret). -->
<UserSecretsId>baya-web-api</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
@@ -9,9 +9,9 @@ namespace Baya.Web.Api.Configuration;
/// A database connection is required in every real environment; the JWE + field-encryption keys are
/// required only in <b>deployed</b> environments (Development keeps working dev-only defaults in
/// <c>appsettings.Development.json</c>, and the "Testing" environment runs on in-memory SQLite with
/// test-injected keys). The effect: a fresh clone with no user-secrets stops at boot with a clear
/// message instead of silently connecting somewhere unintended, and a deployment can never fall back
/// to a committed placeholder key.
/// test-injected keys). The effect: a clone whose configuration was never filled in stops at boot with
/// a clear message instead of silently connecting somewhere unintended, and a Production/Staging
/// deployment can never fall back to a committed placeholder or a dev-only key.
/// </summary>
public static class StartupSecretsGuard
{
@@ -39,7 +39,7 @@ public static class StartupSecretsGuard
RequireReal(errors, "ConnectionStrings:logDb", config.GetConnectionString("logDb"));
// Development supplies working dev-only keys via appsettings.Development.json; only deployed
// environments must inject real per-environment secrets (env vars / Key Vault / KMS).
// environments must supply real per-environment secrets.
if (!builder.Environment.IsDevelopment())
{
RequireReal(errors, "IdentitySettings:SecretKey", config["IdentitySettings:SecretKey"]);
@@ -53,8 +53,8 @@ public static class StartupSecretsGuard
throw new InvalidOperationException(
"Refusing to start: required secret configuration is missing or still a committed placeholder. " +
"Provide real values via user-secrets (Development) or environment variables (deployed) — see " +
"dev/post-phase/refinement/RUNBOOK.md.\n - " + string.Join("\n - ", errors));
"Provide real values in appsettings.<Environment>.json (or as Seams__…-style environment " +
"variables) — see DEPLOY.md.\n - " + string.Join("\n - ", errors));
}
private static void RequireReal(List<string> errors, string key, string? value)
@@ -1,11 +1,11 @@
{
"ConnectionStrings": {
"SqlServer": "Server=87.107.152.16,1433;Database=Baya;User Id=hamid_root_un_sa;Password=N8@s5Taw1zWeh@#Hm;TrustServerCertificate=True;Encrypt=False;",
"logDb":"Server=87.107.152.16,1433;Database=Baya_Logs;User Id=hamid_root_un_sa;Password=N8@s5Taw1zWeh@#Hm;TrustServerCertificate=True;Encrypt=False;"
"logDb": "Server=87.107.152.16,1433;Database=Baya_Logs;User Id=hamid_root_un_sa;Password=N8@s5Taw1zWeh@#Hm;TrustServerCertificate=True;Encrypt=False;"
},
"IdentitySettings": {
"SecretKey": "SET_VIA_USER_SECRETS_OR_ENV",
"Encryptkey": "SET_VIA_USER_SECRETS_OR_ENV",
"SecretKey": "dev-only-jwe-signing-key-not-for-production-0123456789abcdef",
"Encryptkey": "dev-only-16bytes",
"Issuer": "Balinyaar",
"Audience": "BalinyaarClient",
"NotBeforeMinutes": "0",
@@ -13,8 +13,9 @@
},
"Seams": {
"FieldEncryption": {
"Key": "SET_VIA_USER_SECRETS_OR_ENV",
"HashKey": "SET_VIA_USER_SECRETS_OR_ENV"
"//": "DO NOT CHANGE. Every encrypted column in the Baya database (phones, addresses, IBANs, clinical notes) was written with these exact values, and users.PhoneHash — which every login looks up — is derived from HashKey. Rotating either makes the existing data unreadable and locks every account out.",
"Key": "local-dev-field-encryption-key-not-for-production",
"HashKey": "local-dev-field-hash-key-not-for-production"
},
"ObjectStorage": {
"RootPath": ""
@@ -23,7 +24,8 @@
"Provider": "telegram",
"Telegram": {
"BaseUrl": "http://127.0.0.1:5010",
"ApiKey": "ab8984974bc1fe5ce514d0fd74f71c8738b3aed92a7e4d86",
"//": "Must equal the relay's API_KEY. NOT the value in telegram-otp-bot/.env.example — that one is published, so TelegramSmsSender rejects it.",
"ApiKey": "6a8dfaeea1aa375eb61da7663cadf23a3ea245fd939264dd",
"TimeoutSeconds": 10
}
},
@@ -34,11 +36,20 @@
}
},
"Cors": {
"AllowedOrigins": []
"AllowedOrigins": [
"https://balinyaar.ir",
"https://www.balinyaar.ir",
"http://localhost:3000"
]
},
"ForwardedHeaders": {
"//": "Docker bridge ranges — the reverse proxy (Caddy) shares a container network with the API, so its hop must be trusted for X-Forwarded-For to resolve the real client IP the rate limiter partitions on.",
"KnownProxies": [],
"KnownNetworks": []
"KnownNetworks": [
"172.16.0.0/12",
"192.168.0.0/16",
"10.0.0.0/8"
]
},
"AllowedHosts": "*",
"Kestrel": {