카테고리 없음

7주차 - Vault

시스템엔지니어 2025. 11. 29. 09:42

0. 실습 환경 구성

Kind K8s 배포 (WSL기반)

(⎈|N/A:N/A) zosys@4:~$ 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
  extraPortMappings:
  - containerPort: 30000 # Vault UI
    hostPort: 30000
  - containerPort: 30001 # Jenkins UI
    hostPort: 30001
  - containerPort: 30002 # DB 배포(PostgreSQL 또는 MySQL)
    hostPort: 30002
  - containerPort: 30003 # # Sample App
    hostPort: 30003
EOF
Creating cluster "myk8s" ...
 ✓ Ensuring node image (kindest/node:v1.32.8) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-myk8s"
You can now use your cluster with:

kubectl cluster-info --context kind-myk8s

Thanks for using kind! 😊

 

1. Vault 개요

사전 지식

1. 정보 보안의 3요소 (CIA Triad)

  • 기밀성(Confidentiality)
  • 허가된 사람(시스템)만 정보에 접근해야한다.
  • 무결성(Integrity)
  • 정보가 허가 없이 변조되거나 삭제되지 않아야 한다. 변경 될 경우 식별이 되어야한다.
  • 가용성(Availability)
  • 사용자가 원할 때는 언제든지 서비스를 이용가능해야한다.

2.액세스 제어의 3단계(AAA)

  • 인증(Authentication)
  • 신원을 확인하는 절차(출입 게이트에 사원증)
  • 인가(Authorization)
  • 인증된 사용자에게 허용된 권한을 부여하는 절차.(사원증에 따른 출입구역제한)
  • 감사/계정관리(Accounting/Auditing)
  • 사용자가 수행한 모든활동을 기록하고 추적하는것(CCTV 녹화,출입기록로그)

시크릿이란?

A. 사용자 및 시스템 접근 자격 증명 ex) 비밀번호,SSH KEY,DB Credential

B. 서비스 연동 및 자동화 키 ex) Cloud Credentials,Token,API Key

C. 보안 통신 및 암호화 자산 ex) PKI, TLS인증서,암호화키

Vault를 필요한 시크릿 중앙관리가 필요한 이유

기존 모놀리식구조나 3Tier구조와 달리 MSA아키텍쳐가 도입되어 인프라와 아키텍쳐가 상당히 복잡해지며 모든 “시크릿”을 안전하게 관리하기가 불가능하기때문이다.

Vault란?

  • HashiCorp Vault는 신원 기반(identity-based)의 시크릿 및 암호화 관리 시스템입니다.
  • 인증 및 인가방법을 통해 암호화서비스를 제공하여 비밀에 대한 안전하고 감사가능하며, 제한된 접근을 보장
  • Vault의 4가지 핵심요소
  1. 누가(Who) : 인증(Authentication)
  2. 무엇에(What) : 대상 지정(Target System)
  3. 얼마동안(How Long) : 접근시간제어(TTL)
  4. 라이프사이클(Lifecycle) : 자동화(Automation)

 

2. Vault 동작 방식

Vault의 동작 방식 이해

개별 ID인증/인가를 통해 필요한 자격 증명 동적발급

 

Authentication을 위한 절차

3. Kubenetes에 Vault설치

Vault on kubernetes 설치

실습 환경 구성(개발모드로 진행)

네임스페이스 생성 및 Helm Repo추가

(⎈|kind-myk8s:N/A) zosys@4:~$ kubectl create namespace vault
namespace/vault created

(⎈|kind-myk8s:N/A) zosys@4:~$ helm repo add hashicorp https://helm.releases.hashicorp.com
"hashicorp" has been added to your repositories

(⎈|kind-myk8s:N/A) zosys@4:~$ helm search repo hashicorp/vault
NAME                                    CHART VERSION   APP VERSION     DESCRIPTION
hashicorp/vault                         0.31.0          1.20.4          Official HashiCorp Vault Chart
hashicorp/vault-secrets-gateway         0.0.2           0.1.0           A Helm chart for Kubernetes
hashicorp/vault-secrets-operator        1.0.1           1.0.1           Official Vault Secrets Operator Chart

 

Helm Chart 설정 Values설정 및 배포


(⎈|kind-myk8s:N/A) zosys@4:~$ cat vault-values-dev.yaml
global:
  enabled: true
  tlsDisable: true

injector:
  enabled: true

