🔒 보안

Vault

HashiCorp Vault

HashiCorp의 비밀 관리 도구. API 키, 비밀번호, 인증서 등을 안전하게 저장하고, 동적 비밀 생성, 데이터 암호화, 세밀한 접근 제어를 제공하는 중앙 집중형 보안 솔루션입니다.

📖 상세 설명

HashiCorp Vault는 비밀(Secrets)을 안전하게 저장하고 관리하기 위한 오픈소스 도구입니다. API 키, 비밀번호, 인증서, 암호화 키 등 민감한 데이터를 중앙에서 관리하고, 필요할 때만 안전하게 접근할 수 있도록 합니다.

현대 클라우드 네이티브 환경에서는 수많은 서비스가 데이터베이스, 외부 API, 다른 서비스에 접근하기 위해 비밀이 필요합니다. Vault는 이런 비밀들을 코드나 설정 파일에 하드코딩하는 대신, 중앙화된 안전한 저장소에서 관리하고, 감사 로그를 통해 모든 접근을 추적할 수 있게 합니다.

Vault 워크플로우

1
🔐
인증
(Auth)
2
권한 확인
(Policy)
3
🔑
비밀 발급
(Secret)
4
📝
감사 기록
(Audit)

Vault 아키텍처

클라이언트
CLI
UI
API
Agent
인증 방법
Token
LDAP
Kubernetes
AWS IAM
OIDC
Secret Engine
KV
Database
PKI
Transit
AWS
스토리지
Consul
Integrated
File
S3
봉인(Seal)
Shamir
AWS KMS
Azure Key Vault
GCP KMS

🔑 핵심 기능

📦

비밀 저장 (KV Store)

API 키, 비밀번호 등을 키-값 형태로 안전하게 저장. 버전 관리로 변경 이력 추적 가능.

🔄

동적 비밀 생성

요청 시 임시 데이터베이스 자격증명 생성. 사용 후 자동 폐기로 보안 강화.

🔐

암호화 서비스 (Transit)

데이터를 암호화/복호화하는 API 제공. 앱이 직접 키를 관리할 필요 없음.

📜

PKI 인증서 관리

내부 CA 운영. TLS 인증서 자동 발급 및 갱신으로 mTLS 구현 용이.

👥

세밀한 접근 제어

정책 기반 권한 관리. 누가 어떤 비밀에 접근할 수 있는지 세밀하게 제어.

📊

감사 로그

모든 접근과 작업을 기록. 규정 준수(SOC2, HIPAA 등) 요구사항 충족.

비밀 관리 도구 비교

기능 HashiCorp Vault AWS Secrets Manager Azure Key Vault
배포 방식 Self-hosted / Cloud Managed (AWS only) Managed (Azure only)
동적 비밀 DB, AWS, GCP, Azure 등 RDS만 지원 제한적
멀티 클라우드 완전 지원 AWS 전용 Azure 전용
암호화 서비스 Transit Engine KMS 별도 지원
PKI/인증서 내장 CA ACM 별도 지원
비용 OSS 무료 / Enterprise 유료 비밀당 과금 작업당 과금

💻 코드 예제

# Vault CLI 기본 사용법

# 1. Vault 서버 주소 설정
export VAULT_ADDR='https://vault.example.com:8200'

# 2. 로그인 (토큰 방식)
vault login $VAULT_TOKEN

# LDAP 로그인
vault login -method=ldap username=myuser

# 3. 비밀 저장 (KV v2)
vault kv put secret/myapp/config \
    db_host="db.example.com" \
    db_user="admin" \
    db_pass="supersecret123"

# 4. 비밀 읽기
vault kv get secret/myapp/config

# JSON 출력
vault kv get -format=json secret/myapp/config

# 특정 필드만 추출
vault kv get -field=db_pass secret/myapp/config

# 5. 동적 데이터베이스 자격증명 생성
# (사전에 database secret engine 설정 필요)
vault read database/creds/readonly

# 출력 예시:
# lease_id       database/creds/readonly/abc123
# lease_duration 1h
# username       v-token-readonly-xyz789
# password       A1b2C3d4E5f6!

# 6. Transit으로 데이터 암호화
vault write transit/encrypt/my-key \
    plaintext=$(echo "secret data" | base64)

# 7. 정책 확인
vault policy list
vault policy read myapp-policy
# Python에서 Vault 사용 (hvac 라이브러리)
import hvac
import os

# 1. Vault 클라이언트 초기화
client = hvac.Client(
    url=os.environ['VAULT_ADDR'],
    token=os.environ.get('VAULT_TOKEN')
)

# Kubernetes 인증 (Pod 내에서)
def login_with_kubernetes():
    with open('/var/run/secrets/kubernetes.io/serviceaccount/token') as f:
        jwt = f.read()

    client.auth.kubernetes.login(
        role='myapp-role',
        jwt=jwt,
        mount_point='kubernetes'
    )
    return client

# 2. 비밀 읽기 (KV v2)
def get_database_config():
    secret = client.secrets.kv.v2.read_secret_version(
        path='myapp/config',
        mount_point='secret'
    )
    return secret['data']['data']

config = get_database_config()
db_host = config['db_host']
db_pass = config['db_pass']

# 3. 동적 데이터베이스 자격증명
def get_db_credentials():
    creds = client.secrets.database.generate_credentials(
        name='readonly',
        mount_point='database'
    )
    return {
        'username': creds['data']['username'],
        'password': creds['data']['password'],
        'lease_id': creds['lease_id'],
        'lease_duration': creds['lease_duration']
    }

