올해 신규 보안 프로젝트의 일환으로 Vault Cluster를 구축해 보았습니다.
기술 관련 오픈채팅방을 종종 살펴보면서 Vault를 사용하는 실무자가 의외로 많다고 생각했었는데 이번 프로젝트를 통해 Vault에 대한 실질적인 지식을 쌓을 수 있는 좋은 기회가 되었습니다.
Why? 왜 Vault를 사용했는가?
많은 실무자들이 AWS를 활용하면서 동시에 AWS CLI도 같이 사용합니다. 저 역시 실무에서 AWS CLI를 사용하는데, 이때 /root/.aws 디렉터리에 AWS Secret Key가 평문으로 저장되어 있다는 점이 보안상 큰 취약점이라고 판단했습니다. 그래서 Vault를 활용하면 Secret Key를 동적으로 발급받을 수 있으며 이 키는 일정 시간이 지나면 만료가 되어 보안 수준을 한 층 높일 수 있다고 생각했습니다.
Vault는 UI, CLI 또는 HTTP API를 사용하여 애플리케이션이나 인프라에서 사용되는 민감 정보(Secrets) ex) API 키, 비밀번호, 인증서, 데이터베이스 자격 증명 등을 안전하게 저장하고 제어할 수 있게 도와주는 비밀 관리 시스템(Secret Management System) 입니다.
Vault의 기능?
| 기능 | 설명 |
|---|---|
| Secret 저장 | 민감한 정보를 중앙에서 안전하게 저장하고 액세스를 제어할 수 있음 |
| 동적 자격증명(Dynamic Secrets) | 요청 시마다 짧은 TTL(Time-To-Live)을 가진 임시 자격증명을 생성 예: DB 계정, AWS IAM credentials 등 |
| 암호화 서비스(Encryption as a Service) | Vault를 통해 데이터를 직접 암복호화 할 수 있음 (앱에 키를 저장할 필요 없음) |
| 정책 기반 접근 제어 | 사용자/서비스의 권한을 세밀하게 제어 가능 (ACL 정책) |
| 감사 로그(Audit Logs) | 누가 어떤 Secret에 접근했는지 기록을 남겨 보안 감사에 유용 |
| 멀티 백엔드 저장소 지원 | AWS S3, 파일 시스템, Consul, PostgreSQL 등 다양한 스토리지 백엔드를 사용 가능 |
Vault Cluster의 필요성
Vault Cluster 구성 요소?
Raft Storage 구성도
암호화된 데이터를 보관하는 여러가지의 Storage 중 HA를 지원하는 Raft Storage를 선택했습니다.


