[AWS EKS] K8S 시크릿 관리(Vault)

주영·2025년 4월 12일
0

AWS EKS Workshop Study 3기

목록 보기
29/31

이 글은 CloudNet@팀의 AWS EKS Workshop Study(AEWS) 3기 스터디 내용을 바탕으로 작성되었습니다.
AEWS는 CloudNet@의 '가시다'님께서 진행하는 스터디로, EKS를 학습하는 과정입니다.
EKS를 깊이 있게 이해할 기회를 주시고, 소중한 지식을 나눠주시는 가시다님께 다시 한번 감사드립니다.
이 글이 EKS를 학습하는 분들께 도움이 되길 바랍니다.

0. 실습 환경 구성 - Kubernetes(Kind), Jenkins, ArgoCD

본 실습은 Windows WSL2 환경에서 Jenkins를 컨테이너 기반으로 진행합니다. Jenkins는 도커 네트워크(kind) 위에서 구동되며, 호스트 포트 포워딩(8080)을 통해 브라우저에서 접근이 가능합니다.

0.1 Kind 기반 Kubernetes 클러스터 구성 (WSL2 기반)

WSL2를 사용하는 Windows 환경에서는 IP 주소 설정이 필요하므로, 아래 절차를 반드시 따라야 합니다.

# 클러스터 배포 전 Docker가 실행 중인지 확인
docker ps

# 실습 디렉터리 생성
mkdir cicd-labs
cd ~/cicd-labs

# WSL2 Ubuntu에서 사용하는 eth0 IP 확인
ifconfig eth0

# 본인의 IP를 변수로 설정
MyIP=<각자 자신의 WSL2 Ubuntu eth0 IP>
MyIP=172.19.21.65

# cicd-labs 디렉터리에서 아래 kind 클러스터 구성 YAML 파일 작성
cat > kind-3node.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  apiServerAddress: "$MyIP"
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003
  - containerPort: 30004
    hostPort: 30004
  - containerPort: 30005
    hostPort: 30006
- role: worker
- role: worker
EOF

# Kind 클러스터 배포
kind create cluster --config kind-3node.yaml --name myk8s --image kindest/node:v1.32.2

# 클러스터 상태 확인
kind get nodes --name myk8s
kubens default

0.2 Kind의 네트워크 구조 및 클러스터 정보 확인

# kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16
docker network ls
docker inspect kind | jq

# k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까?
kubectl cluster-info

# 노드 정보 확인 : CRI 는 containerd 사용
kubectl get node -o wide

# 파드 정보 확인 : CNI 는 kindnet 사용
kubectl get pod -A -o wide

# 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다!
kubectl get namespaces

# 컨트롤플레인/워커 노드(컨테이너) 확인 : 도커 컨테이너 이름은 myk8s-control-plane , myk8s-worker/worker-2 임을 확인
docker ps
docker images

# 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드
kubectl get pod -v6

# kube config 파일 확인 : "server: https://172.19.21.65:35413" 부분에 접속 주소 잘 확인해두자!
cat ~/.kube/config
ls -l ~/.kube/config

0.3 Jenkins 설치

1. Jenkins 컨테이너 기동

Jenkins 컨테이너는 Kind 네트워크를 사용해야 하므로, 먼저 Kind 클러스터를 구성한 후 해당 네트워크가 생성되어 있어야 합니다.

# 작업 디렉토리 생성 후 이동
cd cicd-labs

# cicd-labs 작업 디렉토리 IDE(VSCODE 등)로 열어두기

# kind 설치를 먼저 진행하여 docker network(kind) 생성 후 아래 Jenkins,gogs 생성 할 것
# docker network 확인 : kind 를 사용
docker network ls
...
7e8925d46acb   kind      bridge    local
...

# docker-compose.yaml 작성
# jenkins_home 볼륨은 Jenkins 데이터를 유지하기 위한 볼륨. kind 네트워크는 external로 지정
cat <<EOT > docker-compose.yaml
services:

  jenkins:
    container_name: jenkins
    image: jenkins/jenkins
    restart: unless-stopped
    networks:
      - kind
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - jenkins_home:/var/jenkins_home

volumes:
  jenkins_home:

networks:
  kind:
    external: true
EOT


# 배포
docker compose up -d
docker compose ps
docker inspect kind


# 기본 정보 확인
for i in jenkins ; do echo ">> container : $i <<"; docker compose exec $i sh -c "whoami && pwd"; echo; done

# 도커를 이용하여 각 컨테이너로 접속
docker compose exec jenkins bash
exit

2. Jenkins 컨테이너 초기 설정

# Jenkins 초기 암호 확인
docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
09a21116f3ce4f27a0ede79372febfb1

# Jenkins 웹 접속 주소 확인 : 계정 / 암호 입력 >> admin / qwe123
웹 브라우저에서 http://127.0.0.1:8080 접속 # Windows

# (참고) 로그 확인 : 플러그인 설치 과정 확인
docker compose logs jenkins -f

  • 플러그인 설치 과정 로그

  • Admin User 생성

3. Jenkins URL 설정 (WSL2 IP 사용)

Jenkins를 외부(브라우저)에서 접속하기 위해, WSL2의 eth0 IP 주소를 기반으로 설정합니다.

# WSL2 Ubuntu IP 확인
ifconfig eth0

# 예시 결과:
# inet 172.19.21.65  netmask 255.255.240.0  broadcast 172.19.31.255

브라우저 주소창에 입력할 URL: http://<WSL2 eth0 IP>:8080
ex) http://172.19.21.65:8080

0.4 ArgoCD 설치

ArgoCD는 Kubernetes에서 선언형 GitOps 방식으로 애플리케이션을 관리할 수 있는 도구입니다. 본 실습에서는 Helm Chart를 사용하여 ArgoCD를 설치하고, 웹 UI에 접속하여 초기 설정을 수행합니다.