server:
  dev:
    enabled: true
    devRootToken: "root"
  dataStorage:
    enabled: false
  service:
    type: "NodePort"
    nodePort: 30000

  ui:
    enabled: true
(⎈|kind-myk8s:N/A) zosys@4:~$ cat vault-values-dev.yaml
global:
  enabled: true
  tlsDisable: true

injector:
  enabled: true

server:
  dev:
    enabled: true
    devRootToken: "root"
  dataStorage:
    enabled: false
  service:
    type: "NodePort"
    nodePort: 30000

  ui:
    enabled: true
(⎈|kind-myk8s:vault) zosys@4:~$ kubectl exec -it vault-0 -- vault status
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    inmem
Cluster Name    vault-cluster-5d53df9b
Cluster ID      195a8699-aff7-c091-925e-8fb0d437777b
HA Enabled      false

 

wsl2환경에서 실습환경 구성

(⎈|kind-myk8s:vault) zosys@4:~$ sudo apt-get update
[sudo] password for zosys:
Get:1 https://download.docker.com/linux/ubuntu noble InRelease [48.5 kB]
Hit:2 http://security.ubuntu.com/ubuntu noble-security InRelease
Hit:3 http://archive.ubuntu.com/ubuntu noble InRelease
Hit:4 http://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:5 http://archive.ubuntu.com/ubuntu noble-backports InRelease
Hit:6 https://ppa.launchpadcontent.net/cncf-buildpacks/pack-cli/ubuntu noble InRelease
Fetched 48.5 kB in 1s (41.7 kB/s)
Reading package lists... Done

(⎈|kind-myk8s:vault) zosys@4:~$ sudo apt-get install -y gpg curl lsb-release
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
gpg is already the newest version (2.4.4-2ubuntu17.3).
gpg set to manually installed.
curl is already the newest version (8.5.0-2ubuntu10.6).
lsb-release is already the newest version (12.0-2).
lsb-release set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 48 not upgraded.


(⎈|kind-myk8s:vault) zosys@4:~$ 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
deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com noble main
(⎈|kind-myk8s:vault) zosys@4:~$ sudo apt-get update
Hit:1 https://download.docker.com/linux/ubuntu noble InRelease
Get:2 https://apt.releases.hashicorp.com noble InRelease [12.9 kB]
Get:3 https://apt.releases.hashicorp.com noble/main amd64 Packages [210 kB]
Hit:4 http://archive.ubuntu.com/ubuntu noble InRelease
Hit:5 http://security.ubuntu.com/ubuntu noble-security InRelease
Hit:6 http://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:7 http://archive.ubuntu.com/ubuntu noble-backports InRelease
Hit:8 https://ppa.launchpadcontent.net/cncf-buildpacks/pack-cli/ubuntu noble InRelease
Fetched 223 kB in 1s (196 kB/s)
Reading package lists... Done

(⎈|kind-myk8s:vault) zosys@4:~$ sudo apt-get install -y vault
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  vault
0 upgraded, 1 newly installed, 0 to remove and 48 not upgraded.
Need to get 169 MB of archives.
After this operation, 512 MB of additional disk space will be used.
Get:1 https://apt.releases.hashicorp.com noble/main amd64 vault amd64 1.21.1-1 [169 MB]
Fetched 169 MB in 14s (11.9 MB/s)
Selecting previously unselected package vault.
(Reading database ... 93628 files and directories currently installed.)
Preparing to unpack .../vault_1.21.1-1_amd64.deb ...
Unpacking vault (1.21.1-1) ...
Setting up vault (1.21.1-1) ...
Generating Vault TLS key and self-signed certificate...
..+...+....+...+.....+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+....+.....+......+.+..+............+...+...+...+......+......+.......+...+.........+...............+......+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*........+.+...+..+..........+..............+..........+...+........+..........+..............+...+.+..+.......+...............+...............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......+.+.............................+..........+..+.........+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.........+.+.....+.+..+..........+........+..........+...+..+...................+...+...+..+......+..........+...........+.+.....+.......+.................+....+.................+...............+....+....................................+........+....+...........+......+.+..............+...+...+............+.+.....+.........+................+...........+................+..+...+...+......+.............+......+.........+..+...+.+.....+.......+........+.........+......+.........+.......+..............+.+.....+.............+..+....+..............+..........+......+.....+.........+................+..+.......+..+......+...+......+.+........+....+..+............................+...+...+......+..............+.......+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
Vault TLS key and self-signed certificate have been generated in '/opt/vault/tls'.

