76 lines
3.9 KiB
Markdown
76 lines
3.9 KiB
Markdown
---
|
|
status: Active
|
|
lastUpdated: 2026-09-18
|
|
applyTo:
|
|
- "Fuchs/Program.cs"
|
|
- "Fuchs/appsettings*.json"
|
|
- "OCORE/OCORE/Secrets/**"
|
|
- "OCORE_web/OCORE_web/Secrets/**"
|
|
relatedDecisions:
|
|
- "0031-shared-keyvault-dpapi-secret-management.md"
|
|
---
|
|
|
|
# Secret management (Key Vault + DPAPI)
|
|
|
|
## Summary
|
|
Fuchs loads its secrets (connection strings, API keys, mailer tokens, ...)
|
|
from the shared Azure Key Vault `pcwkeys` at startup, with a DPAPI-encrypted
|
|
local cache as an offline fallback. The mechanism is shared, host-type-agnostic
|
|
infrastructure owned by the `OCORE`/`OCORE_web` submodules ([0031](../Decisions/0031-shared-keyvault-dpapi-secret-management.md));
|
|
this doc covers how Fuchs specifically wires into it and where to make
|
|
changes. The full mechanism reference (naming/encoding rules, DI wiring,
|
|
cache format) is maintained independently in
|
|
`OCORE_web/.github_instructions/secretsmanagement.instructions.md`.
|
|
|
|
## How it works
|
|
1. `Fuchs/Program.cs` calls `builder.AddSecretManagement()`
|
|
(`OCORE_web.Secrets.SecretManagementWebExtensions`) as the first step in
|
|
`ConfigureServices`, before `FuchsOcmsIntranet.Initialize(configuration)`
|
|
or anything else reads `IConfiguration`.
|
|
2. That call, backed by `OCORE.Secrets.Extensions.SecretManagementExtensions`,
|
|
registers two configuration sources in order: the local DPAPI cache
|
|
(`secrets.cache`, offline fallback) first, then the live Azure Key Vault
|
|
(overrides the cache when reachable) using `PrefixKeyVaultSecretManager`
|
|
to filter to secrets named `fuchs--...` and map them onto
|
|
`IConfiguration` keys.
|
|
3. `KeyVaultSyncService` (a registered `BackgroundService`) periodically
|
|
re-pulls every key listed in `Fuchs:SecretManagement:ManagedSecretKeys`
|
|
from Key Vault, re-writes the DPAPI cache, and calls
|
|
`IConfigurationRoot.Reload()` so a running process picks up rotated
|
|
secrets without a restart.
|
|
4. A secret whose name is only known at runtime (not a fixed
|
|
`IConfiguration` key) — e.g. resolved from a DB job record — is instead
|
|
fetched directly via `OCORE.Secrets.Extensions.SecretsOnDemandLoader`,
|
|
bypassing `ManagedSecretKeys` and the periodic sync entirely.
|
|
5. In `Development`, `appsettings.Development.json` (git-ignored) can
|
|
override any of these values locally, bypassing Key Vault for that key;
|
|
`AssembleConnectionStrings` (`Fuchs/Program.cs`) additionally prefers
|
|
`_Dev`-suffixed credential keys so a reachable Key Vault can never hand a
|
|
dev machine production DB credentials.
|
|
|
|
## Key files
|
|
- `Fuchs/Program.cs` — `builder.AddSecretManagement()` call site and
|
|
`AssembleConnectionStrings`.
|
|
- `Fuchs/appsettings.json` — `SecretManagement` block (`VaultUri`,
|
|
`AppName: "fuchs"`, `CacheFilePath`, `SyncIntervalHours`,
|
|
`ManagedSecretKeys`) plus `"MANAGED_BY_KEYVAULT"` placeholders for every
|
|
managed key.
|
|
- `OCORE/Secrets/Extensions/SecretManagementExtensions.cs` — shared
|
|
Key Vault + DPAPI wiring and DI registration, used by every host type.
|
|
- `OCORE/Secrets/Extensions/SecretsOnDemandLoader.cs` — direct, cached,
|
|
runtime-name secret lookup outside the `ManagedSecretKeys` sync path.
|
|
- `OCORE/Secrets/Sync/KeyVaultSyncService.cs` — periodic re-sync +
|
|
`IConfigurationRoot.Reload()`.
|
|
- `OCORE/Secrets/Cache/DpapiSecretsCache.cs` — DPAPI encrypt/decrypt of the
|
|
local cache file.
|
|
- `OCORE_web/Secrets/SecretManagementWebExtensions.cs` — the
|
|
`WebApplicationBuilder.AddSecretManagement()` entry point Fuchs calls.
|
|
- `OCORE_web/.github_instructions/secretsmanagement.instructions.md` —
|
|
canonical mechanism reference (naming/encoding rules, cache format,
|
|
"adding a new secret" steps), kept current independently of this doc.
|
|
- `.github/copilot-instructions.md` ("Azure Key Vault — Secret Naming") —
|
|
the naming rules summarized for this repo, with the `fuchs--` prefix.
|
|
|
|
## Related decisions
|
|
- [0031 — Shared Key Vault + DPAPI secret management via OCORE/OCORE_web](../Decisions/0031-shared-keyvault-dpapi-secret-management.md)
|