1. ArgoCD 설치 준비

# 작업 디렉터리로 이동
cd cicd-labs

# 네임스페이스 생성 및 Helm 파라미터 파일 작성
kubectl create ns argocd
cat <<EOF > argocd-values.yaml
dex:
  enabled: false

server:
  service:
    type: NodePort
    nodePortHttps: 30002
  extraArgs:
    - --insecure  # HTTPS 대신 HTTP 사용
EOF
  • dex.enabled: false: 인증 서버 비활성화 설정
  • --insecure: HTTPS 대신 HTTP로 접속을 허용하는 설정

2. ArgoCD 설치 (Helm)

# 설치
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd \
  --version 7.8.13 \
  -f argocd-values.yaml \
  --namespace argocd

3. 설치 확인 및 리소스 점검

# 확인
kubectl get pod,svc,ep,secret,cm -n argocd

kubectl get crd | grep argo
# 출력 예시
applications.argoproj.io                     2024-04-14T08:12:16Z
applicationsets.argoproj.io                  2024-04-14T08:12:17Z
appprojects.argoproj.io                      2024-04-14T08:12:16Z

  • -> argocd-repo-server 컨테이너 1개

4. ArgoCD 구성 확인

kubectl get appproject -n argocd -o yaml

# configmap
kubectl get cm -n argocd argocd-cm -o yaml
kubectl get cm -n argocd argocd-rbac-cm -o yaml
...
data:
  policy.csv: ""
  policy.default: ""
  policy.matchMode: glob
  scopes: '[groups]'
  • policy.defaultpolicy.csv가 비어 있다면, 기본 권한은 Argo CD 내장 계정 기준으로 동작하게 됩니다.

5. 관리자 계정 암호 확인

Argo CD 설치 시 자동 생성된 관리자 계정(admin)의 초기 암호는 Kubernetes Secret에 저장되어 있습니다.

# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
# 출력 예시
XxJMMJUv8MHZa-kk

6. 웹 UI 접속

Argo CD 서버는 NodePort(기본값: 30002)로 서비스됩니다.

  • 접속 주소:
    • Windows 사용자: http://127.0.0.1:30002

브라우저에서 접속한 후, 초기 admin 계정과 위에서 확인한 암호로 로그인합니다.

7. 암호 변경

로그인 후 상단 우측의 User Info 메뉴에서 UPDATE PASSWORD 항목을 클릭하여 초기 비밀번호를 변경합니다. (ex. qwe12345)

8. ArgoCD UI 기본 설정 메뉴 확인

Settings 탭을 통해 다음 항목들을 확인할 수 있습니다.

  • Clusters: 현재 연결된 Kubernetes 클러스터 목록

  • Projects: Argo CD에서 관리하는 애플리케이션 그룹

  • Accounts: 사용자 계정 및 권한 설정

0.5 Jenkins에서 Vault Plugin 설치

HashiCorp Vault Plugin은 Jenkins에서 HashiCorp Vault를 활용하여 비밀 정보를 안전하게 주고받을 수 있도록 해주는 플러그인입니다. 이 플러그인을 설치하면 Jenkins 파이프라인이나 빌드 작업에서 Vault의 시크릿 데이터를 연동하여 사용할 수 있습니다.

1. Jenkins UI 접속

2. 상단 메뉴에서 "Manage Jenkins" 진입 → "Plugins" 메뉴 선택

3. "Available" 탭에서 Valut 검색

4. Vault Plugin 설치 후 Jenkins 재시작

1. Vault 개요

1.1 Vault란

HashiCorp Vault는 신원 기반(identity-based)의 시크릿 및 암호화 관리 시스템입니다. 이 시스템은 인증(authentication)인가(authorization) 방법을 통해 암호화 서비스를 제공하여 비밀에 대한 안전하고 감사 가능하며 제한된 접근을 보장합니다.

시크릿(Secret)이란 접근을 철저히 통제하고자 하는 모든 것을 의미하며, 예를 들어 토큰, API 키, 비밀번호, 암호화 키 또는 인증서 등이 이에 해당합니다. Vault는 모든 시크릿에 대해 통합된 인터페이스를 제공하면서, 엄격한 접근 제어와 상세한 감사 로그 기록 기능을 제공합니다.

외부 서비스용 API 키, 서비스 지향 아키텍처 간 통신을 위한 자격 증명 등은 플랫폼에 따라 누가 어떤 비밀에 접근했는지를 파악하기 어려울 수 있습니다. 여기에 키 롤링(교체), 안전한 저장, 상세한 감사 로그까지 추가하려면 별도의 커스텀 솔루션 없이는 거의 불가능합니다. Vault는 바로 이 지점에서 해결책을 제공합니다.

Vault는 클라이언트(사용자, 기계, 애플리케이션 등)를 검증하고 인가한 후에만 비밀이나 저장된 민감한 데이터에 접근할 수 있도록 합니다.

1.2 Vault 동작 방식

Vault는 주로 토큰(Token)을 기반으로 작동하며, 이 토큰은 클라이언트의 정책(Policy)과 연결되어 있습니다. 각 정책은 경로(path) 기반으로 설정되며, 정책 규칙은 클라이언트가 해당 경로에서 수행할 수 있는 작업과 접근 가능성을 제한합니다.

Vault에서는 토큰을 수동으로 생성해 클라이언트에 할당할 수도 있고, 클라이언트가 로그인하여 토큰을 직접 획득할 수도 있습니다.

  • 아래 그림은 Vault의 핵심 워크플로우를 보여줍니다.