(⎈|kind-myk8s:vault) zosys@4:~$ vault --version
Vault v1.21.1 (2453aac2638a6ae243341b4e0657fd8aea1cbf18), built 2025-11-18T13:04:32Z

(⎈|kind-myk8s:vault) zosys@4:~$ export VAULT_ADDR='http://localhost:30000'
(⎈|kind-myk8s:vault) zosys@4:~$ vault status
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    inmem
Cluster Name    vault-cluster-5d53df9b
Cluster ID      195a8699-aff7-c091-925e-8fb0d437777b
HA Enabled      false
(⎈|kind-myk8s:vault) zosys@4:~$ vatuls login
vatuls: command not found
(⎈|kind-myk8s:vault) zosys@4:~$ 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                root
token_accessor       Z79KiTYlABr4QrIXgYNfLsyn
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

 

 

 

실습

KV시크릿 엔진 활성화 및 샘플구성 → 정적시크릿(Static Secret)

(⎈|kind-myk8s:vault) zosys@4:~$ vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_668bf8fc    per-token private secret storage
identity/     identity     identity_827e2b1e     identity store
secret/       kv           kv_eb39bee4           key/value secret storage
sys/          system       system_07d18235       system endpoints used for control, policy and debugging


(⎈|kind-myk8s:vault) zosys@4:~$ vault kv put secret/sampleapp/config \
  username="demo" \
  password="p@ssw0rd"
======== Secret Path ========
secret/data/sampleapp/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-11-24T15:27:21.004785439Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

(⎈|kind-myk8s:vault) zosys@4:~$ vault kv get secret/sampleapp/config
======== Secret Path ========
secret/data/sampleapp/config

======= Metadata =======
Key                Value
---                -----
created_time       2025-11-24T15:27:21.004785439Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

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

 

 

Vault Agent와 Sidecar 패턴

실습

1. Vault AppRole 방식 인증 구성

  • 인증 구성 및 정책 적용
(⎈|kind-myk8s:vault) zosys@4:~$ vault auth list
Path      Type     Accessor               Description                Version
----      ----     --------               -----------                -------
token/    token    auth_token_6a22d402    token based credentials    n/a

(⎈|kind-myk8s:vault) zosys@4:~$ vault policy write sampleapp-policy - <<EOF
> path "secret/data/sampleapp/*" {
>   capabilities = ["read"]
> }
> EOF
Success! Uploaded policy: sampleapp-policy

(⎈|kind-myk8s:vault) zosys@4:~$ vault write auth/approle/role/sampleapp-role token_policies="sampleapp-policy" secret_id_ttl="100h" token_ttl="100h" token_max_ttl="200h"
Success! Data written to: auth/approle/role/sampleapp-role

(⎈|kind-myk8s:vault) zosys@4:~$ SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/sampleapp-role/secret-id)
(⎈|kind-myk8s:vault) zosys@4:~$ echo $ROLE_ID
b3712987-c900-3f0f-d381-e86c19c0ec72
(⎈|kind-myk8s:vault) zosys@4:~$ echo $SECRET_ID
098b8b14-dc3a-fe6f-d777-efe805f7a48c

(⎈|kind-myk8s:vault) zosys@4:~$ 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-approle created

 

2. Vault Agent Sidecar연동

(⎈|kind-myk8s:vault) zosys@4:~$ 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
configmap/vault-agent-config created

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl apply -n vault -f test.yaml
deployment.apps/nginx-vault-demo created
(⎈|kind-myk8s:vault) zosys@4:~$ cat test.yaml
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: {}

 

3. SVC생성

(⎈|kind-myk8s:vault) zosys@4:~$ 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 
EOF
service/nginx-service created

 

4. 컨테이너 확인

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl get pod -l app=nginx-vault-demo
NAME                                READY   STATUS    RESTARTS   AGE
nginx-vault-demo-7776649597-2jk4f   2/2     Running   0          10s

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl describe pod -l app=nginx-vault-demo
Name:             nginx-vault-demo-7776649597-2jk4f
Namespace:        vault
Priority:         0
Service Account:  default
Node:             myk8s-control-plane/172.18.0.2
Start Time:       Thu, 27 Nov 2025 01:27:58 +0900
Labels:           app=nginx-vault-demo
                  pod-template-hash=7776649597
Annotations:      <none>
Status:           Running
IP:               10.244.0.8
IPs:
  IP:           10.244.0.8
