현재 Vault의 기본 구조와 설치, 그리고 Kubernetes 환경에서 Sidecar 패턴으로 Vault를 연동하는 부분까지 학습을 마쳤습니다.
이를 기반으로 이제 실제 CI/CD 파이프라인과 Kubernetes 환경에서 Vault를 활용하는 실습을 진행하려고 합니다.
최종적으로 Jenkins를 통한 CI, Argo CD를 통한 CD, 그리고 Vault Secrets Operator를 통한 Kubernetes 환경의 시크릿 관리까지 모두 Vault와 연계하여 일관성 있고 안전하게 시크릿을 다루는 체계를 마련하는 것이 목표입니다.
CI 파이프라인에서 필요한 민감 정보를 안전하게 관리하기 위해 Vault 의 KV Store 에 username 과 password 와 같은 정적 시크릿을 저장하고Jenkins 와 Vault 를 연동하여 파이프라인 실행 시 필요한 시크릿을 외부 Vault 로부터 안전하게 획득할 수 있도록 구성하여 사용하겠습니다.
① Jenkins에서 Vault Plugin 설치
② Vault AppRole 정보 확인
Vault에서 발급된 ROLE_ID, SECRET_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
③ Jenkins에서 Vault 설정 및 Credentials 추가
④ Jenkins Pipeline Job 생성
Jenkins UI → New Item → Pipeline 선택 → jenkins-vault-kv 입력 후 생성
JekinsFile 작성
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}"
}
}
}
}
}
}
※ 참고 KV Version1은 경로에 data을 넣고 Version2는 경로에 data을 넣지 않습니다.(참고)
· Version 1 : secret/data/sampleapp/config
· Version 2 : secret/sampleapp/config
Argo CD Vault Plugin은 GitOps 환경에서 외부 시크릿 관리 도구를 손쉽게 통합할 수 있게 해주는 플러그인입니다.
Kubernetes Secret 뿐 아니라 다양한 리소스에 시크릿 데이터를 주입할 수 있고 설치 방법으로는 ConfigMap 방식과 사이드카 컨테이너 방식이 있으며, 보안성과 관리 효율성을 고려한다면 사이드카 컨테이너 방식을 우선적으로 검토하는 것이 좋습니다.사이드카 컨테이너를 활용한 방법은 Argo CD v2.4.0부터 도입된 최신 방식 입니다.
① ArgoCD Vault Plugin을 위한 Credentials 활성화(AppRole 인증)
먼저 이전 실습에서 획득한 Role_ID와 Secret_ID를 활용해서 Argo CD가 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: a0f91e0f-714e-2b23-788f-e728afa8582c #Role_ID
AVP_SECRET_ID: db232aea-88ca-10f1-57ff-8ee14aaf1376 #Secret_ID
EOF
② ArgoCD Vault Plugin 설치
ArgoCD Helm 설치시 Plugin 활성화 방안
# GitHub 저장소에서 argocd-vault-plugin 예제 또는 배포용 파일 복제
git clone https://github.com/hyungwook0221/argocd-vault-plugin.git
cd argocd-vault-plugin/manifests/cmp-sidecar
# 예전 문법으로 적용된 부분을 edit fix 명령으로 현행화
# kustomize edit fix
# argocd 네임스페이스 설정
kubens argocd
# 생성될 메니페스트 파일에 대한 확인
kubectl kustomize .
# -k 옵션으로 kusomize 실행
kubectl apply -n argocd -k .
# vault-0 Pod 접속
kubectl exec -it -n vault vault-0 -- sh
# 접속 후 root token으로 로그인
vault login
Token (will be hidden): <토큰입력>
# 확인명령
vault read auth/kubernetes/role/argocd
③ 샘플 Application 배포하여 Vault와 동기화
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
Argo CD 에서 Vault Plugin 을 사용할 때 Vault 설정 변경이나 인증 오류 발생 시 캐시된 정보 때문에 배포시 오류가 발생할 수 있기 때문에 Argo CD repo-server 와 Redis 를 재기동해서 캐시를 초기화한 다음 애플리케이션을 재배포 해주시면 됩니다.
Vault Secrets Operator는 Vault에 저장된 시크릿이나 HCP Vault 시크릿 앱의 데이터를 Kubernetes 네이티브 방식으로 Pod 에 주입하는 오퍼레이터 입니다.
VSO를 활용하면 Vault 에 있는 시크릿을 Kubernetes Secret 으로 자동으로 동기화해서 사용할 수 있고 애플리케이션은 Kubernetes Secret 만 바라보면 되기 때문에 Vault 와 직접적으로 통신할 필요가 없습니다.
즉, Vault 와 Kubernetes 사이의 시크릿 자동화 브릿지 역할을 하는 것입니다.
구분 | 운영자 (Operator) 역할 | 개발자 (Developer) 역할 |
Vault 및 VSO 설치 | Vault 서버 설치 및 VSO 배포 (Helm 또는 Kustomize) | 사용자가 별도로 설치할 필요 없음 |
CRD 관리 | SecretExternalResource 같은 VSO CRD 생성 및 관리 | CRD 를 요청하거나 참고하지만, 직접 관리하지 않음 |
시크릿 정책 설정 | Vault 정책 관리, 시크릿 동기화 대상 지정 | 애플리케이션이 참조할 Kubernetes Secret 이름만 인지 |
시크릿 접근 권한 | Vault 인증 방식 (AppRole, Kubernetes Auth 등) 설정 및 접근 제어 | 별도 인증 로직 없이 Kubernetes Secret 만 참조 |
애플리케이션 연동 | Kubernetes Secret 생성 및 유지보수 관리 | 애플리케이션에서 Kubernetes Secret 을 환경 변수나 마운트로 사용 |
모니터링 및 운영 | Prometheus 등으로 VSO 상태 및 시크릿 동기화 모니터링 | 필요 시 알림을 받고 대응, 별도 모니터링 필요 없음 |
시크릿 변경 시 대응 | Vault 또는 CRD 변경 시 Kubernetes Secret 자동 갱신 확인 | 애플리케이션은 변경된 Secret 을 자동으로 사용 (재배포 불필요) |
① VaultConnection
# Vault 서버 연결 정보
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
namespace: vso-example
name: vault-connection
spec:
address: http://vault.vault.svc.cluster.local:8200
② VaultAuth
# Vault 인증 정보 (주로 Kubernetes Auth)
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
namespace: vso-example
name: vault-auth
spec:
vaultConnectionRef: vault-connection
method: kubernetes
mount: kubernetes
kubernetes:
role: example
serviceAccount: default
③ VaultAuthGlobal
# 전역 인증 정보 정의
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuthGlobal
metadata:
namespace: vso-example
name: vault-auth-global
spec:
defaultAuthMethod: kubernetes
kubernetes:
audiences:
- vault
mount: kubernetes
namespace: example-ns
role: auth-role
serviceAccount: default
tokenExpirationSeconds: 600
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
namespace: vso-example
name: vault-auth
spec:
vaultAuthGlobalRef:
name: vault-auth-global
kubernetes:
role: local-role
④ VaultStaticSecret
# Vault 의 정적 시크릿을 Kubernetes Secret 으로 동기화
# KV v1
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
namespace: vso-example
name: vault-static-secret-v1
spec:
vaultAuthRef: vault-auth
mount: kvv1
type: kv-v1
path: eng/apikey/google
refreshAfter: 60s
destination:
create: true
name: static-secret1
---
# KV v2
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
namespace: vso-example
name: vault-static-secret-v2
spec:
vaultAuthRef: vault-auth
mount: kvv2
type: kv-v2
path: eng/apikey/google
version: 2
refreshAfter: 60s
destination:
create: true
name: static-secret2
⑤ VaultDynamicSecret
# Vault 의 동적 시크릿 (DB, AWS IAM)
# DB Secret
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
namespace: vso-example
name: vault-dynamic-secret-db
spec:
vaultAuthRef: vault-auth
mount: db
path: creds/my-postgresql-role
destination:
create: true
name: dynamic-db
---
# AWS Secret
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
namespace: vso-example
name: vault-dynamic-secret-aws-iam
spec:
vaultAuthRef: vault-auth
mount: aws
path: creds/my-iam-role
destination:
create: true
name: dynamic-aws-iam
⑥ VaultPKISecret
# Vault 의 PKI 시크릿을 Kubernetes Secret 으로 동기화
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultPKISecret
metadata:
namespace: vso-example
name: vault-pki
spec:
vaultAuthRef: vault-auth
mount: pki
role: default
commonName: example.com
format: pem
expiryOffset: 1s
ttl: 60s
namespace: tenant-1
destination:
create: true
name: pki1
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"]
VSO 배포
helm install vault-secrets-operator hashicorp/vault-secrets-operator \
-n vault-secrets-operator-system \
--create-namespace \
--values vault-operator-values.yaml
11주차 - ML Infra(GPU) on EKS (1) | 2025.04.20 |
---|---|
10주차 - K8S 시크릿 관리 (1) (0) | 2025.04.12 |
9주차 - EKS Upgrade (0) | 2025.04.03 |
8주차 - K8S CI/CD (3) (0) | 2025.03.30 |
8주차 - K8S CI/CD (1) (1) | 2025.03.30 |