Vault의 핵심 워크플로우는 다음 네 단계로 구성됩니다:

  1. 인증 (Authenticate): Vault에서 인증은 클라이언트가 Vault에 자신이 누구인지 증명할 수 있는 정보를 제공하는 과정입니다. 클라이언트가 인증 메서드를 통해 인증되면, 토큰이 생성되고 정책과 연결됩니다.
  2. 검증 (Validation): Vault는 Github, LDAP, AppRole 등과 같은 신뢰할 수 있는 외부 소스를 통해 클라이언트를 검증합니다.
  3. 인가 (Authorize): 클라이언트는 Vault의 보안 정책과 비교됩니다. 이 정책은 Vault 토큰을 사용하여 클라이언트가 접근할 수 있는 API 엔드포인트를 정의하는 규칙의 집합입니다. 정책은 Vault 내 특정 경로나 작업에 대한 접근을 허용하거나 거부하는 선언적 방식으로 권한을 제어합니다.
  4. 접근 (Access): Vault는 클라이언트의 신원에 연관된 정책을 기반으로 토큰을 발급하여 비밀, 키, 암호화 기능 등에 대한 접근을 허용합니다. 클라이언트는 이후 작업에서 해당 Vault 토큰을 사용할 수 있습니다.

호텔 체크인 절차에 비유한 Vault 동작 방식

1.3 Vault가 필요한 이유 및 주요 기능

왜 Vault가 필요한가요?

오늘날 대부분의 기업은 자격 증명이 조직 전반에 걸쳐 무분별하게 퍼져 있습니다. → 시크릿 스프롤(Sprwal)
비밀번호, API 키, 자격 증명 등이 일반 텍스트로 앱 소스 코드, 설정 파일, 기타 여러 위치에 저장되어 있습니다. 자격 증명이 이처럼 여기저기 흩어져 있으면 누가 무엇에 접근하고 권한이 있는지를 명확히 파악하기 어렵고, 그로 인해 큰 부담이 따릅니다. 일반 텍스트로 자격 증명을 저장하면 내부 공격자든 외부 공격자든 악의적인 공격 가능성이 크게 증가합니다.

Vault는 이러한 문제를 해결하기 위해 설계되었습니다.
Vault는 이러한 모든 자격 증명을 한 곳에 중앙 집중화하여 정의함으로써, 자격 증명의 불필요한 노출을 줄입니다. 하지만 Vault는 여기서 멈추지 않고, 사용자, 애플리케이션, 시스템이 인증 및 명시적으로 인가된 후에만 리소스에 접근할 수 있도록 보장하며, 클라이언트의 모든 작업 기록을 추적하고 저장하는 감사 로그 기능도 제공합니다.

Vault의 주요 기능은 다음과 같습니다:

  1. 안전한 비밀 저장 (Secure Secret Storage): → Static 시크릿
    Vault는 임의의 key/value 형식의 시크릿을 저장할 수 있으며, 이 시크릿은 영구 저장소에 기록되기 전에 암호화됩니다. 따라서 저장소에 직접 접근하더라도 비밀을 열람할 수 없습니다.
    Vault는 Disk, Consul 등 다양한 저장소를 지원합니다.

  2. 동적 비밀 (Dynamic Secrets):
    Vault는 AWS나 SQL 데이터베이스와 같은 일부 시스템에 대해 요청 시 비밀을 동적으로 생성할 수 있습니다.
    예를 들어, 애플리케이션이 S3 버킷에 접근해야 할 때 Vault에 자격 증명을 요청하면, Vault는 해당 권한을 가진 AWS 키쌍을 생성해줍니다. 이 동적 시크릿은 일정 시간이 지나면 자동으로 폐기됩니다.

  3. 데이터 암호화 (Data Encryption):
    Vault는 데이터를 저장하지 않고 암호화 및 복호화를 수행할 수 있습니다.
    이를 통해 보안 팀은 암호화 매개변수를 정의하고, 개발자는 암호화된 데이터를 SQL 데이터베이스 등 외부 저장소에 안전하게 저장할 수 있습니다.

  4. 임대 및 갱신 (Leasing and Renewal):
    Vault에 저장된 모든 시크릿은 임대 기간(lease)이 설정되어 있으며, 이 기간이 끝나면 해당 비밀은 자동으로 폐기됩니다. 클라이언트는 내장된 갱신 API를 통해 임대를 연장할 수 있습니다.

  5. 폐기 (Revocation):
    Vault는 비밀 폐기를 기본적으로 지원합니다. 단일 비밀뿐만 아니라 특정 사용자에 의해 읽힌 모든 비밀, 또는 특정 유형의 모든 비밀 등 비밀의 계층 구조 전체를 폐기할 수 있습니다. 이 기능은 키 롤링이나 침입 발생 시 시스템을 신속하게 차단하는 데 유용합니다.

1.4 내부 아키텍처

Docs

  • Vault를 API call하게 되면 내부적으로 Token을 발행받을 때/인증받을 때(Token Store) 어떤 정책이 맵핑되어 있고(Policy Store) 해당 정책과 인증 토큰을 위해 뒷단?에 System Backend, Secret Engine, Auth Method 가 연결되어 있습니다.
  • Path Routing은 시크릿 엔진 설정하고 vault cli 명령으로 구성할 때 다 경로 기반으로 세팅하게 되어있습니다.

2. Vault 설치

Kubernetes(Kind) 환경에 HashiCorp Vault를 Helm Chart를 통해 설치하고, 초기화(Unseal)하는 과정입니다.

[참고] Vault Kubernetes 클러스터 외부에 설치할 경우: learn-vault-external-kubernetes

2.1 Helm을 사용한 Vault 배포

1. 네임스페이스 생성 및 Helm 저장소 추가

# Create a Kubernetes namespace.
kubectl create namespace vault

