Skip to content

HashiCorp Vault

Vault는 비밀 정보 즉, 공개되면 안 되는 비밀번호, API 키, 토큰 등을 저장하고 관리하는 도구이다.

Secure, store and tightly control access to tokens, passwords, certificates, encryption keys for protecting secrets and other sensitive data using a UI, CLI, or HTTP API.

Intro

개발하면 꽤 많은 비밀 정보를 사용하게 된다. 여기서 비밀 정보라는 것은 애플리케이션 등에서는 사용해야 하는데 외부에 노출이 되면 안 되는 정보를 얘기하는 것이다. 대표적으로 데이터베이스 계정명과 비밀번호가 있고(URL은 보통 접근 안 되게 차단하지만 이마저도 외부에 공개되어서 좋을 건 없다.), 외부 API를 사용한다면 엑세스 토큰이 있을 수도 있고 서버에 접근하기 위한 SSH 비밀키도 있다. 최소한 내가 경험해 본 프로젝트에서는 이중 비밀번호나 엑세스 토큰은 대부분 소스코드에 하드 코딩해서 사용하고 SSH키는 그냥 개발자의 PC에 (잘 관리할 것이라고 믿고) 저장되어 있고 개발이나 업무에 필요한 계정정보 등은 구글 스프레드시트 등에 관리되는 것이 대부분이었다.

이런 정보를 관리해주는 도구라고 생각하면 된다. 계정 정보 같은 건 구글 스프레드시트가 아니더라도 1Password 같은 솔루션도 있고 여기서는 개발에 대한 부분만 얘기해보자. 보통 이렇게 관리하는 것에 큰 문제가 없기는 하다. 코드에 하드 코딩 되어 있으면 사용하기도 쉽고 변경할 때는 업데이트하면 그만이기는 하지만 소스코드는 생각보다 관리하기가 쉽지 않다. GitHub 등의 공개 저장소의 실수로 올리는 경우를 제외하더라도 소스코드는 대부분 관련 개발자의 PC에 저장되어 있는데 악의적인 누출을 제외하더라도 개개인의 PC까지 다 제어하기는 쉽지 않기 때문에 유출될 가능성도 있고 코드에 하드 코딩 되어 있으므로 이러한 비밀정보를 바꾸기도 쉽지 않다.

프로젝트가 간단하다면 괜찮지만, 프로젝트 수가 많고 사람 수도 많아진다면 문제는 더욱 커진다. Vault는 이러한 정보를 안전하게 보관하고 관리해 주는 도구라고 생각하면 된다. 좀 더 쉽게 얘기하면 Vault에 이 정보를 저장해 놓고 애플리케이션이나 서버에서는 가져다가 사용하겠다는 의미이다. 최근 작업에서 이러한 솔루션이 필요하다는 생각을 하게 되어서 본격적으로 살펴보게 되었다.

Docker example

docker run --rm -it --cap-add=IPC_LOCK -p 8200:8200 -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:1234' hashicorp/vault

옵션 중 --cap-add=IPC_LOCK은 강력하게 권장되는 옵션입니다. IPC(Inter Process Communication)을 잠그는 것으로 메모리 스왑 공격으로부터 보호합니다.

Compose example

docker-compose.yml:

version: '3.8'

services:
  vault:
    image: hashicorp/vault:latest
    container_name: vault
    restart: unless-stopped
    ports:
      - "8200:8200"
    environment:
      VAULT_ADDR: "http://0.0.0.0:8200"
      VAULT_API_ADDR: "http://0.0.0.0:8200"
    cap_add:
      - IPC_LOCK
    volumes:
      - ./vault/config:/vault/config
      - ./vault/data:/vault/data
      - ./vault/logs:/vault/logs
    command: vault server -config=/vault/config/vault.hcl

vault/config/vault.hcl:

ui = true

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 1  # 프로덕션에서는 TLS 활성화 권장
}

storage "file" {
  path = "/vault/data"
}

api_addr = "http://0.0.0.0:8200"

실행 및 초기화:

# 디렉토리 생성
mkdir -p vault/{config,data,logs}

# 실행
docker compose up -d

# 초기화 (최초 1회)
docker exec -it vault vault operator init

# Key 5개와 Root Token이 출력됨 → 반드시 안전한 곳에 보관!