# 4. Transit 암호화
def encrypt_data(plaintext: str) -> str:
    import base64
    encoded = base64.b64encode(plaintext.encode()).decode()

    result = client.secrets.transit.encrypt_data(
        name='my-key',
        plaintext=encoded,
        mount_point='transit'
    )
    return result['data']['ciphertext']

def decrypt_data(ciphertext: str) -> str:
    import base64
    result = client.secrets.transit.decrypt_data(
        name='my-key',
        ciphertext=ciphertext,
        mount_point='transit'
    )
    return base64.b64decode(result['data']['plaintext']).decode()
# External Secrets Operator로 Vault 연동
# Kubernetes Secret을 Vault에서 자동 동기화

# 1. SecretStore 정의 (Vault 연결 설정)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: default
spec:
  provider:
    vault:
      server: "https://vault.example.com:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp-role"
          serviceAccountRef:
            name: "vault-auth"

---
# 2. ExternalSecret 정의 (동기화할 비밀 지정)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-secrets
  namespace: default
spec:
  refreshInterval: "1h"  # 1시간마다 갱신
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: myapp-secrets  # 생성될 K8s Secret 이름
    creationPolicy: Owner
  data:
    - secretKey: DB_HOST
      remoteRef:
        key: myapp/config
        property: db_host
    - secretKey: DB_PASSWORD
      remoteRef:
        key: myapp/config
        property: db_pass

---
# 3. Pod에서 Secret 사용
apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: app
      image: myapp:latest
      envFrom:
        - secretRef:
            name: myapp-secrets  # 자동 동기화된 Secret

💬 실무 대화 예시

주니어: 팀에서 DB 비밀번호를 환경변수로 관리하고 있는데, 배포할 때마다 수동으로 설정해야 해서 불편해요. 더 좋은 방법이 있을까요?
시니어: Vault 도입을 고려해봐. 비밀을 중앙에서 관리하고, 애플리케이션이 시작할 때 자동으로 가져오게 할 수 있어. Kubernetes라면 External Secrets Operator로 쉽게 연동할 수 있고.
주니어: 그런데 DB 비밀번호가 유출되면 어떻게 하죠? 교체하려면 모든 서비스를 재시작해야 하잖아요.
시니어: Vault의 동적 비밀 기능을 쓰면 돼. 요청할 때마다 임시 DB 계정을 만들고, 사용 후 자동 폐기해. 유출돼도 1시간 뒤면 무효화되니까 위험이 크게 줄어들어.
주니어: Vault 자체가 해킹당하면 모든 비밀이 노출되지 않나요?
시니어: Vault는 봉인(Seal) 상태에서는 암호화된 데이터를 해독할 수 없어. Shamir 키 분할이나 클라우드 KMS로 봉인 해제 키를 관리하면, 물리적으로 서버를 탈취해도 비밀을 읽을 수 없어.

⚠️ 주의사항

⚠️ Root 토큰은 즉시 폐기하라

초기 설정 후 Root 토큰은 반드시 폐기하세요. 모든 권한을 가진 토큰이 유출되면 전체 비밀이 노출됩니다. 일반 운영에는 최소 권한을 가진 정책 기반 토큰을 사용하세요.

⚠️ Unseal 키 관리

Shamir 방식 사용 시 Unseal 키를 안전하게 분산 보관하세요. 여러 담당자에게 분산하거나, AWS KMS 같은 Auto-Unseal을 사용하는 것을 권장합니다. 키 분실 시 데이터 복구가 불가능합니다.

⚠️ 감사 로그 활성화

프로덕션 환경에서는 반드시 감사 로그를 활성화하세요. 모든 접근과 변경을 기록해야 보안 사고 발생 시 추적이 가능하고, 규정 준수 요구사항도 충족할 수 있습니다.

⚠️ 고가용성 구성

Vault가 중단되면 애플리케이션이 비밀에 접근할 수 없습니다. 프로덕션에서는 반드시 HA 클러스터로 구성하고, 애플리케이션에 비밀 캐싱 전략을 적용하세요.

📋 성공 사례

🟢 스타트업의 비밀 관리 자동화

20개 이상의 마이크로서비스가 있는 환경에서, 각 서비스마다 환경변수로 비밀을 관리하던 것을 Vault + External Secrets Operator로 전환했습니다. 배포 시 수동 설정이 사라지고, 비밀 교체도 자동화되었습니다.

💡 결과: 배포 시간 50% 단축, 비밀 교체 시간 수시간 → 수분

🟢 금융 기업의 동적 DB 자격증명

PCI-DSS 준수를 위해 DB 자격증명의 수명을 1시간으로 제한해야 했습니다. Vault의 동적 비밀 기능으로 요청 시 임시 계정을 생성하고 자동 폐기하여, 감사 요구사항을 충족하면서도 개발자 경험을 저하시키지 않았습니다.

💡 결과: PCI-DSS 인증 획득, 자격증명 유출 위험 95% 감소

🟢 멀티 클라우드 환경의 통합 비밀 관리

AWS, GCP, 온프레미스에 분산된 인프라에서 각 클라우드의 비밀 관리 도구를 개별적으로 사용하던 것을 Vault로 통합했습니다. 단일 정책과 감사 로그로 모든 환경의 비밀을 일관되게 관리할 수 있게 되었습니다.

💡 결과: 관리 복잡도 70% 감소, 통합 감사 리포트 자동화

🧠 이해도 퀴즈

Vault의 "동적 비밀(Dynamic Secrets)" 기능의 주요 장점은 무엇인가요?

비밀을 더 빠르게 저장할 수 있다
요청 시 임시 자격증명을 생성하여, 유출되어도 자동 만료로 위험을 최소화한다
비밀을 여러 클라우드에 동시에 저장할 수 있다
비밀을 암호화하지 않고 저장할 수 있다

🔗 관련 용어

📚 학습 자료