# View all resources in a namespace.
kubectl get all --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
# NAME                                    CHART VERSION   APP VERSION     DESCRIPTION                          
# hashicorp/vault                         0.30.0          1.19.0          Official HashiCorp Vault Chart       
# hashicorp/vault-secrets-gateway         0.0.2           0.1.0           A Helm chart for Kubernetes          
# hashicorp/vault-secrets-operator        0.10.0          0.10.0          Official Vault Secrets Operator Chart

2. Helm Chart 설정 파일 작성

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
  • Vault는 보안적으로 중요한 시스템이기 때문에 기업 및 조직에서 사용할 경우 TLS를 활성화하는 것을 권장합니다.
  • 본 실습에서는 편의상 TLS를 비활성화하여 진행합니다.
  • 해당 이미지는 오픈소스 버전이며, Enterprise 상용 버전은 바이너리와 이미지가 별도로 있습니다.
  • standalone(단일 인스턴스)로 Vault를 실행합니다. Production 환경에서는 standalone으로 사용하지 않는 것을 권장하며, 고가용성을 위해 홀수로 구성하는 것을 권장합니다.
  • 8200 포트를 NodePort:30000으로 노출시킵니다.
  • Vault Agent Injector도 함께 설치하여 Kubernetes 워크로드와의 통합을 준비합니다.

3. Vault Helm Chart 설치

# 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

NAME                                        READY   STATUS              RESTARTS   AGE
pod/vault-0                                 0/1     ContainerCreating   0          11s
pod/vault-agent-injector-56459c7545-9n94t   0/1     ContainerCreating   0          11s

NAME                               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                         AGE
service/vault                      NodePort    10.96.36.121   <none>        8200:30000/TCP,8201:31091/TCP   11s
service/vault-agent-injector-svc   ClusterIP   10.96.240.81   <none>        443/TCP                         11s
service/vault-internal             ClusterIP   None           <none>        8200/TCP,8201/TCP               11s

NAME                                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/data-vault-0   Bound    pvc-6f5739c5-14e9-4a62-bed2-b98fd327bcb1   10Gi       RWO            standard       <unset>                 11s

  • vault statefulset READY가 0/1이고, describe로 Event를 살펴보면 Readiness probe failed: Key Value가 발생합니다.
  • 이는 최초에 잠겨있고 초기화를 하지 않아서 발생하는 문제입
  • 맨 처음 설치하고 기동하게 되면 잠겨있으며(seal), 잠금 해제를 하기 위해 초기화(Initializing)를 하고 잠금 해제(unseal)를 해주어야 합니다.

2.2 Vault 초기화 및 잠금 해제 (Unseal)

Vault는 기본적으로 Sealed 상태에서 시작되며, 보안 상의 이유로 반드시 초기화(init) 및 잠금 해제(unseal) 작업을 수행해야 합니다.

1. Vault 상태 확인

# Vault Status 명령으로 Sealed 상태확인
kubectl exec -ti vault-0 -- vault status

  • Seal Type: shamir : Shamir Secret Sharing 방식
    • Vault는 보안 강화를 위해 Shamir's Secret Sharing 알고리즘을 사용하여 Unseal Key를 분할하여 저장합니다.
    • 실무에서는 보통 key-shares=5, key-threshold=3 등으로 설정하여 5개의 키 중 3개를 모아야 잠금 해제할 수 있도록 합니다.
  • Sealed: true : 아직 Unseal이 되지 않았음을 의미

2. init-unseal.sh 스크립트 작성 및 실행

초기화와 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
  • operator init: Vault를 최초 초기화
  • key-shares=1, key-threshold=1: 실습 편의를 위해 1개의 Unseal Key만 생성
  • vault-keys.txt: 전체 키 및 토큰 정보 저장
  • vault-unseal-key.txt, vault-root-token.txt: 필요한 정보만 분리 저장

3. Unseal 상태 확인

kubectl exec -ti vault-0 -- vault status

# 출력 예시
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.19.0
Build Date      2025-03-04T12:36:40Z
Storage Type    file
Cluster Name    vault-cluster-26e23c75
Cluster ID      326975b8-4907-2d62-9da1-f3165d7cc0c6
HA Enabled      false
  • Sealed: false로 표시되면 성공적으로 Unseal이 완료된 상태입니다.

2.3 Vault UI 접속 및 로그인

Vault는 UI 모드를 활성화한 상태이며, Helm 설정에서 포트 30000으로 NodePort로 노출되어 있습니다.

1. 웹 브라우저에서 접속

http://127.0.0.1:30000
또는
http://<WSL2 Ubuntu IP>:30000

2. 로그인

  • vault-root-token.txt 파일에서 추출한 Root Token을 사용하여 로그인합니다.
  • 로그인 이후, Vault의 UI 기능(시크릿 작성, 정책 관리 등)을 사용할 수 있습니다.

2.4 Vault CLI 설정 (Ubuntu)

wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) 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
sudo apt update && sudo apt install vault

vault --version  # 설치 확인

# NodePort로 공개한 30000 Port로 설정
export VAULT_ADDR='http://localhost:30000'

# vault 상태확인
vault status

# Root Token으로 로그인
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.egeVgnhMKgnFqof6YLfiPtLa
token_accessor       wWpBsO3TqQEybFF0le2YmNGX
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

3. KV 시크릿 엔진 활성화 및 샘플 구성 (Static Secret)

3.1 목적 및 개념

  • HashiCorp Vault의 KV(Key-Value) 시크릿 엔진은 Key-Value 형태로 데이터를 저장하는 기능을 제공합니다.
  • KV 시크릿 엔진은 두 가지 버전이 존재합니다.
    • KV Version 1 : 버전 관리 불가 (최신 값만 저장 가능)
    • KV Version 2 : 버전 관리 가능 (이전 데이터 복구 가능)

