새소식

CICD

[CI/CD Study 8주차] Vault on K8S

  • -

CoudNet@ 팀의 가시다님께서 리딩하시는 CI/CD Study 8주차 스터디 내용 정리

 

이번 주차는 스터디의 마지막 8주차로 Vault 에 대해 더 자세히 배운 시간이었습니다.

 

이번 글에서는 Vault 를 K8S 에서 사용할 때

 K8S 애플리케이션이 Vault Secret 을 요청하고, 사용하는 방법에 대해 데모 애플리케이션을 배포하여 실습해보겠습니다.

 

 

 

1. Vault 설치 - 실습 환경 구성



1.1. Kind 설치

 

kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  labels:
    ingress-ready: true
  extraPortMappings:
  - containerPort: 30000  # Vault Web UI
    hostPort: 30000
  - containerPort: 30001  # Sample application
    hostPort: 30001
EOF

# 기본 실습 도구 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'



1.2. Vault 설치

 

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update

# 네임스페이스 생성
kubectl create namespace vault

# Vault Values 생성
cat <<EOF > vault-values.yaml
global:
  enabled: true
  tlsDisable: true

server:
  standalone:
    enabled: true
    config: |
      ui = true

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

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

  dataStorage:
    enabled: true
    size: "10Gi"
    mountPath: "/vault/data"

  auditStorage:
    enabled: true
    size: "10Gi"
    mountPath: "/vault/logs"

  service:
    enabled: true
    type: NodePort
    nodePort: 30000

ui:
  enabled: true

injector:
  enabled: false
EOF

# Vault 설치
helm upgrade vault hashicorp/vault -n vault -f vault-values.yaml --install --version 0.31.0

 

1.3. Vault Unseal

 

Vault 를 처음 배포하면 Sealed 상태로 배포됩니다.

 

kubectl exec -ti vault-0 -n vault -- vault status

Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            1.20.4
Build Date         2025-09-23T13:22:38Z
Storage Type       file
HA Enabled         false
command terminated with exit code 2

 

Sealed 를 해제해보겠습니다.

 

Vault Unseal

 

지금은 Vault 를 StandAlone 상태로 배포했기 때문에 키가 1개만 필요합니다.

 

 

Vault 키 확인

 

kubectl exec vault-0 -n vault -- vault operator init \
    -key-shares=1 \
    -key-threshold=1 \
    -format=json > cluster-keys.json

 # 키값확인
cat cluster-keys.json| jq

{
  "unseal_keys_b64": [
    "cljwCu53QVZqKPxujqSsskRoYHH0GDP2hTyivNzsNKA="
  ],
  "unseal_keys_hex": [
    "7258f00aee7741566a28fc6e8ea4acb244686071f41833f6853ca2bcdcec34a0"
  ],
  "unseal_shares": 1,
  "unseal_threshold": 1,
  "recovery_keys_b64": [],
  "recovery_keys_hex": [],
  "recovery_keys_shares": 0,
  "recovery_keys_threshold": 0,
  "root_token": "hvs.0pELTlphXI5UtMnwsiGtt7eC"
}

# Vault Unseal
VAULT_UNSEAL_KEY=$(jq -r ".unseal_keys_b64[]" cluster-keys.json)

kubectl exec vault-0 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.20.4
Build Date      2025-09-23T13:22:38Z
Storage Type    file
Cluster Name    vault-cluster-6d0e7d85
Cluster ID      f7148be6-bc3f-3a0d-d8f5-03c22dfb4286
HA Enabled      false

 

Sealed 상태가 false 로 변경된 것을 알 수 있습니다.

 

1.4. Vault Login

 

# 맥 유저
brew install hashicorp/tap/vault
vault --version

# Vault 주소 (NodePort)
export VAULT_ADDR='http://localhost:30000'

# Vault Root 키
jq -r ".root_token" cluster-keys.json

# Vault 로그인
vault login

#
Token (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                hvs.0pELTlphXI5UtMnwsiGtt7eC
token_accessor       kn5wg61vjub5D21tYh2ylH4L
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]



 

2. Vault 사용

 

 

Vault 가 K8s 시크릿 생성 및 인증을 처리하는 과정

 

1. Vault 에 Secret 를 요청 처리를 위해 사전에 Role(Policy) 설정

 

2. 파드 생성 시, 서비스 어카운트 토큰(JWT) 생성

 

