[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -0,0 +1,161 @@
---
id: devops-secrets-rotation-automation
title: Secrets Rotation — 자동 회전 / 무중단
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [devops, secrets, rotation, security, vibe-coding]
tech_stack: { language: "TS / AWS / Vault", applicable_to: ["DevOps"] }
applied_in: []
aliases: [secret rotation, AWS Secrets Manager, HashiCorp Vault, KMS, key rotation]
---
# Secrets Rotation
> Secret 영원히 같으면 leak 시 영원히 노출. **자동 회전 + 무중단 (dual-secret window)**. AWS Secrets Manager / HashiCorp Vault / Kubernetes External Secrets.
## 📖 핵심 개념
- Static secret: 수동 회전 — 잊혀짐.
- Dynamic secret: 매 요청마다 발급 (Vault dynamic creds).
- Dual-secret window: 새 secret 활성, 기존도 N분 유효.
- Lease: 짧은 시간만 유효, 갱신 필요.
## 💻 코드 패턴
### AWS Secrets Manager rotation
```ts
// Lambda rotation function (4-step)
export const handler = async (event: RotationEvent) => {
const { Step, SecretId, ClientRequestToken } = event;
switch (Step) {
case 'createSecret': return createSecret(SecretId, ClientRequestToken);
case 'setSecret': return setSecret(SecretId, ClientRequestToken); // DB 에 새 password 적용
case 'testSecret': return testSecret(SecretId, ClientRequestToken); // 새 password 로 연결 확인
case 'finishSecret': return finishSecret(SecretId, ClientRequestToken); // AWSCURRENT 로 promote
}
};
```
```hcl
# Terraform
resource "aws_secretsmanager_secret_rotation" "db" {
secret_id = aws_secretsmanager_secret.db.id
rotation_lambda_arn = aws_lambda_function.rotate.arn
rotation_rules { automatically_after_days = 30 }
}
```
### App 측 — refresh 주기
```ts
class SecretCache {
private cached: { value: string; fetchedAt: number } | null = null;
private ttlMs = 60_000;
async get(): Promise<string> {
if (!this.cached || Date.now() - this.cached.fetchedAt > this.ttlMs) {
const v = await fetchFromSecretsManager(this.secretId);
this.cached = { value: v, fetchedAt: Date.now() };
}
return this.cached.value;
}
}
```
### Dual-credential window
```sql
-- DB 에 user app_v1, app_v2 둘 다 존재
-- v1 active 동안 v2 만들고 → v2 로 새 deploy → v1 비활성
CREATE USER app_v2 WITH PASSWORD 'new';
GRANT ALL ON DATABASE app TO app_v2;
-- 새 pod 들 v2 사용 시작
-- 1시간 후
DROP USER app_v1;
```
### Vault dynamic creds
```ts
// app 이 매번 짧은 lease 의 creds 받음
const r = await vault.read('database/creds/readonly');
const { username, password, lease_id, lease_duration } = r.data;
setTimeout(() => vault.renew(lease_id), lease_duration * 0.7 * 1000);
```
### Kubernetes External Secrets
```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata: { name: db-secret }
spec:
refreshInterval: 1h
secretStoreRef: { name: aws-secrets, kind: ClusterSecretStore }
target: { name: db, creationPolicy: Owner }
data:
- secretKey: url
remoteRef: { key: app/db, property: url }
```
ESO 가 Secret 자동 sync — 회전되면 1h 안에 pod 에 반영. Pod restart 또는 reloader 로 새 값 로드.
### App restart on secret change
```yaml
# stakater/reloader 추가
metadata:
annotations:
reloader.stakater.com/auto: "true"
```
### KMS key rotation
```hcl
resource "aws_kms_key" "main" {
description = "App data"
deletion_window_in_days = 30
enable_key_rotation = true # 매년 자동 회전
}
```
### API key 회전 패턴
```ts
// 사용자 API key — 새거 발급 시 24h 둘 다 활성
async function rotateApiKey(userId: string): Promise<string> {
const old = await db.apiKeys.find(userId);
const newKey = generate();
await db.apiKeys.insert({ userId, key: newKey, status: 'active' });
await db.apiKeys.update(old.id, { status: 'sunset', expiresAt: now() + 24 * H });
return newKey;
}
```
## 🤔 의사결정 기준
| 종류 | 솔루션 |
|---|---|
| Cloud (AWS) | Secrets Manager + 자동 rotation lambda |
| Cloud (GCP) | Secret Manager + Cloud Functions |
| K8s | External Secrets Operator |
| Self-hosted | HashiCorp Vault |
| Static creds 만 | Doppler / 1Password Connect |
| Dynamic / short-lived | Vault dynamic secrets |
| Key encryption | KMS / Cloud KMS / Vault Transit |
## ❌ 안티패턴
- **Rotation 수동**: 잊혀짐. 자동.
- **새 secret 즉시 강제 — old 비활성**: 아직 transition 중인 pod 다운.
- **Secret env var 만 — restart 필요**: ESO + Reloader.
- **Repo 에 commit (`.env.prod`)**: leak. .gitignore + secret scan.
- **Logging 시 secret 출력**: 마스킹.
- **단일 user 모든 service 공유**: 한 leak = 전체.
- **회전 불가능한 client (mobile app)**: refresh token 쓰고 짧은 access.
- **Terraform state 안 secret 평문**: state encrypt + 권한 제한.
## 🤖 LLM 활용 힌트
- Secrets Manager / Vault + 자동 rotation lambda.
- App = 짧은 cache + 회전 가능 구조.
- ESO + Reloader = K8s 표준.
## 🔗 관련 문서
- [[DevOps_Terraform_Patterns]]
- [[Backend_API_Auth_Strategies]]
- [[Security_Encryption_at_Rest]]