# Unseal (Key 5개 중 3개 입력 필요)
docker exec -it vault vault operator unseal <key1>
docker exec -it vault vault operator unseal <key2>
docker exec -it vault vault operator unseal <key3>

이후 http://localhost:8200 에서 Web UI 접근 가능합니다.

참고사항:

  • IPC_LOCK: Vault가 메모리를 swap으로 내리지 않도록 하는 필수 capability
  • Unseal: Vault는 재시작할 때마다 unseal이 필요함. 자동화하려면 auto-unseal (Transit, AWS KMS 등) 설정 가능
  • TLS: 프로덕션에서는 tls_disable = 0으로 하고 인증서 설정 필수
  • Storage backend: file 대신 Consul, Raft, PostgreSQL 등도 사용 가능. HA가 필요하면 Raft 추천

IPC_LOCK

IPC_LOCK은 Linux 커널의 메모리 잠금(mlock) 기능을 컨테이너에 허용하는 capability입니다.

Vault는 비밀키, 토큰 등 민감한 데이터를 메모리에 보관하는데, OS가 메모리 부족 시 이 데이터를 swap 영역(디스크)에 기록할 수 있습니다. 디스크에 쓰이면 암호화되지 않은 상태로 남을 수 있어 보안 위험이 생깁니다.

IPC_LOCK을 부여하면 Vault가 mlock() 시스템 콜을 사용해 자신의 메모리 페이지를 RAM에 고정시켜서, 절대 swap으로 내려가지 않게 합니다.

만약 이 capability를 주지 않으면, Vault 설정에서 disable_mlock = true를 명시해야 서버가 기동됩니다. 다만 이 경우 보안이 약해지므로 프로덕션에서는 권장하지 않습니다.

HCP Vault Tutorials

HCP Vault Secrets

HashiCorp Cloud Platform(HCP) Vault Secrets는 비밀을 중앙 집중화하고 애플리케이션이 워크플로에서 해당 비밀에 액세스할 수 있도록 하는 비밀 수명 주기 관리 솔루션입니다. 클라이언트(시스템 또는 사용자)는 명령줄 인터페이스(CLI), HCP 포털 또는 API를 사용하여 HCP Vault Secret과 상호 작용할 수 있습니다.

HCP Vault vs. HCP Vault Secrets

HCP Vault
다양한 퍼블릭 클라우드 제공업체 및 지역에 배포할 수 있는 단일 테넌트 전용 Vault Enterprise 클러스터를 제공합니다. HCP는 클러스터의 프로비저닝, 운영 및 유지 관리를 관리하여 조직이 비밀 액세스 및 데이터 보호 요구 사항에 대해 일관된 ID 기반 액세스 워크플로를 설정할 수 있는 유연성을 제공합니다.
HCP Vault Secrets
보안 수명 주기 관리를 위한 안전하고 단순화된 워크플로를 팀에 제공하는 다중 테넌트 SaaS 플랫폼입니다. 애플리케이션과 인프라 전반에 걸쳐 필요한 곳에 비밀을 쉽게 관리하고 통합하세요.

CURL Example

Generate Service Principal key

HCP 서비스 주체와 연결된 Client_ID 및 Client_Secret은 컴퓨터, 애플리케이션 또는 시스템 서비스에서 사람이 HCP API에 액세스하는 데 사용됩니다. 서비스 주체가 성공적으로 생성되었습니다! 클라이언트 비밀번호를 복사하세요. 나중에 검색할 수 없습니다.

export HCP_CLIENT_ID=...
export HCP_CLIENT_SECRET=...

Generate the API Token

HCP API에는 유효한 액세스 토큰이 필요합니다. 사용자 또는 서비스 주체를 통해 HCP에 인증하면 단기 액세스 토큰 (short-lived Access Token)을 검색하여 HCP API를 호출할 수 있습니다.

