configuration-and-secretslisted
Install: claude install-skill Sarmkadan/dotnet-senior-skills
# Configuration and Secrets
## Secrets: the hard rules
- No secret in `appsettings*.json`, code, or anything git-tracked. Ever. A secret that touched a commit is compromised - rotate it; deleting the commit does not un-leak it.
- Local development: `dotnet user-secrets` (lives outside the repo) or environment variables. `appsettings.Development.json` is committed in most repos - it is NOT a secrets file.
- Production: a real secret store - Azure Key Vault / AWS Secrets Manager / Vault - loaded as a configuration provider, or platform-injected environment variables. Prefer the store: env vars appear in `docker inspect`, crash dumps, and diagnostic endpoints.
- Connection strings are secrets when they contain passwords. Prefer managed identity / IAM auth (`Authentication=Active Directory Default`) so the connection string stops being one.
- Review flag: any string named or shaped like `key`, `token`, `password`, `secret` assigned a literal. Also `DefaultAzureCredential` bypasses like raw account keys "temporarily".
## Options pattern, done properly
Inject `IOptions<T>` (or a snapshot), never `IConfiguration`, into services. `IConfiguration` in a constructor means stringly-typed access (`config["Smtp:Port"]`) scattered anywhere, untypeable, untestable, unvalidatable.
```csharp
public sealed class SmtpOptions
{
public const string Section = "Smtp";
[Required] public required string Host { get; init; }
[Range(1, 65535)] public int Port { get; init; } = 587;
}
serv