이번 실습에서는 버전 관리가 가능한 KV Version 2를 활성화하여 Static Secret 데이터를 등록하고 조회하는 과정을 진행합니다.

3.2 KV 시크릿 엔진 활성화 및 샘플 데이터 추가

Vault CLI를 사용하여 KV Version 2 형태의 시크릿 엔진을 활성화합니다. 활성화 경로는 /secret 으로 지정합니다.
/secret/sampleapp/config 경로에 Key-Value 형태의 시크릿 데이터를 저장합니다.

# 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

======== Secret Path ========
secret/data/sampleapp/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-03-30T05:18:47.797852422Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
password    p@ssw0rd
username    demo

3.3 Vault UI를 통한 시크릿 확인

Vault UI에서도 동일한 데이터를 확인할 수 있습니다.

[Secrets Engine] 탭에 접속 후 [sampleapp - config] 접속하여 실제 저장된 Key / Value를 확인합니다.

[참고] 경로 확인하는 명령 가이드

4. Vault Sidecar 연동 (Vault Agent)

Vault Agent를 활용하면 Kubernetes Pod 내부에 Sidecar 형태로 Vault Agent를 배치하여, Vault로부터 시크릿 데이터를 자동으로 주입할 수 있습니다.

4.1 Vault AppRole 방식 인증 구성

AppRole은 Vault에서 제공하는 인증 방법 중 하나로, Role ID와 Secret ID를 이용해 Vault에 접근 권한을 부여하는 방식입니다.

# 1. AppRole 인증 방식 활성화
vault auth enable approle || echo "AppRole already enabled"
vault auth list

# 2. 정책 생성
# secret/data/sampleapp/ 하위 경로의 시크릿 데이터에 대해 읽기 권한만 허용
vault policy write sampleapp-policy - <<EOF
path "secret/data/sampleapp/*" {
  capabilities = ["read"]
}
EOF

# 3. AppRole Role 생성
vault write auth/approle/role/sampleapp-role \
  token_policies="sampleapp-policy" \
  secret_id_ttl="1h" \
  token_ttl="1h" \
  token_max_ttl="4h"

# 4. Role ID 및 Secret ID 추출 및 저장
ROLE_ID=$(vault read -field=role_id auth/approle/role/sampleapp-role/role-id)
SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/sampleapp-role/secret-id)

echo "ROLE_ID: $ROLE_ID"
echo "SECRET_ID: $SECRET_ID"


# 5. 파일로 저장
mkdir -p approle-creds
echo "$ROLE_ID" > approle-creds/role_id.txt
echo "$SECRET_ID" > approle-creds/secret_id.txt


# 6. (옵션) Kubernetes Secret으로 저장
kubectl create secret generic vault-approle -n vault \
  --from-literal=role_id="${ROLE_ID}" \
  --from-literal=secret_id="${SECRET_ID}" \
  --save-config \
  --dry-run=client -o yaml | kubectl apply -f -
  • 생성된 Secret은 Vault Agent Sidecar가 인증 시 참조합니다.

4.2 Vault Agent Sidecar 연동

Vault Agent는 설정 파일(agent-config.hcl)을 기반으로 Vault에 접근하고, 시크릿 데이터를 템플릿화 하여 특정 파일로 렌더링합니다.

1. Vault Agent 설정 파일 작성 및 ConfigMap 생성 (vault-agent-config.hcl)

cat <<EOF | kubectl create configmap vault-agent-config -n vault --from-file=agent-config.hcl=/dev/stdin --dry-run=client -o yaml | kubectl apply -f -
vault {
  address = "http://vault.vault.svc:8200"
}

auto_auth {
  method "approle" {
    config = {
      role_id_file_path = "/etc/vault/approle/role_id"
      secret_id_file_path = "/etc/vault/approle/secret_id"
      remove_secret_id_file_after_reading = false
    }
  }

  sink "file" {
    config = {
      path = "/etc/vault-agent-token/token"
    }
  }
}

template_config {
  static_secret_render_interval = "20s"
}

template {
  destination = "/etc/secrets/index.html"
  contents = <<EOH
  <html>
  <body>
    <p>username: {{ with secret "secret/data/sampleapp/config" }}{{ .Data.data.username }}{{ end }}</p>
    <p>password: {{ with secret "secret/data/sampleapp/config" }}{{ .Data.data.password }}{{ end }}</p>
  </body>
  </html>
EOH
}
EOF

2. 샘플 애플리케이션 + Sidecar 배포 (수동 방식)

kubectl apply -n vault -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-vault-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-vault-demo
  template:
    metadata:
      labels:
        app: nginx-vault-demo
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html
      - name: vault-agent-sidecar
        image: hashicorp/vault:latest
        args:
          - "agent"
          - "-config=/etc/vault/agent-config.hcl"
        volumeMounts:
        - name: vault-agent-config
          mountPath: /etc/vault
        - name: vault-approle
          mountPath: /etc/vault/approle
        - name: vault-token
          mountPath: /etc/vault-agent-token
        - name: html-volume
          mountPath: /etc/secrets
      volumes:
      - name: vault-agent-config
        configMap:
          name: vault-agent-config
      - name: vault-approle
        secret:
          secretName: vault-approle
      - name: vault-token
        emptyDir: {}
      - name: html-volume
        emptyDir: {}
EOF

3. 서비스 생성

kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx-vault-demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30001 # Kind에서 설정한 Port
EOF

4. 생성된 컨테이너 확인

# 파드 내에 사이드카 컨테이너 추가되어 2/2 확인
kubectl get pod -l app=nginx-vault-demo
NAME                                READY   STATUS    RESTARTS   AGE
nginx-vault-demo-7776649597-tcnxd   2/2     Running   0          5m32s

