본문 바로가기
CI&CD

[ArgoCD] Vault 플러그인으로 인증 관리하기

by interlude-3 2025. 11. 11.

1. 왜 Vault가 필요할까?


Kubernetes 환경에서 Secret은 API 키, 비밀번호, 토큰처럼 민감한 정보를 저장하는 데 사용되지만,

실제 운영 환경에서는 단순히 Secret만 안전하게 보관하는 걸로는 충분하지 않습니다.


인증서, 데이터베이스 자격 증명, 클라우드 액세스 키, OAuth 토큰, TLS 인증서, 서명 키 등 서비스 전반에서 사용하는 모든 보안 자격증명이 관리 대상이 됩니다. 이러한 정보를 코드나 Git 저장소에 그대로 넣는 것은 보안상 위험합니다.


Vault는 이런 문제를 해결하기 위해 설계된 보안 비밀 관리 및 접근 제어 플랫폼입니다.

 

2. GitOps 환경에서 Vault의 필요성


GitOps의 핵심은 Git을 단일 진실의 원천(Single Source of Truth)으로 삼는 것입니다. 하지만 배포에 필요한 민감한 설정값(예: DB 비밀번호, API 토큰 등)을 Git에 그대로 넣을 수는 없습니다. Vault를 연동하면 다음과 같은 구조를 만들 수 있습니다.

 
[Developer]
└── 코드 & 매니페스트만 Git에 저장
 
[ArgoCD Repo Server]
└── Vault에서 필요한 보안 정보 동적으로 가져옴
 
[Vault]
└── Secret, 인증서, 자격 증명 중앙 관리
 

이렇게 되면 Git에는 민감한 값이 저장되지 않고, ArgoCD가 배포할 때만 Vault에서 해당 값을 안전하게 주입 가능합니다.

 

3. ArgoCD Vault Plugin


ArgoCD Vault Plugin (AVP) 는 배포 시점에 Vault에서 Secret 값을 읽어와 Kubernetes 리소스에 자동 주입합니다. 결과적으로 Git에는 민감한 정보 없이 안전한 선언적 설정만 존재하게 됩니다.
 
[작동 방식]

  1. 개발자는 Git에 Secret Placeholder를 작성합니다.
  2. apiVersion: v1 kind: Secret metadata: name: my-db-secret stringData: username: <path:kv-v2/data/demo#user> password: <path:kv-v2/data/demo#password>
  3. ArgoCD가 배포를 트리거할 때,
    argocd-vault-plugin이 <path:...> 구문을 읽고 Vault에서 실제 값을 가져옵니다.
  4. 가져온 값으로 템플릿을 렌더링해 Kubernetes에 배포합니다.

 

4. ArgoCD + Vault 연동 구조


[Developer]
 │ commits manifests to GitHub
[ArgoCD Repo Server]
 ├── pulls manifests
 ├── runs argocd-vault-plugin
  │              └── authenticates with Vault (K8s Auth)
  │              └── retrieves Secrets securely
 ▼
[Kubernetes Cluster]
└── applies real Secret manifests
 
  • Vault는 Kubernetes Auth Method로 인증 (ServiceAccount 기반)
  • ArgoCD Repo Server는 ServiceAccount 토큰을 이용해 Vault에 로그인
  • Vault Policy로 필요한 Secret 경로만 접근 허용

이 구조를 통해 Git은 완전히 클린 상태로 유지하면서
배포 시점에는 Vault에서만 인증된 Secret이 주입됩니다.

 

5. 실습 진행 (ArgoCD + Vault)


5-1. ArgoCD 설치

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
  labels:
    ingress-ready: true
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003
EOF
kubectl get nodes myk8s-control-plane -o jsonpath={.metadata.labels} | jq

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

kubectl edit -n ingress-nginx deployments/ingress-nginx-controller

"--enable-ssl-passthrough" args 추가

 

5-2.  OpenSSL로 self-signed 인증서 생성 및 Secrets 생성

  • Argo CD 서버는 TLS 인증서를 "argocd-server-tls" Secret 에서 직접 로드
  • server.ingress.tls=true
  • nginx.ingress.kubernetes.io/ssl-passthrough=true

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout argocd.example.com.key \
  -out argocd.example.com.crt \
  -subj "/CN=argocd.example.com/O=argocd"
  
kubectl create ns argocd

kubectl -n argocd create secret tls argocd-server-tls \
  --cert=argocd.example.com.crt \
  --key=argocd.example.com.key
cat <<EOF > argocd-values.yaml
global:
  domain: argocd.example.com
server:
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    tls: true
EOF

helm repo add argo https://argoproj.github.io/argo-helm

helm install argocd argo/argo-cd --version 9.0.5 -f argocd-values.yaml --namespace argocd

 

echo "127.0.0.1 argocd.example.com" | sudo tee -a /etc/hosts

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo

argocd login argocd.example.com --insecure

argocd account update-password

admin/1234qwer

 

5-3.  Vault 설치

helm repo add hashicorp https://helm.releases.hashicorp.com

helm repo update

helm search repo hashicorp/vault

vi vault-server-values.yaml
---
server:
  dev:
    enabled: true
    devRootToken: "root"
  logLevel: debug

injector:
  enabled: "false"


helm install vault hashicorp/vault -n vault --create-namespace --values vault-server-values.yaml

 

5-4.  Vault CLI로 KV Secret 등록

root@ria:/home/ria/argocd-vault# kubectl exec -n vault vault-0 -it -- sh
/ $ vault secrets enable kv-v2
Success! Enabled the kv-v2 secrets engine at: kv-v2/
/ $ vault kv put kv-v2/demo user="ria" password="ria1031"
= Secret Path =
kv-v2/data/demo

