[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -2,21 +2,167 @@
|
||||
id: wiki-2026-0508-secret-management
|
||||
title: Secret Management
|
||||
category: 10_Wiki/Topics
|
||||
status: merged
|
||||
redirect_to: 보안_및_시스템_신뢰성_표준
|
||||
canonical_id: wiki-2026-0507-039
|
||||
aliases: []
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Secrets Management, Credential Management, Vault]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [security, devsecops, credentials, kms]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: multi
|
||||
framework: vault-aws-kms
|
||||
---
|
||||
|
||||
# Redirect
|
||||
# Secret Management
|
||||
|
||||
이 문서는 Canonical 문서인 [[보안_및_시스템_신뢰성_표준]]으로 통합되었습니다.
|
||||
모든 최신 지식과 세부 내용은 위 링크를 참조하십시오.
|
||||
## 매 한 줄
|
||||
> **"매 secret 은 매 git 에 절대 — 매 vault 에"**. Secret management 는 매 API key, DB password, certificate, signing key 의 매 lifecycle (issue, store, rotate, revoke, audit) 의 매 centralized control. 2026 현재 매 HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Doppler, Infisical 가 매 dominant; 매 SPIFFE/SPIRE workload identity, 매 short-lived (15min) tokens 가 매 long-lived API key 를 매 replace.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Anti-secrets
|
||||
- Hardcoded in source.
|
||||
- Plain in `.env` committed.
|
||||
- Shared via Slack DM.
|
||||
- Long-lived (years) static API keys.
|
||||
|
||||
### 매 Pillars
|
||||
- **Encryption at rest**: KMS-backed.
|
||||
- **Encryption in transit**: TLS-only.
|
||||
- **Access control**: RBAC + audit log.
|
||||
- **Rotation**: automated (DB pwd, KMS key).
|
||||
- **Workload identity**: 매 service ≠ user — 매 ephemeral token 의 매 cloud IAM.
|
||||
- **Detection**: 매 git pre-commit (gitleaks, trufflehog) + 매 GitHub secret scanning.
|
||||
|
||||
### 매 응용
|
||||
1. App → DB: dynamic creds.
|
||||
2. CI → cloud: OIDC federation, no static keys.
|
||||
3. K8s pod → AWS: IRSA / Workload Identity.
|
||||
4. Cross-service: SPIFFE SVID.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Vault dynamic DB cred
|
||||
```bash
|
||||
vault write database/roles/app-readonly \
|
||||
db_name=postgres-prod \
|
||||
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
|
||||
default_ttl=1h max_ttl=24h
|
||||
|
||||
# App requests cred
|
||||
vault read database/creds/app-readonly
|
||||
# username: v-token-app-readonly-x9a..., password: A1b2C3..., lease_id: ..., lease_duration: 3600
|
||||
```
|
||||
|
||||
### GitHub Actions OIDC → AWS (no static keys)
|
||||
```yaml
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: arn:aws:iam::123:role/github-deploy
|
||||
aws-region: us-east-1
|
||||
- run: aws s3 sync ./build s3://prod-bucket/
|
||||
```
|
||||
|
||||
### Pre-commit secret scan
|
||||
```yaml
|
||||
# .pre-commit-config.yaml
|
||||
repos:
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.18.0
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
```
|
||||
|
||||
### App-side fetch with caching
|
||||
```typescript
|
||||
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
|
||||
const sm = new SecretsManagerClient({});
|
||||
const cache = new Map<string, { value: any; expires: number }>();
|
||||
|
||||
async function getSecret(name: string): Promise<any> {
|
||||
const cached = cache.get(name);
|
||||
if (cached && cached.expires > Date.now()) return cached.value;
|
||||
const res = await sm.send(new GetSecretValueCommand({ SecretId: name }));
|
||||
const value = JSON.parse(res.SecretString!);
|
||||
cache.set(name, { value, expires: Date.now() + 5 * 60_000 });
|
||||
return value;
|
||||
}
|
||||
```
|
||||
|
||||
### K8s External Secrets Operator
|
||||
```yaml
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata: { name: db-creds }
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef: { name: vault-backend, kind: ClusterSecretStore }
|
||||
target: { name: db-creds }
|
||||
data:
|
||||
- secretKey: password
|
||||
remoteRef: { key: database/creds/app, property: password }
|
||||
```
|
||||
|
||||
### Rotation Lambda
|
||||
```typescript
|
||||
export async function rotateApiKey(event) {
|
||||
const step = event.Step;
|
||||
if (step === "createSecret") {
|
||||
const newKey = await crypto.randomUUID();
|
||||
await sm.putSecretValue({ SecretId: event.SecretId, ClientRequestToken: event.ClientRequestToken, SecretString: newKey, VersionStages: ["AWSPENDING"] });
|
||||
} else if (step === "setSecret") { /* configure target */ }
|
||||
else if (step === "testSecret") { /* test */ }
|
||||
else if (step === "finishSecret") {
|
||||
await sm.updateSecretVersionStage({ SecretId: event.SecretId, VersionStage: "AWSCURRENT", MoveToVersionId: event.ClientRequestToken });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Tool |
|
||||
|---|---|
|
||||
| 매 multi-cloud, 매 self-host | HashiCorp Vault |
|
||||
| 매 AWS-only | Secrets Manager + Parameter Store |
|
||||
| 매 dev-friendly UX | Doppler / Infisical |
|
||||
| 매 K8s | External Secrets Operator + cloud KMS |
|
||||
| 매 workload-to-workload | SPIFFE/SPIRE |
|
||||
|
||||
**기본값**: Cloud-native (Secrets Manager) + OIDC for CI + ESO for K8s.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[DevSecOps_Framework]] · [[Application Security]]
|
||||
- 변형: [[KMS]] · [[PKI]]
|
||||
- 응용: [[CI_CD_Pipeline]] · [[Zero-Trust Architecture]]
|
||||
- Adjacent: [[OWASP Top 10]] · [[OAuth 2.0]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: Secret-scanner triage (매 actual secret vs 매 test fixture?), rotation runbook generation, IAM policy synthesis from natural-language requirement.
|
||||
**언제 X**: 매 secret 자체를 매 LLM context 에 매 넣지 마. 매 leak risk.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`.env` in git**: 매 even private repo — 매 contributor leak.
|
||||
- **Long-lived keys**: 매 5-year IAM access key — 매 incident blast-radius huge.
|
||||
- **Shared service account**: 매 audit trail 의 매 useless.
|
||||
- **Plain ENV var visible to all containers**: 매 sidecar / multi-tenant — 매 leak.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (NIST SP 800-57, OWASP ASVS V6, CIS Benchmarks).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — OIDC federation + workload identity 2026 |
|
||||
|
||||
Reference in New Issue
Block a user