kubectl describe pod -l app=nginx-vault-demo
...
Containers:
  nginx:
    Container ID:   containerd://c160c2268ce6d7602b718336b9036ae89646b5fdb7ebf310bed3dcf497b8675e
    Image:          nginx:latest
  ...
  vault-agent-sidecar:
    Container ID:  containerd://6d7e37e8925e681d163b06ae7d18f5d3a236164a60ebf422abd4229a2e337e4e
    Image:         hashicorp/vault:latest
    Image ID:      docker.io/hashicorp/vault@sha256:ee674e47dcf85849aadf255b5341f76c0e1a474bc5fa9be9cdfff2a2edf9a628
    Port:          <none>
    Host Port:     <none>
    Args:
      agent
      -config=/etc/vault/agent-config.hcl
...

# mutating admission
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io   
NAME                       WEBHOOKS   AGE
vault-agent-injector-cfg   1          3h10m

5. 실제 배포된 화면 확인

6. KV 값 변경 후 확인

5. Jenkins + Vault(AppRole) 연동을 통한 CI 파이프라인 구성

목표

  • Jenkins Pipeline에서 Vault(AppRole)를 통해 KV 시크릿 데이터를 안전하게 가져와 사용하는 방법을 학습합니다.
  • Vault AppRole 인증을 활용하여 Jenkins가 Vault와 연동되도록 구성합니다.

5.1 Vault AppRole 정보 확인

Jenkins가 Vault와 연동하기 위해서는 AppRole 방식 인증을 사용합니다. Vault에서 발급된 ROLE_IDSECRET_ID는 기존에 생성한 파일(role_id.txt, secret_id.txt)을 참고하거나 아래 명령어로 다시 조회할 수 있습니다.

# Role ID
vault read auth/approle/role/<role-name>/role-id

# Secret ID
vault write -f auth/approle/role/<role-name>/secret-id

# 예시
vault read auth/approle/role/sampleapp-role/role-id
Key        Value
---        -----
role_id    678c0c6e-57df-bb23-1427-f6318843a514

5.2 Jenkins에서 Vault 설정 및 Credential 추가

Vault Plugin을 활용하여 Jenkins가 Vault와 통신하도록 설정합니다.

  1. Jenkins UI 접속 → 로그인(admin/qwe123) → Manage Jenkins → System Configuration → System
  1. 스크롤 하단의 Vault Plugin Configuration 섹션으로 이동
    Vault URL 입력 후 [Add] 버튼 클릭
  1. Vault Credential 다음 값 입력:
    • 종류: Vault AppRole Credential
    • Role ID & Secret ID 입력 → 생성해놓은 변수 또는 파일 참고
    • ID는 기억하기 쉬운 이름으로 지정 (vault-approle-creds 등)

5.3 Jenkins Pipeline Job 생성

1. Pipeline Job 생성

  1. Jenkins UI → New Item 클릭
  2. Item 이름 입력 (예: jenkins-vault-kv)
  3. Pipeline 선택 후 생성

2. Jenkinsfile 작성

Vault Plugin을 활용한 Jenkinsfile 예시는 다음과 같습니다.

pipeline {
  agent any

  environment {
    VAULT_ADDR = 'http://192.168.0.2:30000' // 실제 Vault 주소로 변경!!!
  }

  stages {
    stage('Read Vault Secret') {
      steps {
        withVault([
          vaultSecrets: [
            [
              path: 'secret/sampleapp/config',
              engineVersion: 2,
              secretValues: [
                [envVar: 'USERNAME', vaultKey: 'username'],
                [envVar: 'PASSWORD', vaultKey: 'password']
              ]
            ]
          ],
          configuration: [
            vaultUrl: "${VAULT_ADDR}",
            vaultCredentialId: 'vault-approle-creds'
          ]
        ]) {
          sh '''
            echo "Username from Vault: $USERNAME"
            echo "Password from Vault: $PASSWORD"
          '''
          script {
            echo "Username (env): ${env.USERNAME}"
            echo "Password (env): ${env.PASSWORD}"
          }
        }
      }
    }
  }
}

3. 파이프라인 실행

3. 실행결과 및 유의사항

Vault Plugin 사용 시 Jenkins Console Output에 출력되는 시크릿 값은 보안상 자동으로 마스킹 처리됩니다.
출력되는 Username/Password 값은 별도로 파일로 저장하거나, 추가 로깅 설정 시 우회하여 확인할 수 있습니다.

6. ArgoCD + Vault Plugin을 활용한 CD 구성 (Kubernetes Auth / AppRole 방식)

목표

  • ArgoCD가 Vault와 연동하여 애플리케이션 배포 시 시크릿 데이터를 안전하게 주입하도록 구성합니다.
  • 인증 방식은 AppRole 기반으로 구성하며, Kubernetes Auth 방식은 참고용으로 소개합니다.

6.1 Vault AppRole 정보 기반 Credential 등록

ArgoCD Vault Plugin이 Vault 서버에 접근하기 위해 필요한 ROLE_ID, SECRET_ID 정보를 활용하여 Kubernetes Secret을 생성합니다. ROLE_ID와 SECRET_ID는 이전 Vault 실습 과정에서 생성한 값을 그대로 사용합니다.

kubectl apply -f - <<EOF
kind: Secret
apiVersion: v1
metadata:
  name: argocd-vault-plugin-credentials
  namespace: argocd
type: Opaque
stringData:
  VAULT_ADDR: "http://vault.vault:8200"
  AVP_TYPE: "vault"
  AVP_AUTH_TYPE: "approle"
  AVP_ROLE_ID: 88e405be-2485-2f4c-44de-0f1c929573d3 #Role_ID
  AVP_SECRET_ID: 4dea7bbb-85f4-b81d-43a4-81dfc2b8ed9d #Secret_ID
EOF

6.2 ArgoCD Vault Plugin 설치 및 Sidecar 구성

