안녕하세요. 인포그랩에서 DevOps 엔지니어로 일하는 Chris입니다. 현대 클라우드 환경에서는 데이터베이스(DB) 비밀번호, API 키, 인증서, 암호화 키 등 민감정보를 안전하게 보호하는 일이 매우 중요합니다.
그러나 단순한 암호화만으로는 불충분합니다. 실질적인 보안을 위해서는 키 관리, 접근 제어, 감사 로깅까지 종합적으로 고려한 보안 아키텍처가 필요합니다.
HashiCorp Vault는 이러한 요구사항을 효과적으로 충족하는 엔터프라이즈급 비밀 관리 시스템입니다. Vault는 Seal/Unseal 메커니즘으로 Root Key를 보호하고, Barrier 암호화로 저장소를 보호하며, 정책 기반 접근 제어와 감사 로깅으로 모든 접근을 통제합니다.
이 글에서는 Vault가 민감정보를 보호하는 방법을 코드베이스 관점에서 살펴보겠습니다. 먼저 Vault의 기본 개념과 역할 을 살펴본 다음, 다층 보안 모델을 분석합니다. 이어서 Vault의 암호화 서비스와 내부 보안 메커니즘을 설명하고, 암호화 과정과 접근 제어 방식을 알아보겠습니다.
Vault의 기본 개념과 역할
Vault는 민감정보를 중앙에서 관리하는 비밀 관리 플랫폼입니다. 애플리케이션 코드나 설정 파일에 흩어진 비밀번호, API 키, 인증서 등을 Vault에 집중해 보안성과 관리 효율성을 동시에 높입니다.
핵심 역할
- 민감정보 암호화 저장: Vault는 내부 데이터를 Barrier 암호화로 보호합니다. 암호화 키는 Unseal 이후 메모리에만 존재하며, 물리적 저장소에 접근해도 데이터를 복호화할 수 없습니다.
- 동적 자격증명 생성: 데이터베이스나 클라우드 서비스에 접근할 때 필요한 자격증명을 실시간으로 생성하고, TTL(Time To Live)이 만료되면 자동 폐기합니다. 고정 비밀번호 대신 수명이 짧은 임시 자격증명을 사용해 보안을 강화합니다.
- 정책 기반 접근 제어, 감사: 정책 파일을 기반으로 권한을 세밀하게 관리하며, 모든 접근 내역을 감사 로그에 기록해 추적성을 확보합니다.
Vault는 API 중심 설계와 Raft 합의 알고리즘 기반 클러스터링으로 고가용성을 보장하며, 클라우드 네이티브 환경에서 민감정보 관리의 표 준 솔루션으로 자리 잡았습니다.
Vault의 다층 보안 모델
Vault는 민감정보를 보호하기 위해 3가지 보안 계층으로 설계됐습니다.
보안 계층
- Seal/Unseal 메커니즘: Vault 접근 자체를 통제합니다. Root Key에 대한 접근을 관리해 Unseal 상태에서만 Root Key가 메모리에 로드됩니다.
- Barrier 암호화 레이어: 저장소 데이터를 보호하는 암호화 경계 역할을 합니다. 모든 저장소 데이터는 AES-256-GCM으로 암호화됩니다.
- 계층적 키 구조: Unseal Key → Root Key → Encryption Key로 이어지는 다층 키 보호 구조입니다. Root Key는 Unseal Key로 암호화돼 저장소에 저장됩니다. Encryption Key는 Root Key로 암호화돼 Vault의 데이터 암호화에 사용됩니다.
이러한 다층 방어 구조는 공격자가 한 레이어를 돌파해도 다른 레이어가 민감정보를 보호하도록 설계됐습니다.
Vault의 Root Key는 평문으로 저장되지 않습니다. 대신 Unseal Key로 암호화된 상태로 저장소에 저장되며, Vault가 Unseal 상태에서만 복호화돼 메모리에 로드됩니다. Vault 프로세스가 종료되거나 Seal 상태로 전환되면 메모리의 모든 복호화된 키가 즉시 제거됩니다. 따라서 공격자가 저장소나 백업에 접근해도 Unseal Key 없이는 데이터를 복호화할 수 없습니다.
각 보안 계층을 더 자세히 살펴보겠습니다.
Seal/Unseal 메커니즘
Vault는 부팅 시 Sealed 상태로 시작합니다. Sealed 상태에서는 Root Key가 Unseal Key로 암호화돼 저장됩니다. Unseal Key 없이는 Root Key를 복호화할 수 없으므로 Encryption Key도 복호화할 수 없어 데이터 접근은 불가능합니다. Unseal 과정을 통해 여러 Unseal Key 조각이 결합하면 Root Key가 복호화돼 메모리에 로드되고, Root Key로 Encryption Key를 복호화해 Vault는 Unsealed 상태로 전환됩니다.
-
상태 정의
- Sealed 상태: Root Key가 암호화돼 Encryption Key를 복호화할 수 없는 상태
- Unsealed 상태: Unseal 키로 Root Key를 복호화해 서비스가 가능한 상태
-
상태 전환 과정
[시스템 부팅]
↓
[Sealed 상태: Root Key 암호화됨, 데이터 접근 불가]
↓
[Unseal Key 제출 (Shamir 또는 AutoUnseal)]
↓
[Root Key 복호화 → Encryption Key 복호화]
↓
[Unsealed 상태: 서비스 정상 동작]
↓
[Barrier가 저장소 접근을 제어] -
Seal 인터페이스
Vault의 Seal 기능은
Seal인터페이스로 정의됩니다. Barrier 암호화 설정(core/seal-config)은 Vault가 Sealed 상태에서도 Seal 모드를 식별해야 하므로 일부 메타데이터는 평문으로 저장됩니다. 그러나 Root Key와 Encryption Key 자체는 절대 평문으로 저장되지 않습니다.// vault/seal.go
const (
// Barrier 암호화 설정 (평문 저장, Sealed 상태에서도 읽을 수 있어야 함)
barrierSealConfigPath = "core/seal-config"
// 복구 키 설정 (Barrier 내부에 암호화되어 저장)
recoverySealConfigPath = "core/recovery-seal-config"
recoverySealConfigPlaintextPath = "core/recovery-config"
// 복구 키 자체 (높은 보안으로 저장)
recoveryKeyPath = "core/recovery-key"
// HSM 저장 Unseal 키 (하드웨어 보안 모듈에 의해 암호화)
StoredBarrierKeysPath = "core/hsm/barrier-unseal-keys"
hsmStoredIVPath = "core/hsm/iv"
// 암호화 세대 관리 (Multi-Seal 지원)
SealGenInfoPath = "core/seal-gen-info"
)**
**
type Seal interface {
SetCore(*Core)
Init(context.Context) error
Finalize(context.Context) error
// Barrier 암호화 설정 관리
BarrierSealConfigType() SealConfigType
BarrierConfig(context.Context) (*SealConfig, error)
SetBarrierConfig(context.Context, *SealConfig) error
// 복구 키 관리 (AutoUnseal)
RecoveryKeySupported() bool
RecoverySealConfigType() SealConfigType
RecoveryKey(context.Context) ([]byte, error)
SetRecoveryKey(context.Context, []byte) error
// HSM에 저장된 Unseal 키
StoredKeysSupported() seal.StoredKeysSupport
GetStoredKeys(context.Context) ([][]byte, error)
SetStoredKeys(context.Context, [][]byte) error
}
Barrier 암호화 레이어
Barrier는 Vault의 저장소 데이터를 암호화·복호화하는 핵심 계층으로, Vault와 물리적 저장소(BoltDB, Consul 등) 사이에 위치합니다. 모든 데이터 접근은 Barrier로 수행되며, Unseal 상태에서만 데이터를 복호화할 수 있습니다.
-
Barrier의 역할
Vault의 모든 저장소 접근은 Barrier를 거치며, 읽기와 쓰기 모두 AES-256-GCM 알고리즘으로 암호화됩니다. Encryption Key는 Root Key로 암호화돼 저장되므로, Root Key가 복호화되지 않으면 Encryption Key를 사용할 수 없고, 데이터에 접근할 수 없습니다.
-
Barrier 암호화 흐름
[평문 데이터]
↓ (Barrier.Put())
[Encryption Key로 AES-256-GCM 암호화]
↓
[암호화된 데이터로 마샬링]
↓
[물리적 저장소(BoltDB, Consul 등)에 기록] -
Barrier 암호화 설정
Barrier는
vault/barrier.go에서 구현되며, Barrier와 Seal 설정 구조(SealConfig)는vault/seal.go에 정의됩니다.// vault/seal.go - Barrier Config 구조
type SealConfig struct {
// 저장소 유형 (Shamir, Transit, Awskms, Azure 등)
Type string
// Shamir 기반 Seal의 경우
SecretShares int // 총 키 조각 수 (예: 5)
SecretThreshold int // 필요한 키 조각 수 (예: 3)
PGPFingerprints []string // PGP로 암호화된 키 조각
// AutoUnseal의 경우
SealGeneration uint64
StoredKeysSupported seal.StoredKeysSupport
// 암호화 관련
Migrate bool
BarrierType string
}