3. 파드의 애플리케이션이 Vault 에 로그인

  a. 애플리케이션은 JWT를 전달하여 Vault 로그인 요청
  b. Vault 는 정보 확인을 위해 K8S API 서버에 TokenReview API 호출
  c. K8S API 서버는 서비스 어카운트의 이름과 네임스페이스를 반환
  d. Vault 는 ‘서비스 어카운트 이름, 네임스페이스’를 Vault 해당 시크릿에 정책과 매칭 확인
  e. 확인 후 Vault 는 Auth Token 을 애플리케이션에게 반환

 

4. 파드의 애플리케이션이 Vault 에 Secret 요청 과정

  a. 애플리케이션은 '3' 에서 받은 Auth Token 으로 Vault 해당 시크릿 정보를 요청
  b. Vault 는 Auth Token 확인 및 매칭 정책 확인
  c. 확인 후 Vault 는 최종적으로 해당 시크릿 정보를 반환

 

 

2.1. KV Engine 활성화

 

vault secrets enable -path=secret kv-v2

# 시크릿 생성
vault kv put secret/webapp/config username="static-user" password="static-password"

#
====== Secret Path ======
secret/data/webapp/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-12-13T12:00:51.142693052Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

 

UI 화면

 

 

 

2.2. k8s 인증 활성화

 

vault auth enable kubernetes

# K8S API 서버 정보 설정
vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc"

# 설정 정보 확인
vault read auth/kubernetes/config

Key                                  Value
---                                  -----
disable_iss_validation               true
disable_local_ca_jwt                 false
issuer                               n/a
kubernetes_ca_cert                   n/a
kubernetes_host                      https://kubernetes.default.svc
pem_keys                             []
token_reviewer_jwt_set               false
use_annotations_as_alias_metadata    false

 

 

2.3. Vault k8s 정책 생성

 

애플리케이션 클라이언트가 secret/webapp/config 에서 정의된 비밀 데이터에 접근하려면,

앞서 생성했던 secret/data/webapp/config 에 대한 읽기 정책이 있어야 합니다.

 

아래와 같이 생성한 kv 시크릿에 대한 읽기 권한을 부여합니다.

 

# 정책 생성
vault policy write webapp - <<EOF
path "secret/data/webapp/config" {
  capabilities = ["read"]
}
EOF

 

K8S Service Account 연동

 

생성한 정책을 k8s Service Account 에 연동합니다.

 

# K8S Service Account 와 Vault Policy 연동
vault write auth/kubernetes/role/webapp \
        bound_service_account_names=vault \
        bound_service_account_namespaces=default \
        policies=webapp \
        ttl=24h \
        audience="https://kubernetes.default.svc.cluster.local"

 

 

2.4. Web Application 생성

 

앞서 생성했던 Vault Secret 을 활용 하는 데모 App 을 배포하고, Vault 와 연동이 잘 되는 지 확인해보겠습니다.

 

# Vault SA 생성
kubectl create sa vault

# 데모 앱 배포
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  labels:
    app: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      serviceAccountName: vault
      containers:
        - name: app
          image: hashieducation/simple-vault-client:latest
          imagePullPolicy: Always
          env:
            - name: VAULT_ADDR
              value: 'http://vault.vault.svc:8200'
            - name: JWT_PATH
              value: '/var/run/secrets/kubernetes.io/serviceaccount/token'
            - name: SERVICE_PORT
              value: '8080'
          volumeMounts:
          - name: sa-token
            mountPath: /var/run/secrets/kubernetes.io/serviceaccount
            readOnly: true
      volumes:
      - name: sa-token
        projected:
          sources:
          - serviceAccountToken:
              path: token
              expirationSeconds: 600 # 10분 만료
---
apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  selector:
    app: webapp
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    nodePort: 30001
EOF

 

Application Token 확인

 

# 애플리케이션에 연결된 ServiceAccount (Vault) 토큰 값
kubectl exec -it deploy/webapp -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

# Vault Secret 을 사용하도록 호출 테스트
curl 127.0.0.1:30001

$ password:static-password username:static-user

# 애플리케이션 로그 확인 > Vault 호출 확인
kubectl logs -l app=webapp -f

 

 

Vault Secret 변경 후 App 호출

 

애플리케이션이 사용하는 Vault Secret 값을 변경하고, 다시 호출해보겠습니다.

 

# Vault Secret 변경
vault kv put secret/webapp/config username="changed-user" password="changed-password"

====== Secret Path ======
secret/data/webapp/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-12-13T12:21:26.475834763Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2


# Application 호출
curl 127.0.0.1:30001

$ password:changed-password username:changed-user

 

 

Vault 의 Secret 이 변경됐음에도 애플리케이션에서 접근이 가능한 것을 확인했습니다.

 

Contents

포스팅 주소를 복사했습니다