======= Metadata =======
Key                Value
---                -----
created_time       2025-11-12T13:23:09.46253118Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
/ $ vault policy write demo - <<EOF
> path "kv-v2/data/demo" {
>   capabilities = ["read"]
> }
> EOF
Success! Uploaded policy: demo
/ $ 
/ $ vault auth enable kubernetes
Success! Enabled kubernetes auth method at: kubernetes/
/ $ 
/ $ vault write auth/kubernetes/config \
>   token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
>   kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
>   kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Success! Data written to: auth/kubernetes/config
/ $ 
/ $ vault write auth/kubernetes/role/argocd \
>   bound_service_account_names=argocd-repo-server \
>   bound_service_account_namespaces=argocd \
>   policies=demo \
>   ttl=48h \
>   audience=vault
Success! Data written to: auth/kubernetes/role/argocd

 

5-5.  ArgoCD Vault Plugin 설치 및 설정

argocd-repo-server에 argocd-vault-plugin을 설치하고 vault 인증정보를 설정하면 ArgoCD에서 동기화할 때 vault 값을 kubernetes 설정 정보에 반영해서 적용합니다.

vi vault-plugin-secret.yaml

kind: Secret
apiVersion: v1
metadata:
  name: argocd-vault-plugin-credentials
  namespace: argocd
type: Opaque
stringData:
  AVP_AUTH_TYPE: "k8s"
  AVP_K8S_ROLE: "argocd"
  AVP_TYPE: "vault"
  VAULT_ADDR: "http://vault.vault:8200"
  
kubectl create -f vault-plugin-secret.yaml

argocd-repo-server를 패치하여 argocd-vault-plugin을 다운로드하고 사이드카를 정의하기 위한 initContainer 추가

kubectl edit deployment argocd-repo-server -n argocd -o yaml

# custom-tools volume 추가
volumes:
      - configMap:
          name: cmp-plugin
        name: cmp-plugin
      - emptyDir: {}
        name: custom-tools

 
# initContainer 추가
initContainers:
      - name: download-tools
        image: alpine/curl
        env:
          - name: AVP_VERSION
            value: 1.15.0
        command: [sh, -c]
        args:
          - >-
            curl -L https://github.com/argoproj-labs/argocd-vault-plugin/releases/download/v$(AVP_VERSION)/argocd-vault-plugin_$(AVP_VERSION)_linux_amd64 -o argocd-vault-plugin &&
            chmod +x argocd-vault-plugin &&
            mv argocd-vault-plugin /custom-tools/
        volumeMounts:
          - mountPath: /custom-tools
            name: custom-tools
   
   
# custom-tools mount 추가, env 추가
# AVP-Helm : argocd-vault-plugin with Helm
containers:
      - name: avp-helm
        command: [/var/run/argocd/argocd-cmp-server]
        image: quay.io/argoproj/argocd:v2.7.4
        securityContext:
          runAsNonRoot: true
          runAsUser: 999
        volumeMounts:
          - mountPath: /var/run/argocd
            name: var-files
          - mountPath: /home/argocd/cmp-server/plugins
            name: plugins
          - mountPath: /tmp
            name: tmp

          # Register plugins into sidecar
          - mountPath: /home/argocd/cmp-server/config/plugin.yaml
            subPath: avp-helm.yaml
            name: cmp-plugin

          # Important: Mount tools into $PATH
          - name: custom-tools
            subPath: argocd-vault-plugin
            mountPath: /usr/local/bin/argocd-vault-plugin

상태 확인
kubectl logs -f argocd-repo-server-5fb98c4c5f-k2b86 -n argocd repo-server
 

5-6.  샘플 애플리케이션 배포 (Secret 참조 포함)

argocd repo add https://github.com/ria-choi/argocd-vault-sample \
  --username ria-choi \
  --password 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
  
argocd repo list
TYPE  NAME  REPO                                             INSECURE  OCI    LFS    CREDS  STATUS      MESSAGE  PROJECT
git         https://github.com/ria-choi/argocd-vault-sample  false     false  false  false  Successful
cat application.yaml
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/ria-choi/argocd-vault-sample
    targetRevision: main
    plugin:
      env:
        - name: HELM_ARGS
          value: '-f override-values.yaml'
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      
      
kubectl apply -f application.yaml

kubectl get application -n argocd
NAMESPACE   NAME   SYNC STATUS   HEALTH STATUS
argocd      demo   Unknown       Healthy

 

5-7.  ArgoCD App Sync 

 
***에러 발생
(결국 해결 못함.. 버전업그레이드해서 다시 해보기)

Message:            ComparisonError: Failed to load target state: failed to generate manifest for source 1 of 1: rpc error: code = Unknown desc = Manifest generation error (cached): plugin sidecar failed. error generating manifests in cmp: rpc error: code = Unknown desc = error generating manifests: `sh -c "helm template $ARGOCD_APP_NAME -n $ARGOCD_APP_NAMESPACE ${ARGOCD_ENV_HELM_ARGS} . |\nargocd-vault-plugin generate -\n"` failed exit status 1: Error: Error making API request.

URL: PUT http://vault.vault:8200/v1/auth/kubernetes/login
Code: 403. Errors:

* invalid audience (aud) claim: audience claim does not match any expected audience

 
 
 
참고
ArgoCD Vault Plugin | docmoa

 

ArgoCD Vault Plugin

ArgoCD Vault Plugin 연동방안

docmoa.github.io

[GitOps]ArgoCD에 Vault 적용하기

 

[GitOps]ArgoCD에 Vault 적용하기

ArgoCD로 kubernetes로 자동배포를 위해 git 저장소를 이용하는데 configmap, secret의 민감한 정보 관리를 위해 vault를 적용해서 GitOps를 구성한 경험을 정리한 글입니다.

velog.io