이번 구성은 Helm으로 배포된 ArgoCD 환경에 Kustomize를 활용하여 Patch 적용 방식으로 Sidecar Plugin을 구성합니다. Sidecar 방식은 ArgoCD의 argocd-repo-server Deployment에 Plugin Container를 추가하는 방식입니다. 이번 실습은 AppRole 방식을 사용하므로 별도의 ServiceAccount Token 구성은 진행하지 않습니다.

git clone https://github.com/hyungwook0221/argocd-vault-plugin.git
cd argocd-vault-plugin/manifests/cmp-sidecar

# argocd 네임스페이스 설정
kubens argocd

# 생성될 메니페스트 파일에 대한 확인
kubectl kustomize .

# -k 옵션으로 kusomize 실행
kubectl apply -n argocd -k .  

k exec -it -n vault vault-0 -- sh

# vault pod shell에 접속 후 root token으로 로그인
vault login
Token (will be hidden): <토큰입력>
    
# 확인명령
vault read auth/kubernetes/role/argocd

exit

6.3 Sample Application 배포 및 Vault 연동 검증

1. Application 리소스 생성 (Vault 연동)

Vault에 저장된 시크릿 데이터를 ArgoCD 배포 단계에서 Helm Values 파일 내 변수로 치환하여 배포합니다.

kubectl apply -n argocd -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo
  namespace: argocd
spec:
  destination:
    namespace: argocd
    server: https://kubernetes.default.svc
  project: default
  source:
    path: infra/helm
    repoURL: https://github.com/hyungwook0221/spring-boot-debug-app
    targetRevision: main
    plugin:
      name: argocd-vault-plugin-helm
      env:
        - name: HELM_ARGS
          value: -f new-values.yaml
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
EOF

2. Application 배포시 참조하는 new-values.yaml 확인

Github

serviceAccount:
  create: true

image:
  repository: luafanti/spring-boot-debug-app
  tag: main
  pullPolicy: IfNotPresent

replicaCount: 1

resources:
  memoryRequest: 256Mi
  memoryLimit: 512Mi
  cpuRequest: 500m
  cpuLimit: 1

probes:
  liveness:
    initialDelaySeconds: 15
    path: /actuator/health/liveness
    failureThreshold: 3
    successThreshold: 1
    timeoutSeconds: 3
    periodSeconds: 5
  readiness:
    initialDelaySeconds: 15
    path: /actuator/health/readiness
    failureThreshold: 3
    successThreshold: 1
    timeoutSeconds: 3
    periodSeconds: 5

ports:
  http:
    name: http
    value: 8080
  management:
    name: management
    value: 8081

envs:
  - name: VAULT_SECRET_USER
    value: <path:secret/data/sampleapp/config#username>
  - name: VAULT_SECRET_PASSWORD
    value: <path:secret/data/sampleapp/config#password>

log:
  level:
    spring: "info"
    service: "info"

3. 실제 배포시 적용된 화면

  • ArgoCD Vault Plugin 적용된 화면 : [DETAILS] - [PARAMETERS]
  • Application 배포화면
  • Deployment에 적용된 env 값 확인

    envs:
    - name: VAULT_SECRET_USER
     value: <path:secret/data/sampleapp/config#username>
    - name: VAULT_SECRET_PASSWORD
     value: <path:secret/data/sampleapp/config#password>

7. Vault Secrets Operator(VSO) 기반 Dynamic Secrets

목표

  • Kubernetes 애플리케이션이 DB 접속 계정과 비밀번호 같은 정보를 Vault에서 동적으로 발급받아 사용하도록 구성합니다.
  • Vault Secrets Operator(VSO)를 활용하여 Dynamic Secrets 관리 자동화 및 시크릿 자동 동기화를 구성합니다.

7.1 VSO Chart Values 파일 작성

# vault-operator-values.yaml
defaultVaultConnection:
  enabled: true
  address: "http://vault.vault.svc.cluster.local:8200"
  skipTLSVerify: false
controller:
  manager:
    clientCache:
      persistenceModel: direct-encrypted
      storageEncryption:
        enabled: true
        mount: k8s-auth-mount
        keyName: vso-client-cache
        transitMount: demo-transit
        kubernetes:
          role: auth-role-operator
          serviceAccount: vault-secrets-operator-controller-manager
          tokenAudiences: ["vault"]

7.2 VSO 배포

helm install vault-secrets-operator hashicorp/vault-secrets-operator \
  -n vault-secrets-operator-system \
  --create-namespace \
  --values vault-operator-values.yaml

7.3 PostgreSQL 설치(Bitnami Helm Chart)

kubectl create ns postgres

helm repo add bitnami https://charts.bitnami.com/bitnami
helm upgrade --install postgres bitnami/postgresql \
  --namespace postgres \
  --set auth.audit.logConnections=true \
  --set auth.postgresPassword=secret-pass

7.4 Vault Kubernetes Auth Method 설정

kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh

# 최초 설치시 획득한 vault root token 사용. 
# 예시) hvs.hnlFKWjE10FOyrwLMeK9PrCC
vault login

# Kubernetes 인증 메서드 활성화
vault auth enable -path k8s-auth-mount kubernetes

# Kubernetes 클러스터 정보 구성
vault write auth/k8s-auth-mount/config \
  kubernetes_host="https://kubernetes.default.svc:443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

# 설정 확인  
vault read auth/k8s-auth-mount/config

7.5 Vault Kubernetes Auth Role 생성

vault write auth/k8s-auth-mount/role/auth-role \
   bound_service_account_names=demo-dynamic-app \
   bound_service_account_namespaces=demo-ns \
   token_ttl=0 \
   token_period=120 \
   token_policies=demo-auth-policy-db \
   audience=vault

7.6 Vault Database Secret Engine 설정

