0Pricing
C# Academy · 강의

보안 정보 관리

개발 환경에서는 .NET User Secrets를, 프로덕션에서는 Azure Key Vault 또는 환경 변수를 사용해 보안 정보를 안전하게 저장합니다.

보안 정보 관리은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 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.json

User 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 config

HashiCorp 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/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“보안 정보 관리”에서 뭘 배우나요?

개발 환경에서는 .NET User Secrets를, 프로덕션에서는 Azure Key Vault 또는 환경 변수를 사용해 보안 정보를 안전하게 저장합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“보안 정보 관리” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 구성 소스와 공급자
  2. IOptions를 사용한 강력한 형식의 옵션
  3. 옵션 유효성 검사와 명명된 옵션
  4. 보안 정보 관리
← C# Academy(으)로 돌아가기