CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.
1. Vault 개요
HashiCorp Vault는 신원 기반(identity-based)의 시크릿 및 암호화 관리 시스템입니다. 이 시스템은 인증(authentication) 및 인가(authorization) 방법을 통해 암호화 서비스를 제공하여 비밀에 대한 안전하고 감사 가능하며 제한된 접근을 보장합니다.
- 시크릿(Secret)이란 접근을 철저히 통제하고자 하는 모든 것을 의미하며, 예를 들어 토큰, API 키, 비밀번호, 암호화 키 또는 인증서 등이 이에 해당합니다. Vault는 모든 시크릿에 대해 통합된 인터페이스를 제공하면서, 엄격한 접근 제어와 상세한 감사 로그 기록 기능을 제공합니다.
대표적인 Secret 종류
- 비밀번호
- Cloud Credentials : AWS, GCP, Azure, NCP
- Database Credentials : MySQL,
- SSH Key
- Token, API Key : GitHub, Telegram, Slack, OpenAI, Claude
- 인증서(PKI, TLS 등)
외부 서비스용 API 키, 서비스 지향 아키텍처 간 통신을 위한 자격 증명 등은 플랫폼에 따라 누가 어떤 비밀에 접근했는지를 파악하기 어려울 수 있습니다. 여기에 키 롤링(교체), 안전한 저장, 상세한 감사 로그까지 추가하려면 별도의 커스텀 솔루션 없이는 거의 불가능합니다.
Vault는 바로 이 지점에서 해결책을 제공합니다.
Vault는 클라이언트(사용자, 기계, 애플리케이션 등)를 검증하고 인가한 후에만 비밀이나 저장된 민감한 데이터에 접근할 수 있도록 합니다.
Vault 의 동작방식
Vault는 주로 토큰(Token)을 기반으로 작동하며, 이 토큰은 클라이언트의 정책(Policy)과 연결되어 있습니다.
각 정책은 경로(path) 기반으로 설정되며, 정책 규칙은 클라이언트가 해당 경로에서 수행할 수 있는 작업과 접근 가능성을 제한합니다.
Vault에서는 토큰을 수동으로 생성해 클라이언트에 할당할 수도 있고, 클라이언트가 로그인하여 토큰을 직접 획득할 수도 있습니다.
- 아래 그림은 Vault의 핵심 워크플로우를 보여줍니다.
Vault의 핵심 워크플로우는 다음 네 단계로 구성됩니다:
- 인증 (Authenticate): Vault에서 인증은 클라이언트가 Vault에 자신이 누구인지 증명할 수 있는 정보를 제공하는 과정입니다. 클라이언트가 인증 메서드를 통해 인증되면, 토큰이 생성되고 정책과 연결됩니다.
- 검증 (Validation): Vault는 Github, LDAP, AppRole 등과 같은 신뢰할 수 있는 외부 소스를 통해 클라이언트를 검증합니다.
- 인가 (Authorize): 클라이언트는 Vault의 보안 정책과 비교됩니다. 이 정책은 Vault 토큰을 사용하여 클라이언트가 접근할 수 있는 API 엔드포인트를 정의하는 규칙의 집합입니다. 정책은 Vault 내 특정 경로나 작업에 대한 접근을 허용하거나 거부하는 선언적 방식으로 권한을 제어합니다.
- 접근 (Access): Vault는 클라이언트의 신원에 연관된 정책을 기반으로 토큰을 발급하여 비밀, 키, 암호화 기능 등에 대한 접근을 허용합니다. 클라이언트는 이후 작업에서 해당 Vault 토큰을 사용할 수 있습니다.
2. Vault 기본 구조의 이해
3. kind 클러스터 배포 후 Vault 실습
Step0. jenkins을 배포
# 작업 디렉토리 생성 후 이동
mkdir cicd-labs
cd cicd-labs
# cicd-labs 작업 디렉토리 IDE(VSCODE 등)로 열어두기
code .
#
cat <<EOT > docker-compose.yaml
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins
restart: unless-stopped
networks:
- cicd-network
ports:
- "8080:8080"
- "50000:50000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- jenkins_home:/var/jenkins_home
volumes:
jenkins_home:
networks:
cicd-network:
driver: bridge
EOT
# 배포
docker compose up -d
docker compose ps
# 기본 정보 확인
for i in jenkins ; do echo ">> container : $i <<"; docker compose exec $i sh -c "whoami && pwd"; echo; done
# 도커를 이용하여 각 컨테이너로 접속
docker compose exec jenkins bash
exit
Step0. kind로 k8s을 배포
# 클러스터 배포 전 확인
docker ps
# cicd-labs 디렉터리에서 아래 파일 작성
cat > kind-3node.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerAddress: "127.0.0.1" # $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: 30005
- containerPort: 30006
hostPort: 30006
- role: worker
- role: worker
EOF
kind create cluster --config kind-3node.yaml --name myk8s --image kindest/node:v1.32.2
# 확인
kind get nodes --name myk8s
kubens default
# 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 파일 확인
cat ~/.kube/config
Step0. argocd을 배포
# 네임스페이스 생성 및 파라미터 파일 작성
cd cicd-labs
kubectl create ns argocd
cat <<EOF > argocd-values.yaml
dex:
enabled: false
server:
service:
type: NodePort
nodePortHttps: 30002
extraArgs:
- --insecure # HTTPS 대신 HTTP 사용
EOF
# 설치
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
# 확인
kubectl get pod,svc,ep,secret,cm -n argocd
kubectl get crd | grep argo
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]'
# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
XxJMMJUv8MHZa-kk
# Argo CD 웹 접속 주소 확인 : 초기 암호 입력 (admin 계정)
open "http://127.0.0.1:30002" # macOS
# Windows OS경우 직접 웹 브라우저에서 http://127.0.0.1:30002 접속
Step1. Helm을 사용한 Vault 배포
# 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
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
disable_mlock = true
cluster_name = "vault-local"
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_disable = 1
}
storage "raft" { # Raft 구성 권장
path = "/vault/data"
node_id = "vault-dev-node-1"
}
service:
enabled: true
type: NodePort
port: 8200
targetPort: 8200
nodePort: 30000 # Kind에서 열어둔 포트 중 하나 사용
injector:
enabled: true
ui:
enabled: true
serviceType: "NodePort"
EOF
# Helm Install 실행
helm upgrade vault hashicorp/vault -n vault -f override-values.yaml --install
# Install Kind
brew install kind
kind --version
# Install kubectl
brew install kubernetes-cli
kubectl version --client=true
## kubectl -> k 단축키 설정
echo "alias kubectl=kubecolor" >> ~/.zshrc
# Install Helm
brew install helm
helm version
# 툴 설치
brew install krew
brew install kube-ps1
brew install kubectx
# kubectl 출력 시 하이라이트 처리
brew install kubecolor
echo "alias kubectl=kubecolor" >> ~/.zshrc
echo "compdef kubecolor=kubectl" >> ~/.zshrc
# krew 플러그인 설치
kubectl krew install neat stren
# 네임스페이스 변경 : vault
kubens vault
Context "kind-myk8s" modified.
Active namespace is "vault".
# 배포확인
k get pods,svc,pvc
koo ~/cicd-labs k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
data-vault-0 Bound pvc-c938125c-0877-49d1-9835-0ada3e99c87f 10Gi RWO standard <unset> 5m18s
Step2. Vault 초기화 및 잠금해제
✘ koo ~/cicd-labs kubectl exec -ti vault-0 -- 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.19.0
Build Date 2025-03-04T12:36:40Z
Storage Type raft
Removed From Cluster false
HA Enabled true
샤미르의 비밀 공유 (SSS)는 그룹 간에 개인 정보 ("비밀")를 분배하는효율적인 비밀 공유 알고리즘 입니다 ..
일부 애플리케이션에서는 샤미르의 비밀 공유를 사용하여 마스터 비밀에 대한 액세스 키를 공유합니다.
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
##
## hvs.zw0kKrDFmFzG53Qw4GkEwY4H
koo ~/cicd-labs 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 raft
Cluster Name vault-local
Cluster ID 75f723a8-6240-ead3-1d63-ed11a76b01d9
Removed From Cluster false
HA Enabled true
HA Cluster https://vault-0.vault-internal:8201
HA Mode active
Active Since 2025-04-11T06:21:43.518651969Z
Raft Committed Index 37
Raft Applied Index 37
Step3. CLI 설정(MacOS) - Docs / 수동설치
✘ koo ~/cicd-labs 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.zw0kKrDFmFzG53Qw4GkEwY4H
token_accessor kSzxOUko6P1ZPN5L4vpQmICR
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
Step4. KV 시크릿 엔진
- KV 시크릿 엔진 활성화 및 샘플 구성 → Static Secret
## → Vault KV version 2 엔진을 활성화하고 샘플 데이터를 저장합니다.
## → Version1 : KV 버전관리 불가 / Version2 : 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
======== 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
- UI 에서 확인
4. Vault Sidecar 연동 (Vault Agent) - 링크1 링크2
Vault Agent Injector는 Kubernetes Pod 내부에 Vault Agent를 자동으로 주입해주는 기능입니다. 이를 통해 어플리케이션이 Vault로부터 자동으로 비밀 정보를 받아올 수 있게 됩니다. 하지만 이를 사용하기 전에 몇 가지 사전 준비가 필요합니다.
1. Vault가 설치되어 있고, Kubernetes와 통합되어 있어야 합니다
- Vault가 실행 중이어야 하고, Kubernetes 클러스터에 접근 가능해야 합니다.
- Vault는 Kubernetes 인증 방식을 설정하고 있어야 하며, 이를 통해 서비스 어카운트를 기반으로 토큰을 발급받을 수 있습니다.
2. Vault Agent Injector가 클러스터에 배포되어 있어야 합니다
- Injector는 Kubernetes에 배포되는 별도의 구성 요소입니다.
- 일반적으로 Helm Chart를 통해 배포하며, 이 컴포넌트가 있어야 Pod에 Vault Agent가 자동으로 주입됩니다.
3. Kubernetes 인증 방식이 활성화되어야 합니다
- Vault에서 Kubernetes Auth Method를 활성화하고 구성해야 합니다.
- 이 설정을 통해 특정 서비스 어카운트에 Vault 접근 권한을 부여할 수 있습니다.
4. 정책과 역할이 정의되어 있어야 합니다
- Vault에 접근할 수 있도록 적절한 Policy와 Role이 설정되어야 합니다.
- 예를 들어, 특정 서비스 어카운트가 특정 경로의 시크릿에만 접근할 수 있도록 제한할 수 있습니다.
5. 애플리케이션 Pod에 주입할 주석(annotation)을 추가해야 합니다
- Vault Agent Injector는 특정 주석이 있는 Pod에 대해서만 Vault Agent를 주입합니다.
Use AppRole authentication
AppRole 인증 방식(AppRole Auth Method)은 Vault에 정의된 역할을 사용하여 머신이나 애플리케이션이 인증할 수 있도록 해줍니다.
AppRole의 개방적인 설계 덕분에 많은 수의 애플리케이션을 처리할 수 있는 다양한 워크플로우와 구성 방식이 가능합니다.
이 인증 방식은 자동화된 워크플로우(예: 머신이나 서비스)를 위한 것이며, 사람이 직접 사용하는 경우에는 적합하지 않습니다.
AppRole 인증 방식에는 배치 토큰(batch token) 사용을 권장합니다.
AppRole은 특정 Vault 정책과, 해당 정책을 포함한 토큰을 발급받기 위해 충족해야 하는 로그인 제약 조건의 집합을 의미합니다.
AppRole의 적용 범위는 좁게도, 넓게도 설정할 수 있습니다. 예를 들어, 특정 머신을 위한 AppRole을 만들 수도 있고, 그 머신에서 실행되는 특정 사용자나, 여러 머신에 걸친 서비스용으로 만들 수도 있습니다.
성공적으로 로그인하기 위해 필요한 자격 증명은, 해당 AppRole에 설정된 제약 조건에 따라 달라집니다.
Step1. Vault AppRole 방식 인증 구성 - AppRole 인증이란?
Use AppRole authentication | Vault | HashiCorp Developer
Use AppRole authentication with Vault to control how machines and services authenticate to Vault.
developer.hashicorp.com
# 1. AppRole 인증 방식 활성화
vault auth enable approle || echo "AppRole already enabled"
vault auth list
# 2. 정책 생성
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 -
Step2. Vault Agent Sidecar 연동
- 1. Vault Agent config 설정
# Vault Agent는 vault-agent-config.hcl 설정을 통해 연결할
# Vault의 정보와, Template 구성, 렌더링 주기, 참조할 Vault KV 위치정보 등을 정의한다.
# 1. Vault Agent 설정 파일 작성 및 생성 (vault-agent-config.hcl) - 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 배포(수동방식)
# Nginx + Vault agent 사이드카 배포
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. SVC 생성
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
...
# 볼륨 마운트 확인
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- ls -l /etc/vault-agent-token
total 4
-rw-r----- 1 vault vault 95 Apr 10 02:09 token
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault-agent-token/token ; echo
hvs.CAESIEKGV7vnUk7UxQ4c-QQq4pSEDGdWuFNKjOESJ7WfyKHuGh4KHGh2cy5paXJCTHFMWlBKU0pFMXlQelpqaFJDYWU
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- ls -al /etc/vault
...
drwxr-xr-x 2 root root 4096 Apr 10 02:09 ..2025_04_10_02_09_17.2775716426
lrwxrwxrwx 1 root root 32 Apr 10 02:09 ..data -> ..2025_04_10_02_09_17.2775716426
lrwxrwxrwx 1 root root 23 Apr 10 02:09 agent-config.hcl -> ..data/agent-config.hcl
drwxrwxrwt 3 root root 120 Apr 10 02:09 approle
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/agent-config.hcl
...
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- ls -al /etc/vault/approle
...
lrwxrwxrwx 1 root root 14 Apr 10 02:09 role_id -> ..data/role_id
lrwxrwxrwx 1 root root 16 Apr 10 02:09 secret_id -> ..data/secret_id
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/approle/role_id ; echo
5bcefce3-e2ff-9ae3-39c1-19d380a1635e
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/vault/approle/secret_id ; echo
d50a1232-926a-81da-b053-132ee65a0ef9
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- ls -l /etc/secrets
total 4
-rw-r--r-- 1 vault vault 94 Apr 10 02:09 index.html
kubectl exec -it deploy/nginx-vault-demo -c vault-agent-sidecar -- cat /etc/secrets/index.html
<html>
<body>
<p>username: demo</p>
<p>password: p@ssw0rd</p>
</body>
</html>
kubectl exec -it 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>
# 로그 확인
kubectl stern -l app=nginx-vault-demo -c vault-agent-sidecar
# mutating admission
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io
NAME WEBHOOKS AGE
vault-agent-injector-cfg 1 3h10m
(참고) Annotation을 활용한 Vault Sidecar Injection - Docs
- Vault의 Kubernetes 인증 활성화 및 구성
# Kubernetes Auth Method 활성화
vault auth enable kubernetes
# Kubernetes Auth Config 설정
vault write auth/kubernetes/config \
token_reviewer_jwt="$(kubectl get secret $(kubectl get serviceaccount vault -n vault -o jsonpath='{.secrets[0].name}') -n vault -o jsonpath="{.data.token}" | base64 --decode)" \
kubernetes_host="$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.server}')" \
kubernetes_ca_cert="$(kubectl get secret $(kubectl get serviceaccount vault -n vault -o jsonpath='{.secrets[0].name}') -n vault -o jsonpath='{.data.ca\.crt}' | base64 --decode)"
# 필요한 Policy 작성 (앞선 과정에서 만들었으므로 생략가능)
vault policy write sampleapp-policy - <<EOF
path "secret/data/sampleapp/*" {
capabilities = ["read"]
}
EOF
# Role 생성 (Injector가 로그인할 수 있도록)
vault write auth/kubernetes/role/sampleapp-role \
bound_service_account_names="vault-ui-sa" \
bound_service_account_namespaces="vault" \
policies="sampleapp-policy" \
ttl="24h"
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-ui-sa
namespace: vault
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vault-injected-ui
namespace: vault
spec:
replicas: 1
selector:
matchLabels:
app: vault-injected-ui
template:
metadata:
labels:
app: vault-injected-ui
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "sampleapp-role"
vault.hashicorp.com/agent-inject-secret-config.json: "secret/data/sampleapp/config"
vault.hashicorp.com/agent-inject-template-config.json: |
{{- with secret "secret/data/sampleapp/config" -}}
{
"username": "{{ .Data.data.username }}",
"password": "{{ .Data.data.password }}"
}
{{- end }}
vault.hashicorp.com/agent-inject-output-path: "/vault/secrets"
spec:
serviceAccountName: vault-ui-sa
containers:
- name: app
image: python:3.10
ports:
- containerPort: 5000
command: ["sh", "-c"]
args:
- |
pip install flask && cat <<PYEOF > /app.py
import json, time
from flask import Flask, render_template_string
app = Flask(__name__)
while True:
try:
with open("/vault/secrets/config.json") as f:
secret = json.load(f)
break
except:
time.sleep(1)
@app.route("/")
def index():
return render_template_string("<h2>🔐 Vault Injected UI</h2><p>👤 사용자: {{username}}</p><p>🔑 비밀번호: {{password}}</p>", **secret)
app.run(host="0.0.0.0", port=5000)
PYEOF
python /app.py
---
apiVersion: v1
kind: Service
metadata:
name: vault-injected-ui
namespace: vault
spec:
type: NodePort
ports:
- port: 5000
targetPort: 5000
nodePort: 30003
selector:
app: vault-injected-ui
EOF
'DevOps' 카테고리의 다른 글
[AWS EKS] (28) EKS 스터디 10주차 (Vault + ArgoCD Plugin 패턴) (0) | 2025.04.12 |
---|---|
[AWS EKS] (27) EKS 스터디 10주차 ( Jenkins + Vault (AppRole) ) (0) | 2025.04.12 |
[AWS EKS] (25) EKS 스터디 8주차 (Blue-Green Upgrade) (1) | 2025.04.02 |
[AWS EKS] (24) EKS 스터디 8주차 (In-place Upgrade) (0) | 2025.03.31 |
[AWS EKS] (23) EKS 스터디 8주차 (Amazon EKS Upgrades: Strategies and Best Practices) (0) | 2025.03.31 |