Controlled By:  ReplicaSet/nginx-vault-demo-7776649597
-------------------------중략 -------------------------------

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io
NAME                       WEBHOOKS   AGE
vault-agent-injector-cfg   1          2d1h

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vault-demo -c vault-agent-sidecar -- vault agent -h
Usage: vault agent [options]

  This command starts a Vault Agent that can perform automatic authentication
  in certain environments.

  Start an agent with a configuration file:

      $ vault agent -config=/etc/vault/config.hcl

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/approle/secret_id
87fb5719-5b31-dd97-e701-08ba809d3121(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/approle/role_id
b3712987-c900-3f0f-d381-e86c19c0ec72(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/approle/role_id
(⎈|kind-myk8s:vault) zosys@4:~$ ec72(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vls -l /etc/vault/approlear -- cat /etc/vault/approle/role_id
total 0
lrwxrwxrwx    1 root     root            14 Nov 26 16:27 role_id -> ..data/role_id
lrwxrwxrwx    1 root     root            16 Nov 26 16:27 secret_id -> ..data/secret_id
(⎈|kind-myk8s:vault) zosys@4:~$ kubectl  exec -it -n vault deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/agent-config.hcl
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
}

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl exec -it -n vault deploy/nginx-vault-demo -c nginx -- ls -l /usr/share/nginx/html
total 4
-rw-r--r-- 1 100 1000 94 Nov 26 16:28 index.html
(⎈|kind-myk8s:vault) zosys@4:~$ kubectl exec -it -n vault deploy/nginx-vault-demo -c nginx -- cat /usr/share/nginx/html/index.html
  <html>
  <body>
    <p>username: demo</p>
    <p>password: p@ssw0rd</p>
  </body>
  </html>

 

5. 실제 배포된 화면 확인

 

6. 변경후 재배포 확인

 

4. Jenkins + Vault (AppRole) - CI

실습1. Jenkins + KV 시크릿

1. 젠킨스는 두가지 방법 중 Pod배포 방식으로 진행

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl create ns jenkins
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
-------중략-----------
namespace/jenkins created
persistentvolumeclaim/jenkins-pvc created
deployment.apps/jenkins created
service/jenkins-svc created

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl get deploy,svc,ep,pvc -n jenkins
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/jenkins   1/1     1            1           2m21s

NAME                  TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)                          AGE
service/jenkins-svc   NodePort   10.96.150.6   <none>        8080:30001/TCP,50000:31211/TCP   2m21s

NAME                    ENDPOINTS                            AGE
endpoints/jenkins-svc   10.244.0.10:50000,10.244.0.10:8080   2m21s

NAME                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/jenkins-pvc   Bound    pvc-ea0d13e8-ea9d-49cf-879c-578d1532fbc3   10Gi       RWO            standard       <unset>                 2m21s


(⎈|kind-myk8s:vault) zosys@4:~$ kubectl exec -it -n jenkins deploy/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
0db0da89485340638ecf03a53599de62

*배포 및 어드민설정/Vault플러그인 설치

 

 

 

 

2. Vault Approle정보 확인

(⎈|kind-myk8s:vault) zosys@4:~/approle-creds$ cat role_id.txt
b3712987-c900-3f0f-d381-e86c19c0ec72
(⎈|kind-myk8s:vault) zosys@4:~/approle-creds$ cat secret_id.txt
87fb5719-5b31-dd97-e701-08ba809d3121

 

3. vault plugin 설치 및 credential 설정

 

4. 파이프 라인 작성 및 구동. pod배포시에 시스템 설정 및 젠킨스파이프라인내에 http://vault.vault.svc:8200로 설정할것.

 

 

실습2. Jenkins + 동적(Dynamic) DB 시크릿

1. 인프라 구성

(⎈|kind-myk8s:vault) zosys@4:~$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: default
spec:
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:13
          env:
            - name: POSTGRES_PASSWORD
              value: "rootpassword"
            - name: POSTGRES_DB
              value: "mydb"
          ports:
            - containerPort: 5432
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: default
spec:
  type: NodePort
  ports:
    - port: 5432
      targetPort: 5432
      nodePort: 30002  # [External] Jenkins 접속용
  selector:
    app: postgres
EOF
deployment.apps/postgres created
service/postgres created

 

2. Vault DB Engine 설정

(⎈|kind-myk8s:vault) zosys@4:~$ export VAULT_ADDR=http://127.0.0.1:30000
(⎈|kind-myk8s:vault) zosys@4:~$ export VAULT_TOKEN=root
(⎈|kind-myk8s:vault) zosys@4:~$ vault secrets enable database
Success! Enabled the database secrets engine at: database/
(⎈|kind-myk8s:vault) zosys@4:~$ vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_668bf8fc    per-token private secret storage
database/     database     database_43519aa6     n/a
identity/     identity     identity_827e2b1e     identity store
secret/       kv           kv_eb39bee4           key/value secret storage
sys/          system       system_07d18235       system endpoints used for control, policy and debugging

(⎈|kind-myk8s:vault) zosys@4:~$ vault write database/config/my-postgresql-database \
    plugin_name=postgresql-database-plugin \
    allowed_roles="jenkins-role" \
    connection_url="postgresql://{{username}}:{{password}}@postgres.default.svc.cluster.local:5432/mydb?sslmode=disable" \
    username="postgres" \
    password="rootpassword"
Success! Data written to: database/config/my-postgresql-database
(⎈|kind-myk8s:vault) zosys@4:~$ vault write database/roles/jenkins-role \
    db_name=my-postgresql-database \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"
Success! Data written to: database/roles/jenkins-role

 

3. 기존 AppRole 권한 확장 진행

(⎈|kind-myk8s:vault) zosys@4:~$ vault policy write sampleapp-policy - <<EOF
# 1. KV v2 데이터 읽기
path "secret/data/sampleapp/*" {
  capabilities = ["read"]
}
# 2. KV v2 목록 조회 (플러그인 에러 방지용 필수!)
path "secret/metadata/sampleapp/*" {
  capabilities = ["list", "read"]
}
# 3. DB Creds 발급
path "database/creds/jenkins-role" {
  capabilities = ["read"]
}
EOF
Success! Uploaded policy: sampleapp-policy
(⎈|kind-myk8s:vault) zosys@4:~$ vault policy read sampleapp-policy
# 1. KV v2 데이터 읽기
path "secret/data/sampleapp/*" {
  capabilities = ["read"]
}
# 2. KV v2 목록 조회 (플러그인 에러 방지용 필수!)
path "secret/metadata/sampleapp/*" {
  capabilities = ["list", "read"]
}
# 3. DB Creds 발급
path "database/creds/jenkins-role" {
  capabilities = ["read"]
}
(⎈|kind-myk8s:vault) zosys@4:~$ vault write auth/approle/role/sampleapp-role \
  token_policies="default,sampleapp-policy" \
  secret_id_ttl="0" \
  token_ttl="1h" \
  token_max_ttl="4h"
Success! Data written to: auth/approle/role/sampleapp-role

 

4. 젠킨스 파이프라인 작성

 

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl exec -it -n default deploy/postgres -- psql -U postgres
psql (13.23 (Debian 13.23-1.pgdg13+1))
Type "help" for help.

postgres=# \du
                                                       
                                                        List of roles
                     Role name                      |                         Attributes                         | Member of
----------------------------------------------------+------------------------------------------------------------+-----------
 postgres                                           | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
 v-approle-jenkins--sKg8NpSTXnFzluA9jTvf-1764314075 | Password valid until 2025-11-28 08:14:40+00                | {}

 

5. 암호화(Encryption)와 Vault Transit엔진

이번 실습에서 주로 다룰 내용은 계층별 암호화 방안 중 애플리케이션 계층에 대한 암호화를 진행한다.

실습

0. 사전준비

(⎈|kind-myk8s:vault) zosys@4:~$ export NS=vault-demo
export IMAGE=hyungwookhub/vault-transit-demo:v1   # 이번 실습에서는 제 개인 저장소에 업로드한 이미지를 사용
# export IMAGE=DOCKER_HUB_USER/vault-transit-demo:latest   # 본인 계정으로 교체
export VAULT_ADDR=http://localhost:30000                 # NodePort 엔드포인트
export VAULT_TOKEN=root                                  # 실습용 토큰

 

1. Vault Transit활성화

(⎈|kind-myk8s:vault) zosys@4:~$ vault status
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    inmem
Cluster Name    vault-cluster-5d53df9b
Cluster ID      195a8699-aff7-c091-925e-8fb0d437777b
HA Enabled      false
(⎈|kind-myk8s:vault) zosys@4:~$ vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/
(⎈|kind-myk8s:vault) zosys@4:~$ vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_668bf8fc    per-token private secret storage
database/     database     database_43519aa6     n/a
identity/     identity     identity_827e2b1e     identity store
secret/       kv           kv_eb39bee4           key/value secret storage
sys/          system       system_07d18235       system endpoints used for control, policy and debugging
transit/      transit      transit_692f884a      n/a
(⎈|kind-myk8s:vault) zosys@4:~$ vault write -f transit/keys/ds-poc type=aes256-gcm96
Key                       Value
---                       -----
allow_plaintext_backup    false
auto_rotate_period        0s
deletion_allowed          false
derived                   false
exportable                false
imported_key              false
keys                      map[1:1764317025]
latest_version            1
min_available_version     0
min_decryption_version    1
min_encryption_version    0
name                      ds-poc
supports_decryption       true
supports_derivation       true
supports_encryption       true
supports_signing          false
type                      aes256-gcm96

(⎈|kind-myk8s:vault) zosys@4:~$ vault list transit/keys
Keys
----
ds-poc
(⎈|kind-myk8s:vault) zosys@4:~$ PLAINTEXT="My Data"
(⎈|kind-myk8s:vault) zosys@4:~$ CIPHERTEXT=$(vault write -field=ciphertext transit/encrypt/ds-poc \
  plaintext=$(echo -n "$PLAINTEXT" | base64))
(⎈|kind-myk8s:vault) zosys@4:~$ echo "ciphertext: $CIPHERTEXT"
ciphertext: vault:v1:aR/otS5ymKQcqqKN/jQ8RBVIQDf+4voBtzKXbKbwnUaosy4=
(⎈|kind-myk8s:vault) zosys@4:~$ vault write -field=plaintext transit/decrypt/ds-poc \
  ciphertext="$CIPHERTEXT" | base64 -d && echo
My Data

 

 

2. MYSQL 배포진행 (NodePort 30002)

(⎈|kind-myk8s:vault) zosys@4:~$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: ${NS}
---
---------중략-------------
namespace/vault-demo created
deployment.apps/mysql created
service/mysql created

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl -n ${NS} rollout status deploy/mysql
deployment "mysql" successfully rolled out
(⎈|kind-myk8s:vault) zosys@4:~$ kubectl -n ${NS} exec -it deploy/mysql -- \
  mysql -uroot -prootpassword -e "CREATE DATABASE IF NOT EXISTS VaultData;"
mysql: [Warning] Using a password on the command line interface can be insecure.
(⎈|kind-myk8s:vault) zosys@4:~$ kubectl -n ${NS} exec -it deploy/mysql -- \
  mysql -uroot -prootpassword -e "SHOW DATABASES LIKE 'VaultData';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------------+
| Database (VaultData) |
+----------------------+
| VaultData            |
+----------------------+

 

3. Transit Demo APP 배포

(⎈|kind-myk8s:vault) zosys@4:~$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vault-transit-demo
  namespace: ${NS}
-----중략----------
deployment.apps/vault-transit-demo created
service/vault-transit-demo created

 

 

(⎈|kind-myk8s:vault) zosys@4:~$ kubectl -n ${NS} exec -it deploy/mysql -- \
mysql -uroot -prootpassword -e "USE VaultData; SHOW TABLES; SELECT id,data,date_created FROM vault_data;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------------+
| Tables_in_VaultData |
+---------------------+
| vault_data          |
+---------------------+
+----+-----------------------------------------------------------+----------------------------+
| id | data                                                      | date_created               |
+----+-----------------------------------------------------------+----------------------------+
|  1 | vault:v1:jAuhJlZtaoX20eeh87hXjQ1toUpyYjleuCK9roZWVi5VyF3w | 2025-11-28 17:11:09.457000 |
+----+-----------------------------------------------------------+----------------------------+
(⎈|kind-myk8s:vault) zosys@4:~$ echo "hello vault transit" > original.txt
(⎈|kind-myk8s:vault) zosys@4:~$ md5sum original.txt
5b92abfe363ae7212a37a55f96bf5967  original.txt

 

4.원본파일과 복호화파일 해쉬값비교

(⎈|kind-myk8s:vault) zosys@4:~$ md5sum original.txt
5b92abfe363ae7212a37a55f96bf5967  original.txt

(⎈|kind-myk8s:vault) zosys@4:~$ md5sum original.txt.enc
63b7c4829152bfb93fc8c8a7101f7cab  original.txt.enc

(⎈|kind-myk8s:vault) zosys@4:~$ md5sum original.dec.txt
5b92abfe363ae7212a37a55f96bf5967  original.dec.tx