シークレット管理
開発環境では.NET User Secrets、本番環境ではAzure Key Vaultまたは環境変数を使って、シークレットを安全に保存します。
「シークレット管理」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
シークレットは構成ではない
パスワード、APIキー、接続文字列、JWT署名キーをappsettings.jsonに保存したり、ソース管理にコミットしたりしてはいけません。.NETには、シークレット管理専用の仕組みが複数用意されています。
User Secrets(開発)
User Secretsは、開発用のシークレットをプロジェクトディレクトリの外部にあるマシン固有のファイルへ保存します。Development環境では自動的に読み込まれ、ソースコードと一緒に扱われることはありません。
# Initialize (adds UserSecretsId to .csproj):
dotnet user-secrets init
# Set secrets:
dotnet user-secrets set "Database:Password" "dev-pass-123"
dotnet user-secrets set "Jwt:SigningKey" "dev-jwt-key-abc"
dotnet user-secrets set "OpenAI:ApiKey" "sk-..."
# List / remove:
dotnet user-secrets list
dotnet user-secrets remove "OpenAI:ApiKey"
# Stored at:
# macOS/Linux: ~/.microsoft/usersecrets/{id}/secrets.json
# Windows: %APPDATA%\Microsoft\UserSecrets\{id}\secrets.jsonUser Secretsの明示的な読み込み
Host.CreateApplicationBuilderは、Development環境でUser Secretsを自動的に読み込みます。Development以外のシナリオやテストプロジェクトでは、明示的に読み込むこともできます。
var builder = Host.CreateApplicationBuilder(args);
// Automatic (Development only) — already done by default
// Equivalent manual call:
if (builder.Environment.IsDevelopment())
builder.Configuration.AddUserSecrets<Program>();
// In test projects (no ASPNETCORE_ENVIRONMENT):
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true)
.AddUserSecrets<Program>() // loads secrets.json
.AddEnvironmentVariables()
.Build();本番環境の環境変数
本番環境では、シークレットを環境変数として注入します。実行時にOSまたはコンテナオーケストレーターから読み取られるため、コードと一緒に平文でディスクへ永続化されることはありません。
# docker-compose.yml — inject secrets:
services:
api:
image: myapp:latest
environment:
- Database__Password=${DB_PASSWORD} # from .env file
- Jwt__SigningKey=${JWT_KEY}
- ConnectionStrings__Default=Server=db;Password=${DB_PASSWORD}
# Kubernetes Secret:
kubectl create secret generic app-secrets \
--from-literal=Database__Password=secret123 \
--from-literal=Jwt__SigningKey=verylongkey
# Reference in pod spec:
# env:
# - name: Database__Password
# valueFrom:
# secretKeyRef: { name: app-secrets, key: Database__Password }Azure Key Vaultの統合
Azure Key Vaultは、本番環境向けのマネージドシークレットストアです。公式プロバイダーによってシークレットが構成システムへ直接読み込まれるため、アプリは他の構成値と同じように読み取れます。
// dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
// dotnet add package Azure.Identity
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
{
var kvUri = new Uri(builder.Configuration["Azure:KeyVaultUri"]!);
// Uses Managed Identity / workload identity in production:
builder.Configuration.AddAzureKeyVault(kvUri, new DefaultAzureCredential());
}
// Secrets named "Database--Password" in Key Vault
// are accessible as builder.Configuration["Database:Password"]
// (Key Vault uses -- as the : separator)AWS Secrets Manager
AWSでは、Amazon.Extensions.Configuration.SystemsManagerを使用するか、Secrets Managerを直接使用して、シークレットを.NETの構成パイプラインへ注入します。
// dotnet add package Amazon.Extensions.Configuration.SystemsManager
builder.Configuration.AddSystemsManager(
path: "/myapp/production", // parameter store prefix
optional: false,
reloadAfter: TimeSpan.FromMinutes(30));
// Or Secrets Manager directly:
using Amazon.SecretsManager;
using Amazon.SecretsManager.Model;
var client = new AmazonSecretsManagerClient();
var response = await client.GetSecretValueAsync(new GetSecretValueRequest
{
SecretId = "myapp/production/db-password"
});
var secret = response.SecretString; // JSON string
// Parse and inject into configHashiCorp Vault
HashiCorp Vaultは、動的なシークレット、シークレットのローテーション、きめ細かなアクセス制御を提供します。コミュニティ製のVaultSharpライブラリまたは構成プロバイダーを使用して.NETと統合します。
// dotnet add package VaultSharp
using VaultSharp;
using VaultSharp.V1.AuthMethods.Token;
var authMethod = new TokenAuthMethodInfo("vault-token");
var vaultClient = new VaultClient(
new VaultClientSettings("https://vault.example.com:8200", authMethod));
// Read a secret:
var kv = await vaultClient.V1.Secrets.KeyValue.V2
.ReadSecretAsync(path: "myapp/database", mountPoint: "secret");
var password = kv.Data.Data["password"].ToString();
// Then store in configuration or pass to IOptions:
builder.Configuration["Database:Password"] = password;メモリ上のシークレットの保護
メモリ上であっても、シークレットは慎重に扱う必要があります。SecureStringを使用するか、usingブロックでスコープを限定し、シークレットの値をログに出力しないようにします。
// NEVER log secrets:
_logger.LogInformation("API Key: {Key}", apiKey); // WRONG!
_logger.LogInformation("API Key configured: {HasKey}", !string.IsNullOrEmpty(apiKey)); // CORRECT
// Mask in diagnostics:
public string KeyHint => apiKey.Length > 8
? $"{apiKey[..4]}...{apiKey[^4..]}"
: "****";
// Scope the secret:
void ProcessWithSecret()
{
var secret = LoadSecret();
try { UseSecret(secret); }
finally { secret = string.Empty; } // clear reference
}CI/CDのシークレット
CI/CDパイプライン(GitHub Actions、Azure DevOps、Jenkins)には、シークレット変数ストアが用意されています。ビルドまたはデプロイ時にシークレットを環境変数として注入し、パイプラインのYAMLにハードコードしてはいけません。
# GitHub Actions — store in Settings > Secrets:
# name: Deploy
# on: push
# jobs:
# deploy:
# runs-on: ubuntu-latest
# env:
# Database__Password: ${{ secrets.DB_PASSWORD }}
# Jwt__SigningKey: ${{ secrets.JWT_KEY }}
# steps:
# - name: Run migration
# run: dotnet ef database update
# Azure Pipelines:
# variables:
# - group: my-app-secrets # from Azure DevOps Variable Group
# The secrets are masked in logs and never stored in plaintext実例:開発環境と本番環境のシークレット戦略
開発環境ではUser Secrets、本番環境ではAzure Key Vaultを使用し、フォールバックとして環境変数を利用する、完全なシークレット戦略の例です。
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
// Dev: local secrets.json, never committed
builder.Configuration.AddUserSecrets<Program>();
}
else
{
// Production: Azure Key Vault via Managed Identity
var kvUri = builder.Configuration["Azure:KeyVaultUri"];
if (!string.IsNullOrEmpty(kvUri))
builder.Configuration.AddAzureKeyVault(
new Uri(kvUri), new DefaultAzureCredential());
}
// Always load env vars (works in all environments + containers):
// Already loaded by CreateBuilder — they override Key Vault
// Bind secrets to strongly typed options:
builder.Services
.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.ValidateDataAnnotations()
.ValidateOnStart();クイックチェック
シークレットをappsettings.jsonに保存してはいけないのはなぜですか?
まとめ:シークレット管理
重要なポイント:
- シークレットを
appsettings.jsonに保存してはいけません — ソース管理にコミットされるためです - 開発環境:User Secrets(
dotnet user-secrets)を使用します — プロジェクトの外部に保存されます - 本番環境:環境変数、Azure Key Vault、AWS Secrets Manager、HashiCorp Vaultを使用します
- CI/CD:パイプラインのシークレットストアに保存し、環境変数として注入します
- 生のシークレット値をログに出力せず、ヒントやマスクを使用します
- 戦略を組み合わせます:開発環境ではUser Secrets、本番環境ではKey Vault、上書きには環境変数を使用します
よくある質問
「シークレット管理」レッスンは無料ですか?
はい。「シークレット管理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「シークレット管理」で何を学びますか?
開発環境では.NET User Secrets、本番環境ではAzure Key Vaultまたは環境変数を使って、シークレットを安全に保存します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「シークレット管理」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。