HCP_API_TOKEN=$(curl --location "https://auth.idp.hashicorp.com/oauth2/token" \
    --header "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "client_id=$HCP_CLIENT_ID" \
    --data-urlencode "client_secret=$HCP_CLIENT_SECRET" \
    --data-urlencode "grant_type=client_credentials" \
    --data-urlencode "audience=https://api.hashicorp.cloud" | jq -r .access_token)

JSON 스타일로 컨텐츠를 보낼 경우:

HCP_API_TOKEN=$(curl --location 'https://auth.hashicorp.com/oauth/token' \
  --header 'content-type: application/json' \
  --data '{
  "audience": "https://api.hashicorp.cloud",
  "grant_type": "client_credentials",
  "client_id": "'$HCP_CLIENT_ID'",
  "client_secret": "'$HCP_CLIENT_SECRET'"
  }' | jq -r .access_token)

Read your secrets

export HCP_ORG_ID=...
export HCP_PROJ_ID=...
export HCP_APP_NAME=...

API_PREFIX="https://api.cloud.hashicorp.com/secrets/2023-06-13/organizations"

curl \
--location "$API_PREFIX/$HCP_ORG_ID/projects/$HCP_PROJ_ID/apps/$HCP_APP_NAME/open" \
--request GET \
--header "Authorization: Bearer $HCP_API_TOKEN" | jq

vlt client in docker

FROM ubuntu
RUN apt update && apt install -y --no-install-recommends gpg curl lsb-release ca-certificates openssl
RUN curl -fsSL https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list
RUN apt update && apt install vlt -y --no-install-recommends
RUN apt clean && rm -rf /var/lib/apt/lists/*

Build:

docker build --tag ubuntu-with-vlt .

Run:

docker run --rm -it ubuntu-with-vlt ...

WebUI 초기화 방법

서버 실행 후 API 접속하면 나오는 첫 번째 화면:

Let's set up the initial set of root keys that you will need in case of an emergency.

Key shares
[ ]
The number of key shares to split the root key into

Key threshold
[ ]
The number of key shares required to reconstruct the root key
Vault 초기화 - Shamir's Secret Sharing
Vault는 마스터 키를 통째로 보관하지 않고, Shamir's Secret Sharing 알고리즘으로 여러 조각으로 분할합니다.
Key shares
마스터 키를 몇 조각으로 나눌 것인가
Key threshold
그 중 몇 조각을 모아야 Vault를 unseal(잠금 해제)할 수 있는가

예를 들어 shares=5, threshold=3이면, 5개의 키 조각이 생성되고 그 중 아무 3개만 있으면 Vault를 열 수 있습니다.

권장 설정

상황

Key shares

Key threshold

개인/테스트

1

1

소규모 팀

3

2

프로덕션 (기본값)

5

3

왜 이렇게 하는가

핵심은 단일 장애점 제거입니다. 한 사람이 키를 전부 갖고 있으면 그 사람이 퇴사하거나 키를 분실하면 끝입니다. 반대로 여러 명에게 나눠주면, 일부가 분실해도 threshold만큼 모이면 복구 가능하고, 한 사람이 악의적으로 단독으로 Vault를 열 수도 없습니다.

실용적 조언

개인 셀프호스팅이면 1 / 1로 해도 무방합니다. 어차피 혼자 관리하니까요.

초기화 후 나오는 Unseal KeyRoot Token은 반드시 안전한 곳에 백업해두세요. 분실하면 Vault 데이터에 접근할 방법이 없습니다.

Vault는 재시작할 때마다 sealed 상태가 되므로, 매번 unseal key를 입력해야 합니다. 이게 번거로우면 나중에 Auto Unseal (Transit, AWS KMS 등) 설정을 고려할 수 있습니다.

CLI 초기화 방법

해당하는 컨테이너에 접속하여 다음 명령을 사용:

# 초기화 (최초 1회)
docker exec -it vault vault operator init

# Key 5개와 Root Token이 출력됨 → 반드시 안전한 곳에 보관!

# Unseal (Key 5개 중 3개 입력 필요)
docker exec -it vault vault operator unseal <key1>
docker exec -it vault vault operator unseal <key2>
docker exec -it vault vault operator unseal <key3>

Troubleshooting

Cannot delete service principal

You cannot delete service principal Desktop since it has 1 key(s) active within it. Please delete the active keys in this service principal to proceed with deletion.

잘 안보이지만 다음 순서로 가보자.

  1. https://portal.cloud.hashicorp.com/sign-in 에서 로그인
  2. 왼쪽 메뉴의 'Access control (IAM)' 항목 클릭
  3. 왼쪽 메뉴의 'Service principals' 항목 클릭
  4. 제거를 원하는 Service principals 선택
  5. 왼쪽 메뉴의 'Keys' 항목 클릭
  6. 존재하는 모든 키를 제거한 후 Service principals 제거.

See also

Favorite site