쿠버네티스/AEWS

AEWS 10주차 - K8S Secret Update(vault 설치 및 kv 구성)

라리음 2025. 4. 11. 08:36
본 글은 가시다님이 진행하시는 AEWS(AWS EKS Workshop Study)를 참여하여 정리한 글입니다. 
모르는 부분이 많아서 틀린 내용이 있다면 말씀 부탁드리겠습니다!

 

 

 

 

 


Vault

 

Kubernetes Secret 보안은 충분할까? Vault로 비밀 관리 강화하기

Kubernetes(K8s)를 쓰다 보면 애플리케이션에 민감한 정보를 전달할 일이 자주 생깁니다. 데이터베이스 비밀번호, API 키, 인증 토큰 등등… 이런 정보를 Kubernetes에서는 Secret 리소스를 통해 관리하죠.

하지만 여기서 질문 하나. "Kubernetes Secret은 정말 안전할까?"

 

Kubernetes Secret의 기본 구조

Kubernetes의 Secret은 기본적으로 base64 인코딩된 문자열입니다.

예를 들어, 아래와 같이 MySQL 비밀번호를 설정할 수 있습니다.

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  password: bXlwYXNzd29yZA==

 

bXlwYXNzd29yZA==는 "mypassword"를 base64로 인코딩한 값일 뿐이죠. 암호화가 아닌 인코딩, 쉽게 복호화할 수 있는 방식입니다.
또한 기본적으로 etcd에 저장되는 Secret은 암호화되지 않은 상태이며, 클러스터 내 권한이 있는 사용자라면 접근이 가능합니다.

이러한 이유로 보안에 민감한 환경에서는 Secret만으로는 부족할 수 있습니다.

 

여기서 등장하는 Vault란?

Vault는 HashiCorp에서 만든 오픈소스 **비밀 관리 시스템(Secret Management System)**입니다.
다양한 시스템과 연동하여 민감한 정보를 암호화하여 저장하고, 안전하게 전달하며, 접근을 제어할 수 있는 플랫폼이죠.

Vault의 주요 특징

  • 강력한 암호화: Secret은 Vault 내부에서 안전하게 암호화되어 저장됩니다.
  • 정교한 접근 제어: 정책 기반 접근 제어로 사용자 및 애플리케이션마다 권한을 세밀하게 조정 가능.
  • 동적 Secret 발급: 예를 들어 DB 접근 정보도 사용 시점에 동적으로 생성하고 일정 시간이 지나면 자동 폐기.
  • 자동 토큰 갱신: 만료되기 전에 자동으로 갱신 가능 (Kubernetes 연동 시 유용함)
  • 감사 로깅: 누가 언제 어떤 Secret을 요청했는지 추적 가능.

Kubernetes + Vault = 시너지

Vault는 Kubernetes와 자연스럽게 연동할 수 있도록 다양한 기능을 제공합니다. 예를 들면:

  • Kubernetes Auth Method: Pod 내의 서비스 어카운트로 Vault에 인증 가능
  • Vault Agent Injector: 애플리케이션에 Sidecar 형태로 Vault Agent를 붙여 자동으로 Secret을 주입

간단한 구성 흐름 예시

  1. 애플리케이션 Pod가 시작됨
  2. Sidecar Vault Agent가 함께 실행됨
  3. Vault에 인증 → 권한 확인
  4. 필요한 Secret을 받아서 공유 메모리나 파일로 애플리케이션에 전달
  5. 애플리케이션은 암호화된 정보를 직접 다루지 않고 안전하게 사용

 

저는 vault의 기본 동작을 실습하기 위해서 jenkins, argocd를 설치하였습니다.

이후 vault을 설치하여 진행하겠습니다.


Vault 설치

 

 

ns 생성 및 helm repo 추가

# Create a Kubernetes namespace.
kubectl create namespace vault

# Setup Helm repo
helm repo add hashicorp https://helm.releases.hashicorp.com

# Check that you have access to the chart.
helm search repo hashicorp/vault

 

 

Helm Chart 설정 Values 설정 및 배포

cat <<EOF > override-values.yaml
global:
  enabled: true
  tlsDisable: true  # Disable TLS for demo purposes

server:
  image:
    repository: "hashicorp/vault"
    tag: "1.19.0"
  standalone:
    enabled: true
    replicas: 1
    config: |
      ui = true

      listener "tcp" {
        address = "[::]:8200"
        cluster_address = "[::]:8201"
        tls_disable = 1
      }

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

  service:
    enabled: true
    type: NodePort
    port: 8200
    targetPort: 8200
    nodePort: 30000   # 🔥 Kind에서 열어둔 포트 중 하나 사용

injector:
  enabled: true
EOF

 

helm 배포 및 리소스 확인

# Helm Install 실행
helm upgrade vault hashicorp/vault -n vault -f override-values.yaml --install

# 네임스페이스 변경 : vault
kubens vault
Context "kind-myk8s" modified.
Active namespace is "vault".

# 배포확인
k get pods,svc,pvc

 

 

 


Vault 초기화 및 잠금해제

 

 

초기에 배포를 하면 sealed상태입니다.

 

 

🔐 Vault는 왜 처음에 sealed 상태일까?

Vault는 기본적으로 비밀 정보(Secret)를 안전하게 보호하는 금고입니다.
그렇기 때문에 Vault는 시작하자마자 바로 사용 가능하지 않아요.

Vault 내부에 저장되는 모든 데이터는 암호화되어 저장되며, 이를 **복호화하는 키(master key)**는 자동으로 Pod에 보관되지 않습니다.
이 키가 유출된다면 모든 비밀 정보가 외부에 드러날 수 있으니까요.

