25๋ ๋ AWS EKS Hands-on Study ์คํฐ๋ ์ ๋ฆฌ ๋ด์ฉ์ ๋๋ค.
๋ณธ ์ค์ต ์ฐธ๊ณ ํ์ด์ง : https://aws-ia.github.io/terraform-aws-eks-blueprints/patterns/blue-green-upgrade/
์ค์ต ํ๊ฒฝ ๊ตฌ์ฑ
์ ํจ์ค
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
# Jenkins ์ด๊ธฐ ์ํธ ํ์ธ
docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
09a21116f3ce4f27a0ede79372febfb1
# Jenkins ์น ์ ์
open "http://127.0.0.1:8080"
docker compose logs jenkins -f
์ ํจ์ค์ ์ ์ํ์ฌ ์ด๊ธฐ ์ธํ ์ ํด์ค ํ ์ด๊ธฐ ํ๋ฌ๊ทธ์ธ์ ์ค์นํ๋ค.
์ดํ ์ ์์ ์ผ๋ก ์๋ฃ๋์์ผ๋ฉด ๊ณ์ ์ธํ ์ ์งํํด์ฃผ๊ณ Jenkins ๊ด๋ฆฌ > ํ๋ฌ๊ทธ์ธ > available plugins์์ hashicorp vault๋ฅผ ๋ค์ด๋ฐ๋๋ค.
kind ํด๋ฌ์คํฐ ๊ตฌ์ฑ
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
argocd
kubectl create ns argocd
cat <<EOF > argocd-values.yaml
dex:
enabled: false
server:
service:
type: NodePort
nodePortHttps: 30002
extraArgs:
- --insecure
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
Vault
์ธ์ฆ๊ณผ ์ธ๊ฐ
์ธ์ฆ (Authentication) : "์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์ง ์ฆ๋ช ํ๋ ์ ์ฐจ"
- ์ฌ์ฉ์๊ฐ ์ฃผ์ฅํ๋ ์ ์์ ํ์ธํ๋ ๊ณผ์ ์ด๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ID์ ๋น๋ฐ๋ฒํธ, ์ธ์ฆ์, OTP, ์์ฒด ์ ๋ณด ๋ฑ์ ์ฌ์ฉํ๋ค.
- ์์
- ๋ก๊ทธ์ธํ ๋ ID/PW๋ฅผ ์ ๋ ฅํด์ ๋ด๊ฐ ์ง์ง ํน์ ์ฌ๋์ด๋ผ๋ ๊ฑธ ํ์ธ๋ฐ๋ ๊ฒ
- OAuth์์ ๊ตฌ๊ธ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๊ธฐ
์ธ๊ฐ (Authorization) : "์ฌ์ฉ์๊ฐ ๋ฌด์์ ํ ์ ์๋์ง ๊ฒฐ์ ํ๋ ์ ์ฐจ"
- ์ธ์ฆ์ด ๋๋ ์ฌ์ฉ์์๊ฒ ์ด๋ค ๊ถํ์ด ์๋์ง ํ๋จํ๋ ๊ณผ์ ์ด๋ค.
- ์ด๋ค ๋ฆฌ์์ค์ ์ ๊ทผ ๊ฐ๋ฅํ์ง, ์ด๋ค ์์ ์ ์ํํ ์ ์๋์ง๋ฅผ ๊ฒฐ์ ํ๋ค.
- ์์
- ๋ก๊ทธ์ธํ ์ฌ์ฉ์๊ฐ ๊ด๋ฆฌ์ ํ์ด์ง์ ์ ๊ทผํ ์ ์๋์ง ํ์ธ
- ํ์ผ ์์คํ ์์ ์ฝ๊ธฐ/์ฐ๊ธฐ ๊ถํ์ด ์๋์ง ์ฒดํฌ
vault ์ค์ต ํ๊ฒฝ ๊ตฌ์ฑ
helm์ผ๋ก ํจํค์ง ์ค์น
helm repo add hashicorp https://helm.releases.hashicorp.com
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
# 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" {
path = "/vault/data"
node_id = "vault-dev-node-1"
}
service:
enabled: true
type: NodePort
port: 8200
targetPort: 8200
nodePort: 30000
injector:
enabled: true
ui:
enabled: true
serviceType: "NodePort"
EOF
์ด ํ๊ฒฝ์ ์ค์ต์ฉ ๊ตฌ์ฑ์ด๋ฏ๋ก ์คํ ๋์ผ๋ก ์ ๋จ์ผ ๋ ธ๋ ํํ๋ก ๊ตฌ์ฑ์ด ์งํ๋๋ค. ์ค์ ์ด์ ํ๊ฒฝ์์๋ ๊ถ์ฅ๋์ง ์๋ ํ๊ฒฝ ๊ตฌ์ฑ์ธ ์ ์ ์ฃผ์ํ๋ค.
k get pods,svc,pvc
NAME READY STATUS RESTARTS AGE
pod/vault-0 0/1 ContainerCreating 0 14s
pod/vault-agent-injector-56459c7545-bqgk2 0/1 Running 0 14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/vault NodePort 10.96.228.133 <none> 8200:30000/TCP,8201:32730/TCP 14s
service/vault-agent-injector-svc ClusterIP 10.96.147.40 <none> 443/TCP 14s
service/vault-internal ClusterIP None <none> 8200/TCP,8201/TCP 14s
service/vault-ui NodePort 10.96.51.20 <none> 8200:31005/TCP 14s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/data-vault-0 Bound pvc-6df6d70b-9815-4f4c-b8fc-8c05efe570a5 10Gi RWO standard <unset> 14s
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
command terminated with exit code 2
vault unseal
Vault๋ '๊ธ๊ณ '๋ผ๋ ๋ป์ ๊ฐ์ง๊ณ ์๋๋งํผ ๊ธฐ๋ณธ ์ํ์์๋ '์ ๊ธด ์ฑ'๋ก ์์ํ๋ค.
- Initialize: Vault๊ฐ ์ํ๋ฅผ ์ ์ฅํ backend(์: Consul, file ๋ฑ)์ ์ต์ด ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์ฑํ๊ณ , ๋ง์คํฐ ํค์ ํค ์์ด๋ฅผ ์์ฑํ๋ค.
- Unseal: Vault๋ ์ด๊ธฐํ ์ดํ์๋ ์ค์ ๋น๋ฐ ์ ์ฅ์๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๋ด์ธ(seal)๋์ด ์๋ค. ์ต์ 3๊ฐ ์ค 2๊ฐ ์ด์์ ํค ์์ด๋ฅผ ์ ๋ ฅํด์ผ ๋ด์ธ์ ํด์ ํ ์ ์๋ค.
์ฆ, Vault๋ ์ค์นํ๋ฉด ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅ ์ํ๊ฐ ์๋๋ค. ์๋์ผ๋ก ์ด๊ธฐํํ๊ณ ๋ด์ธ์ ํด์ ํด์ผ ๋ณธ๊ฒฉ์ ์ธ ๋์์ ์์ํ๋ค.
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
kubectl exec -ti vault-0 -- vault status
Key Value
--- -----
Seal Type shamir
Initialized true
unseal ์ดํ vault-root-token.txt๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ํ ์ ์๋ค.
vault cli
brew tap hashicorp/tap
brew install hashicorp/tap/vault
export VAULT_ADDR='http://localhost:30000'
vault status
vault login
vault ์ํฌ๋ฆฟ์์ง ํ์ฑํ
vault secrets enable -path=secret kv-v2
Success! Enabled the kv-v2 secrets engine at: secret/
vault kv put secret/sampleapp/config \
username="demo" \
password="p@ssw0rd"
======== Secret Path ========
secret/data/sampleapp/config
======= Metadata =======
Key Value
--- -----
created_time 2025-04-12T16:10:07.147938837Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
vault kv get secret/sampleapp/config
======== Secret Path ========
secret/data/sampleapp/config
======= Metadata =======
Key Value
--- -----
created_time 2025-04-12T16:10:07.147938837Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password p@ssw0rd
username demo
vault sidecar ์ค์ต
AppRole ๋ฐฉ์ ์ธ์ฆ ๊ตฌ์ฑ
AppRole ์ธ์ฆ ํ์ฑํ
vault auth enable approle || echo "AppRole already enabled"
vault auth list
Success! Enabled approle auth method at: approle/
Path Type Accessor Description Version
---- ---- -------- ----------- -------
approle/ approle auth_approle_e9721a41 n/a n/a
token/ token auth_token_363206bd token based credentials n/a
์ ๊ทผ ์ ์ฑ (Policy) ์์ฑ
vault policy write sampleapp-policy - <<EOF
path "secret/data/sampleapp/*" {
capabilities = ["read"]
}
EOF
Success! Uploaded policy: sampleapp-policy
sampleapp-policy๋ผ๋ ์ด๋ฆ์ ์ ์ฑ ์ ์์ฑํ๋ค.
ํด๋น ์ ์ฑ ์ secret/data/sampleapp/* ๊ฒฝ๋ก์ KV ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ(read) ํ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ๋ค.
AppRole Role ์์ฑ
vault write auth/approle/role/sampleapp-role \
token_policies="sampleapp-policy" \
secret_id_ttl="1h" \
token_ttl="1h" \
token_max_ttl="4h"
Success! Data written to: auth/approle/role/sampleapp-role
vault policy write๋ ์ ์ฑ ์ด๋ฆ๊ณผ ๋ด์ฉ์ Vault์ ๋ฑ๋กํ๋ค.
์ด Role์ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ sampleapp-policy์ ์ ์๋ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋ ํ ํฐ์ ์ป์ ์ ์๋ค.
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)
mkdir -p approle-creds
echo "$ROLE_ID" > approle-creds/role_id.txt
echo "$SECRET_ID" > approle-creds/secret_id.txt
ROLE_ID๋ AppRole ์์ฒด์ ์๋ณ์๋ก ๊ณ ์ ๊ฐ์ด๋ฉฐ ๊ณต๊ฐ์ ์ผ๋ก ์ ๋ฌํด๋ ์์ ํ๋ค.
SECRET_ID๋ ์ผํ์ฉ ์ํฌ๋ฆฟ ํค๋ก, ์ค์ ์ธ์ฆ ์ Role ID์ ํจ๊ป ์ฌ์ฉ๋์ด Vault ์ ๊ทผ์ ํ์ฉํ๋ค.
์ด ๋ ๊ฐ์ ์กฐํฉํด์ AppRole ์ธ์ฆ ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ ์ ์๋ค.
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-approle created
ํ๋๊ฐ Vault์ ์ ๊ทผํ๊ธฐ ์ํ ์๊ฒฉ์ฆ๋ช ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
vault agent sidecar ์ฐ๋
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
Vault Agent๋ฅผ Kubernetes ํ๊ฒฝ์์ ์ฌ์ฉํ๊ธฐ ์ํ ConfigMap ์์ฑ ๊ณผ์ ์ ๋ด๊ณ ์์ผ๋ฉฐ, Vault Agent๋ Vault์์ ์ธ์ฆ, ํ ํฐ ๊ด๋ฆฌ, ์ํฌ๋ฆฟ ํ ํ๋ฆฟ ๋ ๋๋ง์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๋ ๋๊ตฌ์ด๋ค.
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
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
service/nginx-service created
kubectl get pod -l app=nginx-vault-demo
NAME READY STATUS RESTARTS AGE
nginx-vault-demo-7776649597-tcm4l 2/2 Running 0 3m14s
์ ๊ท ํจ์ค์๋
vault + jenkins
ArgoCD + vault plugin
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: ๋กค
AVP_SECRET_ID: ์ํฌ๋ฆฟ
EOF
secret/argocd-vault-plugin-credentials created
ํ๋ฌ๊ทธ์ธ ํ์ฑํ
git clone https://github.com/hyungwook0221/argocd-vault-plugin.git
cd argocd-vault-plugin/manifests/cmp-sidecar
# kustomize edit fix
kubens argocd
kubectl kustomize .
kubectl apply -n argocd -k .
์ ํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌ
kubectl apply -n argocd -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: demo
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
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
๋ํ๋ก์ด๋จผํธ์ ์ ์ฉ๋ env๊ฐ์ด ๋ณ๊ฒฝ๋ ํจ์ค์๋๋ก ์ ์ฉ๋ผ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Vault Secret Operator
# 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"]
๊ถํ ์ค์
kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh
vault login
# Kubernetes ์ธ์ฆ ๋ฉ์๋ ํ์ฑํ
vault auth enable -path k8s-auth-mount 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 k8s 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
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"
# 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
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
helm install vault-secrets-operator hashicorp/vault-secrets-operator \
-n vault-secrets-operator-system \
--create-namespace \
--values vault-operator-values.yaml
NAME: vault-secrets-operator
LAST DEPLOYED: Sun Apr 13 02:35:06 2025
NAMESPACE: vault-secrets-operator-system
STATUS: deployed
REVISION: 1
vault read auth/k8s-auth-mount/role/auth-role-operator
Key Value
--- -----
alias_name_source serviceaccount_uid
audience vault
bound_service_account_names [vault-secrets-operator-controller-manager]
bound_service_account_namespace_selector n/a
bound_service_account_namespaces [vault-secrets-operator-system]
token_bound_cidrs []
token_explicit_max_ttl 0s
token_max_ttl 0s
token_no_default_policy false
token_num_uses 0
token_period 2m
token_policies [demo-auth-policy-operator]
token_ttl 0s
token_type default
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
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
app-secret.yaml
---
# app-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: vso-db-demo
namespace: demo-ns
app-secret-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
k apply -f .
secret/vso-db-demo created
deployment.apps/vaultdemo created
service/vaultdemo created
serviceaccount/demo-dynamic-app created
vaultauth.secrets.hashicorp.com/dynamic-auth created
vaultdynamicsecret.secrets.hashicorp.com/vso-db-demo created
์ค์ต ๋ฆฌ์์ค ์ญ์
docker compose down --volumes --remove-orphans
[+] Running 3/3
โ Container jenkins Removed 0.5s
โ Volume cicd-labs_jenkins_home Removed 0.2s
โ Network cicd-labs_cicd-network Removed 0.2s
kind delete cluster --name myk8s
Deleting cluster "myk8s" ...
Deleted nodes: ["myk8s-worker2" "myk8s-worker" "myk8s-control-plane"]
'Infra > AWS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[AEWS] #9์ฃผ์ฐจ EKS ๋ธ๋ฃจ ๊ทธ๋ฆฐ ๋ง์ด๊ทธ๋ ์ด์ with Terraform (0) | 2025.04.03 |
---|---|
[AEWS] #8์ฃผ์ฐจ ์ ํจ์ค, ArgoCD ์ค์ต (1) | 2025.03.30 |
[AEWS] #7์ฃผ์ฐจ Fargate ๋ฐฐํฌ ์ค์ต (1) | 2025.03.23 |
[AEWS] #6์ฃผ์ฐจ Kyverno ์ค์ต (5) (0) | 2025.03.16 |
[AEWS] #6์ฃผ์ฐจ IRSA ์ค์ต (4) (1) | 2025.03.16 |