# demo-db라는 경로로 Database Secret Engine을 활성화
vault secrets enable -path=demo-db database

# PostgreSQL 연결 정보 등록
# 해당 과정은 postgres가 정상적으로 동작 시 적용 가능
# allowed_roles: 이후 설정할 Role 이름 지정
vault write demo-db/config/demo-db \
   plugin_name=postgresql-database-plugin \
   allowed_roles="dev-postgres" \
   connection_url="postgresql://{{username}}:{{password}}@postgres-postgresql.postgres.svc.cluster.local:5432/postgres?sslmode=disable" \
   username="postgres" \
   password="secret-pass"
  
# DB 사용자 동적 생성 Role 등록
# 해당 Role 사용 시 Vault가 동적으로 사용자 계정과 비밀번호를 생성 가능
# TTL은 생성된 자격증명의 유효 시간 (30초~10분)
vault write demo-db/roles/dev-postgres \
   db_name=demo-db \
   creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
      GRANT ALL PRIVILEGES ON DATABASE postgres TO \"{{name}}\";" \
   revocation_statements="REVOKE ALL ON DATABASE postgres FROM  \"{{name}}\";" \
   backend=demo-db \
   name=dev-postgres \
   default_ttl="1m" \
   max_ttl="1m"

# 정책 설정: DB 자격증명 읽기 권한
# demo-db/creds/dev-postgres 경로에 대한 read 권한 부여
# 추후 Kubernetes 서비스 어카운트(demo-dynamic-app)에 이 정책을 연결해서 자격증명 요청 가능
vault policy write demo-auth-policy-db - <<EOF
path "demo-db/creds/dev-postgres" {
   capabilities = ["read"]
}
EOF

7.7 Vault Transit Secret Engine 설정 및 VSO 캐시 암호화 구성

kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh

# Transit Secret Engine 활성화
# transit 엔진을 demo-transit 경로로 활성화.
#   - 데이터를 저장하지 않고 암복호화 기능만 제공하는 Vault의 기능
vault secrets enable -path=demo-transit transit

# vso-client-cache라는 키를 생성
# 이 키는 VSO가 암복호화 시 사용할 암호화 키 역할
vault write -force demo-transit/keys/vso-client-cache

# vso-client-cache 키에 대해 암호화(encrypt), 복호화(decrypt)를 허용하는 정책 생성
vault policy write demo-auth-policy-operator - <<EOF
path "demo-transit/encrypt/vso-client-cache" {
   capabilities = ["create", "update"]
}
path "demo-transit/decrypt/vso-client-cache" {
   capabilities = ["create", "update"]
}
EOF

# Vault Secrets Operator가 사용하는 ServiceAccount에 위 정책을 바인딩
# vso가 Vault에 로그인할 때 사용할 수 있는 JWT 기반 Role 설정
# 해당 Role을 통해 Operator는 Transit 엔진을 이용한 암복호화 API 호출 가능
vault write auth/k8s-auth-mount/role/auth-role-operator \
   bound_service_account_names=vault-secrets-operator-controller-manager \
   bound_service_account_namespaces=vault-secrets-operator-system \
   token_ttl=0 \
   token_period=120 \
   token_policies=demo-auth-policy-operator \
   audience=vault
   
vault read auth/k8s-auth-mount/role/auth-role-operator

7.8 샘플 애플리케이션 구성 및 배포

1. demo-ns 네임스페이스 생성

kubectl create ns demo-ns
mkdir vso-dynamic
cd vso-dynamic

2. vault-auth-dynamic.yaml

---
# vault-auth-dynamic.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: demo-ns
  name: demo-dynamic-app
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: dynamic-auth
  namespace: demo-ns
spec:
  method: kubernetes
  mount: k8s-auth-mount
  kubernetes:
    role: auth-role
    serviceAccount: demo-dynamic-app
    audiences:
      - vault

3. app-secret.yaml

---
# app-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: vso-db-demo
  namespace: demo-ns

4. vault-dynamic-secret.yaml

---
# vault-dynamic-secret.yaml
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
  name: vso-db-demo
  namespace: demo-ns
spec:
  refreshAfter: 25s
  mount: demo-db
  path: creds/dev-postgres
  destination:
    name: vso-db-demo
    create: true
    overwrite: true
  vaultAuthRef: dynamic-auth
  rolloutRestartTargets:
  - kind: Deployment
    name: vaultdemo

5. app-spring-deploy.yaml

---
# app-spring-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vaultdemo
  namespace: demo-ns
  labels:
    app: vaultdemo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vaultdemo
  template:
    metadata:
      labels:
        app: vaultdemo
    spec:
      volumes:
        - name: secrets
          secret:
            secretName: "vso-db-demo"
      containers:
        - name: vaultdemo
          image: hyungwookhub/vso-spring-demo:v5
          imagePullPolicy: IfNotPresent
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: "vso-db-demo"
                  key: password
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: "vso-db-demo"
                  key: username
            - name: DB_HOST
              value: "postgres-postgresql.postgres.svc.cluster.local"
            - name: DB_PORT
              value: "5432"
            - name: DB_NAME
              value: "postgres"
          ports:
            - containerPort: 8088
          volumeMounts:
            - name: secrets
              mountPath: /etc/secrets
              readOnly: true
---
apiVersion: v1
kind: Service
metadata:
  name: vaultdemo
  namespace: demo-ns
spec:
  ports:
    - name: vaultdemo
      port: 8088         
      targetPort: 8088 
      nodePort: 30003
  selector:
    app: vaultdemo
  type: NodePort

6. 애플리케이션 배포

kubectl apply -f .

7.9 애플리케이션 접속 및 동작 확인

localhost:30003 접속 후 K8s Secrets에 생성된 username, password 값으로 연결을 테스트합니다.

0개의 댓글