그래서 Vault는 처음 시작할 때 다음과 같은 보안 절차를 거칩니다

 

 

🛠️ 1단계: vault operator init — 초기화

Vault를 처음 실행하면 데이터 저장 영역은 존재하지만, 암호화 키가 없습니다.
이때 vault operator init 명령어를 실행하면 다음과 같은 작업이 진행됩니다:

  • Master Key를 생성
  • 이 Master Key를 직접 저장하지 않고, 여러 개의 Unseal Key로 나눔 (Shamir의 비밀 분할 방식 사용)
  • Vault 내부 데이터를 암호화하는 **Root Key(암호화 키)**를 생성하고, 이 키도 Master Key로 암호화
vault operator init
Unseal Key 1: xxxxxxxx
Unseal Key 2: xxxxxxxx
...
Unseal Key 5: xxxxxxxx

Initial Root Token: s.xxxxxxxx

주의: 이 키들은 매우 중요합니다. 유실되면 Vault에 접근할 수 없게 되므로, 안전한 장소에 백업하세요.

 

 

 

 

🔓 2단계: vault operator unseal — 금고 열기

Vault는 보안 강화를 위해 기본적으로 **잠긴 상태(sealed)**로 시작합니다.
잠긴 상태에서는 내부 데이터를 읽을 수 없어요.

이 잠금을 풀기 위해서는 Unseal Key 중 다수를 입력해야 합니다.
기본적으로는 5개 중 3개 이상을 입력해야 합니다 (이 설정은 helm values로 조정 가능).

vault operator unseal <Unseal Key 1>
vault operator unseal <Unseal Key 2>
vault operator unseal <Unseal Key 3>

3개 이상 입력하면 드디어 Vault가 unsealed 되고, Root Token을 이용해서 정상적인 API 호출 및 시크릿 저장이 가능해집니다!

 

 

🔁 재시작할 때마다 unseal 해야 하나요?

Vault Pod가 재시작되면 다시 sealed 상태로 돌아갑니다.
이때마다 수동으로 unseal 명령을 입력해줘야 하죠.

하지만 운영 환경에서는 너무 불편하므로 다음과 같은 방법을 사용합니다:

  • Auto Unseal 기능 사용
    → AWS KMS, GCP KMS, Azure Key Vault 등 외부 키 관리 시스템(KMS)을 이용해 자동으로 Unseal

Helm으로 배포할 때 values 파일에서 auto-unseal 설정도 함께 구성하면, Vault가 재시작돼도 자동으로 열린 상태로 운영할 수 있어요.

 

 

 
init-unseal.sh 을 사용하여 Vault Unseal 자동화

 

cat <<EOF > init-unseal.sh
#!/bin/bash

# Vault Pod 이름
VAULT_POD="vault-0"

# Vault 명령 실행
VAULT_CMD="kubectl exec -ti \$VAULT_POD -- vault"

# 출력 저장 파일
VAULT_KEYS_FILE="./vault-keys.txt"
UNSEAL_KEY_FILE="./vault-unseal-key.txt"
ROOT_TOKEN_FILE="./vault-root-token.txt"

# Vault 초기화 (Unseal Key 1개만 생성되도록 설정)
\$VAULT_CMD operator init -key-shares=1 -key-threshold=1 | sed \$'s/\\x1b\\[[0-9;]*m//g' | tr -d '\r' > "\$VAULT_KEYS_FILE"

# Unseal Key / Root Token 추출
grep 'Unseal Key 1:' "\$VAULT_KEYS_FILE" | awk -F': ' '{print \$2}' > "\$UNSEAL_KEY_FILE"
grep 'Initial Root Token:' "\$VAULT_KEYS_FILE" | awk -F': ' '{print \$2}' > "\$ROOT_TOKEN_FILE"

# Unseal 수행
UNSEAL_KEY=\$(cat "\$UNSEAL_KEY_FILE")
\$VAULT_CMD operator unseal "\$UNSEAL_KEY"

# 결과 출력
echo "[🔓] Vault Unsealed!"
echo "[🔐] Root Token: \$(cat \$ROOT_TOKEN_FILE)"
EOF

# 실행 권한 부여
chmod +x init-unseal.sh

# 실행
./init-unseal.sh

 

 

 

확인

 

inital 방법(수동)

kubectl exec -ti vault-0 -- vault operator init -key-shares=1 -key-threshold=1

 

 

unseal 방법

kubectl exec -ti vault-0 -- vault operator unseal <UNSEAL_KEY>

 

확인

 

 

Root token을 이용해 UI도 확인이 가능합니다.

 

 

 

 


vault CLI 설정

 

 

WSL ubuntu 기준 설치

# HashiCorp GPG 키 등록
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

# HashiCorp 저장소 추가
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

# 패키지 업데이트 후 Vault 설치
sudo apt update && sudo apt install vault -y

# 설치 확인
vault --version

 

 

export VAULT_ADDR='http://localhost:30000'

# vault 로그인
vault login

# root token 기입

 

 

 


KV 시크릿 엔진 활성화

 

# KV v2 형태로 엔진 활성화
vault secrets enable -path=secret kv-v2

# 샘플 시크릿 저장
vault kv put secret/sampleapp/config \
  username="demo" \
  password="p@ssw0rd"
  
# 입력된 데이터 확인
vault kv get secret/sampleapp/config

 

 

UI로도 확인이 가능합니다.

 

이렇게 기초적인 vault를 구성하고 배포하였습니다.

values 파일을 이용해서 더 세부적인 vault control이 가능하며,

다음글에서는 Vault Sidecar & Jenkins + Vault를 알아보고 실습하겠습니다.