Raft Storage는 Raft Consensus 알고리즘 사용하여 Leader 선출하는데 자세한 내용은 Google에... 질문하시면 더 자세한 정보를 얻을 수 있습니다!
sudo apt update && sudo apt install gpg wgetwget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpggpg --no-default-keyring --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg --fingerprint
sudo apt update && sudo apt install vaultvault -version
systemctl enable vault.service
systemctl start vault.service
같은 방식으로 3EA 서버에 Vault 세팅 진행하면 됩니다
mkdir -p /data/vaultmkdir -p /data/vault/tlschown -R vault:vault /data/vault
cd /data/vault/tlsVault 환경 구성 진행
vi /etc/vault.d/vault.hcl
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
# Full configuration options can be found at https://developer.hashicorp.com/vault/docs/configuration
ui = true # UI 모드 Enable
#mlock = true
#disable_mlock = true
#storage "file" {
# path = "/opt/vault/data"
#}
#storage "consul" {
# address = "127.0.0.1:8500"
# path = "vault"
#}
# HTTP listener
#listener "tcp" {
# address = "127.0.0.1:8200"
# tls_disable = 1
#}
cluster_addr = "https://sample1.domain.com:8201"
api_addr = "https://sample1.domain.com:8200"
# 메모리 부족 오류 방지
disable_mlock = true
# HTTPS listener
# HTTPS 구성
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "0.0.0.0:8201"
tls_cert_file = "/data/vault/tls/fullchain.pem"
tls_key_file = "/data/vault/tls/privkey.pem"
tls_client_ca_file = "/data/vault/tls/chain.pem"
tls_disable = 0
}
# Storage 구성 각 **node_id는 달라야함!!**
storage "raft" {
path = "/data/vault"
node_id = "raft_node_1"
retry_join {
leader_api_addr = "https://sample1.domain.com:8200"
leader_tls_servername = "sample1.domain.com"
leader_ca_cert_file = "/data/vault/tls/chain.pem"
leader_client_cert_file = "/data/vault/tls/fullchain.pem"
leader_client_key_file = "/data/vault/tls/privkey.pem"
}
retry_join {
leader_api_addr = "https://sample2.domain.com"
leader_tls_servername = "sample2.domain.com"
leader_ca_cert_file = "/data/vault/tls/chain.pem"
leader_client_cert_file = "/data/vault/tls/fullchain.pem"
leader_client_key_file = "/data/vault/tls/privkey.pem"
}
retry_join {
leader_api_addr = "https://sample3.domain.com:8200"
leader_tls_servername = "sample3.domain.com"
leader_ca_cert_file = "/data/vault/tls/chain.pem"
leader_client_cert_file = "/data/vault/tls/fullchain.pem"
leader_client_key_file = "/data/vault/tls/privkey.pem"
}
}
# Enterprise license_path
# This will be required for enterprise as of v1.8
#license_path = "/etc/vault.d/vault.hclic"
# Example AWS KMS auto unseal
#seal "awskms" {
# region = "us-east-1"
# kms_key_id = "REPLACE-ME"
#}
# Example HSM auto unseal
#seal "pkcs11" {
# lib = "/usr/vault/lib/libCryptoki2_64.so"
# slot = "0"
# pin = "AAAA-BBBB-CCCC-DDDD"
# key_label = "vault-hsm-key"
# hmac_key_label = "vault-hsm-hmac-key"
#}
실제 상용 서버에 구성하기 때문에 보안향상을 위해 TLS을 사용하여 구성 진행하였습니다. 또한 각 Vault 서버별로 node ID를 다르게 구성 하셔야 합니다.
vi /etc/profile
export VAULT_ADDR="https://sample1.domain.com:8200" or sample2. sample3(각 서버에 맞게)
source /etc/profile
vault operator init초기화를 진행하게 되면, Unseal Key가 나오는데 5개 중 3개를 입력해야지 Seal이 해제 됩니다.
vault operator raft list-peers
Vault Cluster 활용법으로 Terraform과 연동 진행해 보았습니다.
앞서 언급한것처럼 기존에는 평문으로 AWS Token을 저장하여 Terraform을 사용하였는데, 보안 향상을 위해 Terraform Provider에서 Token을 주입해 AWS 리소스들을 다룰 수 있습니다.
Terraform에서는 임시 AWS Secret을 동적으로 provider에 주입하여 사용!
(단, Secret인증은 30분간 유효)
1. vault_token으로 Vault에 연결 (provider "vault")
2. Vault에서 AWS 자격증명 가져오기 (data "vault_aws_access_credentials")
3. AWS provider에 동적으로 그 자격증명 주입
4. 이제 Terraform이 AWS 자원 생성/조회 가능
GSLB 구성이 안 되어 있을 경우

Vault 2번으로 Terraform은 주소를 알고 있지만 장애가 발생하여 HA 구성을 통해 Vault 1번으로 Active Node로 전환 되었을 때 Terraform과 Vault Cluster는 통신이 불가합니다.
GSLB 구성이 되어 있을 경우

GSLB를 통해 어디로 통신이 되든 Stanby Node는 Active Node로 요청을 Redirect 하기 때문에, 만약 Vault 2번이 장애가 나도 GSLB는 장애가 난 Node에게는 요청을 보내지 않기 때문에 서로 통신이 가능합니다.
단) GSLB는 sample.domain.com으로 요청을 받아야 합니다.
각 Node들은 고유의 도메인을 가지고 있으며(sample1, sample2, sample3) sample.domain.com 으로 요청을 받아 요청을 Balancing 해주게 됩니다.
vi /etc/profile
export TF_VAR_vault_token="{Vault Token}”
source /etc/profilevariable "vault_token" {
type = string
sensitive = true # 토큰 값을 보호하기 위해 sensitive로 설정
}
provider "vault" {
address = "https://sample.domain.com:8200" # Vault 서버의 주소
token = sensitive(var.vault_token) # Vault Token
}
data "vault_aws_access_credentials" "example" {
backend = "aws-test" # 원하는 secret 설정
role = "terraform" # Vault에서 설정한 역할 이름
}
provider "aws" {
access_key = data.vault_aws_access_credentials.example.access_key
secret_key = data.vault_aws_access_credentials.example.secret_key
region = "ap-northeast-2"
}
terraform init
terraform plan보안을 위해 몇가지 빠진 부분이 있지만, Vault Cluster 구축 및 Terraform과 연동을 위한 분들께 도움이 되었으면 좋겠습니다..!
Install Vault | Vault | HashiCorp Developer
Vault with integrated storage deployment guide | Vault | HashiCorp Developer
Vault with integrated storage deployment guide | Vault | HashiCorp Developer
Vault with integrated storage reference architecture | Vault | HashiCorp Developer