12 KiB
12 KiB
Vault 기준
목적
이 문서는 Kubernetes 환경에서 HashiCorp Vault 1.17+ 를 1000+ 서비스의 secret / PKI / dynamic credential 소스로 운영하기 위한 기준을 고정한다.
- Integrated Storage (Raft) HA + auto-unseal을 1차 권장 경로로 둔다
- 공식 Helm chart (
hashicorp/vault) values.yaml의 핵심 필드를 명시한다 - Vault Secrets Operator (VSO) 0.8+ CRD 경로를 secret delivery 기본값으로 둔다
- Vault Agent Injector는 Kubernetes Secret을 우회하고 싶은 워크로드의 2차 경로로 둔다
- Raft snapshot / audit device / telemetry / TLS / Kubernetes auth role을 운영 필수 요소로 둔다
공식 의미 (Vault 1.17+ 기준)
- Vault는 sealed 상태로 기동한다. Shamir 수동 unseal 또는 auto-unseal (
awskms,gcpckms,azurekeyvault,transit)로 unseal한다. - **Integrated Storage (Raft)**는 공식 지원 HA backend다. 기동 시
storage "raft"stanza,cluster_addr, listener의cluster_address가 모두 필요하다.ha_storage와 동시 선언 금지. - Vault는 두 포트를 쓴다:
8200(API/client),8201(cluster-to-cluster Raft replication). Service는 8201을 반드시 expose해야 peer-to-peer Raft가 성립한다. /v1/sys/health는 단일 endpoint로 상태 코드로 응답한다:200active,429standby (standbyok=true면 200),472DR secondary,473performance standby,501uninitialized,503sealed.- Audit device는 최소 하나 활성화해야 한다. audit device가 전부 실패하면 Vault는 요청 처리를 멈춘다(블로킹). 여러 개 운영 권장.
- Kubernetes auth method는 ServiceAccount JWT를 TokenReview API로 검증한다. Vault 1.17+는 short-lived projected SA token(
audiences)을 권장한다. - VSO 0.8+는
secrets.hashicorp.com/v1beta1API group을 사용하고VaultConnection,VaultAuth,VaultStaticSecret,VaultDynamicSecret,VaultPKISecret,HCPAuth,HCPVaultSecretsAppCRD를 제공한다. - Vault Agent Injector는
vault.hashicorp.com/agent-inject: "true"같은 Pod annotation으로 sidecar/init container를 주입해 secret을/vault/secrets/<name>파일로 렌더링한다. - DR replication / Performance replication은 Enterprise 기능이다. OSS에서는 Raft snapshot restore가 복구 경로다.
- Telemetry는
telemetry { prometheus_retention_time = "24h" disable_hostname = true }stanza로 활성화하고/v1/sys/metrics?format=prometheus에서 scrape한다.
기본 규칙
1. 배포는 공식 Helm chart (hashicorp/vault)
기본:
helm repo add hashicorp https://helm.releases.hashicorp.comserver.ha.enabled=true+server.ha.raft.enabled=trueinjector.enabled는 secret delivery 전략에 따라 결정 (VSO만 쓰면false)- values.yaml은 Git에 보관 + Helmfile / Argo CD Application로 배포
기본 금지:
- 수제 StatefulSet으로 처음부터 조립
dev모드 운영- chart 기본
standalone모드 production 사용 (single node + file storage)
2. HA topology: Raft 3-node 또는 5-node
기본:
server.ha.replicas: 3(과반수 장애 허용: 1 node)- critical path면
5로 확장 (2 node 장애 허용) server.ha.raft.setNodeId: true(각 pod의 hostname을 node_id로 자동 주입)- anti-affinity: hostname 기준 required, zone 기준 preferred
3. Raft config: listener 8200 + cluster 8201 + service_registration
server.ha.raft.config HCL에 최소한 아래 stanza가 필요하다.
ui = true
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_disable = 0
tls_cert_file = "/vault/tls/tls.crt"
tls_key_file = "/vault/tls/tls.key"
}
storage "raft" {
path = "/vault/data"
node_id = "$(HOSTNAME)"
}
cluster_addr = "https://$(HOSTNAME).vault-internal:8201"
api_addr = "https://$(HOSTNAME).vault-internal:8200"
service_registration "kubernetes" {}
telemetry {
prometheus_retention_time = "24h"
disable_hostname = true
}
cluster_addr는 headless service(vault-internal)의 pod FQDN을 쓴다. 8201 Service expose 필수.
4. Auto-unseal 채택 (1차 권장)
기본:
- AWS:
seal "awskms" { region = "..." kms_key_id = "..." } - GCP:
seal "gcpckms" { project = "..." region = "..." key_ring = "..." crypto_key = "..." } - Azure:
seal "azurekeyvault" { tenant_id = "..." vault_name = "..." key_name = "..." } - Vault-to-Vault:
seal "transit" { address = "..." token = "..." key_name = "autounseal" mount_path = "transit/" }
기본 금지:
- Shamir key를 CI/CD 환경변수나 Kubernetes Secret에 저장
- seal backend에 lifecycle 보호 없음 (KMS key deletion protection 필수)
5. Audit device는 최소 2개
Audit device 전부 실패 시 Vault가 요청을 block한다. redundancy 확보.
기본:
auth/kubernetes/login경로 포함 모든 API 감사file:server.auditStorage.enabled: true→/vault/audit/audit.logsyslog또는socket: 중앙 로그 파이프라인 (Loki, Splunk, CloudWatch)vault audit enable file file_path=/vault/audit/audit.log
기본 금지:
- audit device 0개 운영
- audit log PVC 용량 무제한 (log rotation + sink 필수)
6. TLS는 end-to-end
기본:
- cert-manager Certificate로
vault-tlsSecret 발급 (cluster issuer) - listener에
tls_cert_file,tls_key_file,tls_min_version = "tls13" - client (app, VSO, Injector)는 CA bundle trust
- Vault ↔ Storage ↔ seal backend 전 구간 TLS
7. Vault는 기본 내부 전용 (ClusterIP)
기본:
- Service type: ClusterIP (8200, 8201)
- Ingress 기본 금지
- 외부 관리자 접근은 VPN / bastion / port-forward / OIDC-protected admin Ingress
8. Probe: /v1/sys/health 상태코드 의미 반영
기본:
- readiness:
GET /v1/sys/health?standbyok=true&perfstandbyok=true&uninitcode=204(uninitialized를 200으로 수용 초기 bootstrap 허용) - liveness:
GET /v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204(sealed + uninit이어도 pod 생존) - startup: initialDelay 10s, failureThreshold 12 (2분 유예)
기본 금지:
GET /단순 probe- sealed 상태에서 liveness 실패 → 무한 재시작 루프
9. Kubernetes auth method 구성
Vault 쪽 (1회 bootstrap):
vault auth enable kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://kubernetes.default.svc.cluster.local" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
disable_iss_validation=false
Role은 ServiceAccount + namespace에 바인딩:
vault write auth/kubernetes/role/auth-server \
bound_service_account_names=auth-server \
bound_service_account_namespaces=auth-prod \
policies=auth-server-read \
ttl=1h \
audience=vault
기본 금지:
bound_service_account_names=*또는bound_service_account_namespaces=*- TTL 무한 또는 24h 이상
10. Secret delivery: VSO가 1차 권장
기본:
- 클러스터 전체 1개
VaultConnection(namespace:vault) - 앱 namespace마다
VaultAuth(ServiceAccount 바인딩) - 정적 KV 동기화:
VaultStaticSecret - 동적 DB credential:
VaultDynamicSecret - TLS 인증서:
VaultPKISecret destination.create: true로 K8s Secret 자동 생성,rolloutRestartTargets로 consumer 재시작
11. Vault Agent Injector: Kubernetes Secret 우회가 필요할 때
기본 annotation set:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "auth-server"
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/auth-server"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{ with secret "database/creds/auth-server" -}}
DATABASE_USERNAME={{ .Data.username }}
DATABASE_PASSWORD={{ .Data.password }}
{{- end }}
vault.hashicorp.com/agent-pre-populate-only: "true" # init-only (앱이 파일 1회 읽음)
vault.hashicorp.com/agent-inject-file-db-creds: "db.env"
기본:
- etcd에 민감정보를 남기고 싶지 않을 때 선택
- 앱이 파일 기반 secret 소비 가능해야 함
- 장기 실행 sidecar 대신
agent-pre-populate-only: "true"로 init container만 사용해 resource overhead 감소
12. Raft snapshot 백업은 운영 필수
기본:
- 하루 1회
vault operator raft snapshot saveCronJob - snapshot을 off-cluster object storage (S3, GCS, MinIO replicated bucket)에 저장
- retention 30일 이상 + 주간 / 월간 snapshot 분리
- restore 절차를 runbook으로 문서화
13. Telemetry + Prometheus scrape
기본:
- config:
telemetry { prometheus_retention_time = "24h" disable_hostname = true } - 내부 Prometheus token policy:
path "sys/metrics" { capabilities = ["read"] } - Prometheus scrape:
/v1/sys/metrics?format=prometheus+ Bearer token (unauth-endpoint 가능하지만 권장하지 않음)
14. 포트 expose: 8200 + 8201 둘 다
기본:
- Pod containerPort: 8200 (api), 8201 (cluster)
- Service
vault: ClusterIP, 8200 - Service
vault-internal: Headless, 8200 + 8201 (Raft peer discovery 필수) - 8201 누락 시 Raft peer-to-peer 실패, leader election 불가
15. Replication 경계: OSS vs Enterprise
DR replication, performance replication, namespace multi-tenancy는 Vault Enterprise 전용이다.
OSS 기준 복구:
- Raft snapshot restore로 state 복원
- 동일 seal backend 요구 (auto-unseal이면 KMS key 필요)
기본 금지:
- OSS에서 DR topology를 가정한 설계
- Enterprise 기능을 OSS manifest에 넣기
16. Security context: Restricted PSS
기본:
runAsNonRoot: true,runAsUser: 100(vault user)readOnlyRootFilesystem: trueallowPrivilegeEscalation: false,capabilities.drop: [ALL],capabilities.add: [IPC_LOCK](mlockall을 위함, swap 방지)seccompProfile: RuntimeDefault
17. Resource 요청
기본 단일 replica (Raft 3 node 클러스터 중 하나):
- requests:
cpu: 250m,memory: 256Mi - limits:
cpu: 1,memory: 512Mi
대규모 PKI / dynamic secret 발급량이 많으면 memory: 1Gi 이상.
18. Token / root token 취급
기본:
vault operator init출력 root token은 1회성 bootstrap- 초기 설정 완료 후
vault token revoke <root-token> - 장기 root 필요 시
vault operator generate-root절차로 ephemeral 생성 - app token은 Kubernetes auth login 경로로만 발급
- CLI history에 unseal key, root token 남기지 않음 (
HISTCONTROL=ignorespace)
19. 현재 스택 기본 권장안
- 배포: Helm chart
hashicorp/vault,server.ha.enabled=true+server.ha.raft.enabled=true - Replicas: 3
- Storage: Integrated Storage (Raft) + dataStorage PVC + auditStorage PVC
- Unseal: auto-unseal (awskms / gcpckms / azurekeyvault / transit)
- TLS: end-to-end, cert-manager Certificate
- Service: ClusterIP 8200 + Headless 8200/8201
- Ingress: 기본 금지 (관리자 경로만 OIDC-protected 예외)
- Probe:
/v1/sys/healthstatus-code aware - Audit: file + syslog 중복
- Secret delivery: VSO 1차, Injector 2차
- Backup: daily Raft snapshot → off-cluster object storage
프로젝트 기준 요약
- Helm chart 공식 배포, HA Raft 3-node, auto-unseal
- 8200 (client) + 8201 (cluster) Service expose 필수
/v1/sys/healthstatus-code 기반 probe- audit device 최소 2개, 전체 실패 시 block 특성 인지
- Kubernetes auth role은 SA + namespace 단위, wildcard 금지
- VSO 1차 / Injector 2차 (
agent-pre-populate-onlyinit-only 선호) - Raft snapshot daily CronJob → off-cluster 보관
- Telemetry
/v1/sys/metrics?format=prometheus+ Prometheus token policy - DR/perf replication은 Enterprise 기능, OSS 경계 분명
- Restricted PSS + IPC_LOCK capability (mlockall)