ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [AEWS 3기] 10주차 - K8S 시크릿 관리
    AWS 2025. 4. 12. 22:20
      1. 실습환경 - Kind k8s cluster & Jenkins & ArgoCD

      0.1. kind 로 k8s 배포 : macOS 사용자 → 필수

          1. 기본 정보 확인
      # 클러스터 배포 전 확인
      docker ps
      
      # Create a cluster with kind
      MyIP=<각자 자신의 PC IP>
      MyIP=192.168.254.127
      
      # 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
      
      KUBECONFIG=$PWD/kubeconfig
      
      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
       
          1. (참고) 클러스터 삭제
      # 클러스터 삭제
      kind delete cluster --name myk8s
      docker ps
      cat ~/.kube/config
       

      0.2. 컨테이터 (Jenkins) : 호스트 OS 포트 노출(expose)로 접속 및 사용 : macOS 사용자 → 필수

          1. 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
       
          1. Jenkins 컨테이너 초기 설정
      # Jenkins 초기 암호 확인
      docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
      5ecee51cb8694adeb1c77aee0af065df
      
      # Jenkins 웹 접속 주소 확인 : 계정 / 암호 입력 >> admin / qwe123
      open "http://127.0.0.1:8080" # macOS
      웹 브라우저에서 http://127.0.0.1:8080 접속 # Windows
      
      # (참고) 로그 확인 : 플러그인 설치 과정 확인
      docker compose logs jenkins -f
      
      # Jenkins URL
      http://192.168.0.10:8080/
       
          1. Jenkins URL 설정 : 각자 자신의 PC의 IP를 입력
      image
       
       
      (참고) 실습 완료 후 해당 컨테이너 중지 상태로 둘 경우 → 재부팅 및 이후에 다시 실습을 위해 컨테이너 시작 시
      (참고) 특정 컨테이너만 삭제 후 다시 초기화 상태로 기동 시
          1. (참고) 모든 실습 후 삭제 시 : docker compose down --volumes --remove-orphans
       

      0.3. ArgoCD 설치

      0.3.1. ArgoCD 이전 스터디 내용
      Argo CD 소개 : Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes
      (기초) helm chart 를 통한 배포 실습
      0.3.2. Argo CD 설치 및 기본 설정 - helm_chart
        • Argo CD 설치
      # 네임스페이스 생성 및 파라미터 파일 작성
      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 접속
       
        • Argo CD 웹 접속 확인
          • User info → UPDATE PASSWORD 로 admin 계정 암호 변경 (qwe12345)
       
          • 기본 정보 확인 (Settings) : Clusters, Projects, Accounts
        image
         
         
          1. Vault 개요

        1.1. Vault란? - Docs

        HashiCorp Vault는 신원 기반(identity-based)의 시크릿 및 암호화 관리 시스템입니다. 이 시스템은 인증(authentication)인가(authorization) 방법을 통해 암호화 서비스를 제공하여 비밀에 대한 안전하고 감사 가능하며 제한된 접근을 보장합니다.

        시크릿(Secret)이란 접근을 철저히 통제하고자 하는 모든 것을 의미하며, 예를 들어 토큰, API 키, 비밀번호, 암호화 키 또는 인증서 등이 이에 해당합니다. Vault는 모든 시크릿에 대해 통합된 인터페이스를 제공하면서, 엄격한 접근 제어와 상세한 감사 로그 기록 기능을 제공합니다.

        외부 서비스용 API 키, 서비스 지향 아키텍처 간 통신을 위한 자격 증명 등은 플랫폼에 따라 누가 어떤 비밀에 접근했는지를 파악하기 어려울 수 있습니다. 여기에 키 롤링(교체), 안전한 저장, 상세한 감사 로그까지 추가하려면 별도의 커스텀 솔루션 없이는 거의 불가능합니다. Vault는 바로 이 지점에서 해결책을 제공합니다.

        Vault는 클라이언트(사용자, 기계, 애플리케이션 등)를 검증하고 인가한 후에만 비밀이나 저장된 민감한 데이터에 접근할 수 있도록 합니다.

        image
        관련 이미지 및 영상
        image
        HashiCorp 공동 창업자이자 CTO인 Armon Dadgar가 소개하는 Vault 영상

         

        1.2. 대표적인 시크릿의 종류

        • 비밀번호
        • Cloud Credentials : AWS, GCP, Azure, NCP
        • Database Credentials : MySQL,
        • SSH Key
        • Token, API Key : GitHub, Telegram, Slack, OpenAI, Claude
        • 인증서(PKI, TLS 등)
        그 밖에 어떤 대표적인 Secret이 있을까요?🤔

         

        1.3. Vault의 동작방식? - Docs

        Vault는 주로 토큰(Token)을 기반으로 작동하며, 이 토큰은 클라이언트의 정책(Policy)과 연결되어 있습니다. 각 정책은 경로(path) 기반으로 설정되며, 정책 규칙은 클라이언트가 해당 경로에서 수행할 수 있는 작업과 접근 가능성을 제한합니다.

        Vault에서는 토큰을 수동으로 생성해 클라이언트에 할당할 수도 있고, 클라이언트가 로그인하여 토큰을 직접 획득할 수도 있습니다.

        • 아래 그림은 Vault의 핵심 워크플로우를 보여줍니다.
        image

        Vault의 핵심 워크플로우는 다음 네 단계로 구성됩니다:

        1. 인증 (Authenticate): Vault에서 인증은 클라이언트가 Vault에 자신이 누구인지 증명할 수 있는 정보를 제공하는 과정입니다. 클라이언트가 인증 메서드를 통해 인증되면, 토큰이 생성되고 정책과 연결됩니다.
        2. 검증 (Validation): Vault는 Github, LDAP, AppRole 등과 같은 신뢰할 수 있는 외부 소스를 통해 클라이언트를 검증합니다.
        3. 인가 (Authorize): 클라이언트는 Vault의 보안 정책과 비교됩니다. 이 정책은 Vault 토큰을 사용하여 클라이언트가 접근할 수 있는 API 엔드포인트를 정의하는 규칙의 집합입니다. 정책은 Vault 내 특정 경로나 작업에 대한 접근을 허용하거나 거부하는 선언적 방식으로 권한을 제어합니다.
        4. 접근 (Access): Vault는 클라이언트의 신원에 연관된 정책을 기반으로 토큰을 발급하여 비밀, 키, 암호화 기능 등에 대한 접근을 허용합니다. 클라이언트는 이후 작업에서 해당 Vault 토큰을 사용할 수 있습니다.

         

        1.4. 왜 Vault가 필요한가요?

        오늘날 대부분의 기업은 자격 증명이 조직 전반에 걸쳐 무분별하게 퍼져 있습니다. 비밀번호, API 키, 자격 증명 등이 일반 텍스트로 앱 소스 코드, 설정 파일, 기타 여러 위치에 저장되어 있습니다. 자격 증명이 이처럼 여기저기 흩어져 있으면 누가 무엇에 접근하고 권한이 있는지를 명확히 파악하기 어렵고, 그로 인해 큰 부담이 따릅니다. 일반 텍스트로 자격 증명을 저장하면 내부 공격자든 외부 공격자든 악의적인 공격 가능성이 크게 증가합니다.

        Vault는 이러한 문제를 해결하기 위해 설계되었습니다. Vault는 이러한 모든 자격 증명을 한 곳에 중앙 집중화하여 정의함으로써, 자격 증명의 불필요한 노출을 줄입니다. 하지만 Vault는 여기서 멈추지 않고, 사용자, 애플리케이션, 시스템이 인증 및 명시적으로 인가된 후에만 리소스에 접근할 수 있도록 보장하며, 클라이언트의 모든 작업 기록을 추적하고 저장하는 감사 로그 기능도 제공합니다.

        Vault의 주요 기능은 다음과 같습니다:

        1. 안전한 비밀 저장 (Secure Secret Storage): → Static 시크릿

        Vault는 임의의 key/value 형식의 시크릿을 저장할 수 있으며, 이 시크릿은 영구 저장소에 기록되기 전에 암호화됩니다. 따라서 저장소에 직접 접근하더라도 비밀을 열람할 수 없습니다. Vault는 Disk, Consul 등 다양한 저장소를 지원합니다.

        2. 동적 비밀 (Dynamic Secrets):

        Vault는 AWS나 SQL 데이터베이스와 같은 일부 시스템에 대해 요청 시 비밀을 동적으로 생성할 수 있습니다. 예를 들어, 애플리케이션이 S3 버킷에 접근해야 할 때 Vault에 자격 증명을 요청하면, Vault는 해당 권한을 가진 AWS 키쌍을 생성해줍니다. 이 동적 시크릿은 일정 시간이 지나면 자동으로 폐기됩니다.

        3. 데이터 암호화 (Data Encryption):

        Vault는 데이터를 저장하지 않고 암호화 및 복호화를 수행할 수 있습니다. 이를 통해 보안 팀은 암호화 매개변수를 정의하고, 개발자는 암호화된 데이터를 SQL 데이터베이스 등 외부 저장소에 안전하게 저장할 수 있습니다.

        4. 임대 및 갱신 (Leasing and Renewal):

        Vault에 저장된 모든 시크릿은 임대 기간(lease)이 설정되어 있으며, 이 기간이 끝나면 해당 비밀은 자동으로 폐기됩니다. 클라이언트는 내장된 갱신 API를 통해 임대를 연장할 수 있습니다.

        5. 폐기 (Revocation):

        Vault는 비밀 폐기를 기본적으로 지원합니다. 단일 비밀뿐만 아니라 특정 사용자에 의해 읽힌 모든 비밀, 또는 특정 유형의 모든 비밀 등 비밀의 계층 구조 전체를 폐기할 수 있습니다. 이 기능은 키 롤링이나 침입 발생 시 시스템을 신속하게 차단하는 데 유용합니다.

         

        1.5. Vault 요약

        특징
        HashiCorp Vault
        주요 기능
        다양한 환경과 플랫폼에서 secret을 저장, 액세스 및 배포하기 위한 포괄적인 secret 관리 솔루션
        암호화
        높은 유연성과 보안을 위해 여러 암호화 백엔드(예: AWS KMS, Azure Key Vault, GCP KMS)를 지원하는 고급 암호화 메커니즘을 제공합니다.
        접근 제어
        역할, 경로 및 작업을 기반으로 세분화된 권한을 허용하는 세부적인 액세스 제어 정책(ACL)을 구현합니다.
        동적 secret
        데이터베이스, 클라우드 자격 증명, SSH 키와 같은 리소스에 대한 일시적이고 주문형 액세스를 제공하여 동적 secret 생성을 지원합니다.
        감사 로깅
        모든 작업과 액세스 요청을 추적하여 책임과 추적성을 보장하기 위한 포괄적인 감사 로그를 제공합니다.
        완성
        Kubernetes, Terraform, Jenkins 및 클라우드 공급자와 같은 광범위한 도구 및 서비스와의 광범위한 통합을 통해 광범위한 애플리케이션 범위가 가능합니다.
        설치 복잡성
        서버 배포 및 구성을 포함한 더 많은 설정 및 인프라가 필요하며 학습 곡선이 더 가파를 수 있습니다.
        secret rotation
        자동화된 secret rotation을 지원하여 secret이 정기적으로 업데이트되고 노출 위험이 최소화되도록 합니다.
        API 및 CLI
        다양한 작업을 위한 vault와의 광범위한 프로그래밍 액세스 및 상호 작용을 허용하는 풍부한 API 및 CLI를 제공합니다.
        사용 사례
        동적 secret 생성, 서비스로서의 암호화, 다양한 애플리케이션 및 환경에서의 안전한 데이터 저장을 포함한 광범위한 사용 사례에 적합합니다.
        전개
        최적의 성능과 보안을 위해 전용 인프라와 리소스가 필요한 독립 실행형 서비스로 배포됨
        확장성
        분산 환경에서 대량의 secret과 여러 클라이언트를 처리할 수 있는 높은 확장성을 위해 설계되었습니다.
        버전 관리
        secret 버전 관리를 지원하여 사용자가 시간 경과에 따라 다양한 버전의 secret을 추적하고 관리할 수 있도록 합니다.
        오픈소스
        추가 기능과 지원을 제공하는 엔터프라이즈 버전과 함께 오픈 소스 도구로 사용 가능

        1.6. 시크릿을 관리할 수 있는 여러 방법

        • private 망에 있는 각 서버들의 .evn에 환경변수로 저장하여 관리
          • server마다 환경변수 세팅하여 관리해야하는 번거로움
          • FE에서는 server가 없으므로 server 환경변수로는 관리 어려움
          • 정보의 파편화가 올라감
        • Jenkins, Github, Dockerhub 등의 Credentials에 등록하여 관리
          • github이나 dockerhub는 repository 종속적이고, 같은 정보를 repository마다 각각 세팅하여 관리해야 함
          • 정보의 파편화가 올라감
        • Jenkins Config file Provider 활용
          • jenkins에서 build시에 주입할 수 있는 장점
          • audit log를 관리하기 어려움
        • Secret Management System 사용하여 관리
          • 비용, 사용방법, 다양한 언어 제공 등의 학습 비용 발생
          • 초기 진입 허들

         

        1.7. Vault 동작 방식 이해하기

        호텔 체크인 절차에 비유한 Vault의 동작방식 이해

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

         

        1.8. Vault 내부 아키텍처 - Docs

        • High Level
        image
         
          1. Kubernetes에 Vault 설치 - Docs1 Docs2

        2.1. 실습환경 구성

        Step1. Helm을 사용한 Vault 배포 -
        • 네임스페이스 생성 및 Helm Repo 추가
        # 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
        
        # 네임스페이스 변경 : vault
        kubens vault
        Context "kind-myk8s" modified.
        Active namespace is "vault".
        
        # 배포확인
        k get pods,svc,pvc
        
        NAME                                        READY   STATUS              RESTARTS   AGE
        pod/vault-0                                 0/1     ContainerCreating   0          14s
        pod/vault-agent-injector-56459c7545-sgtth   1/1     Running             0          15s
        
        NAME                               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
        service/vault                      NodePort    10.96.120.103   <none>        8200:30000/TCP,8201:32281/TCP   15s
        service/vault-agent-injector-svc   ClusterIP   10.96.249.165   <none>        443/TCP                         15s
        service/vault-internal             ClusterIP   None            <none>        8200/TCP,8201/TCP               15s
        service/vault-ui                   NodePort    10.96.105.103   <none>        8200:31916/TCP                  15s
        
        NAME                                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
        persistentvolumeclaim/data-vault-0   Bound    pvc-c6dcf24c-acdb-4b13-b1c2-064207a206fb   10Gi       RWO            standard       <unset>                 15s
         
        Step2. Vault 초기화 및 잠금해제
        • 상태확인
        # Vault Status 명령으로 Sealed 상태확인
        kubectl exec -ti vault-0 -- vault status
        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
        • vault status 명령을 사용하여 Unseal 되었는지 확인한다 → Sealed=false
        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              90fbefc2-3218-c047-43de-23a11223d869
        Removed From Cluster    false
        HA Enabled              true
        HA Cluster              https://vault-0.vault-internal:8201
        HA Mode                 active
        Active Since            2025-04-12T05:19:35.118981221Z
        Raft Committed Index    37
        Raft Applied Index      37
         

        (참고) UI에 접속해서 Unseal Key 입력도 가능

        image
         

        이제 Unseal이 마무리 되었으므로 Root Token 값을 사용하여 UI에 접속할 수 있습니다.

         
        • Root Token 입력 후 Vault UI 화면 - vault-root-token.txt 파일에서 획득
        open "http://$MyIP:30000"
        
        #token은 앞에서 unseal을 통해 획득한 root token을 입력!!
        hvs.GdQtl6yNEcSeeDSGXCXVQRzx
        image
         
        Step3. CLI 설정(MacOS) - Docs / 수동설치
        brew tap hashicorp/tap
        brew install hashicorp/tap/vault
        
        vault --version  # 설치 확인
        Vault v1.19.1 (aa75903ec499b2236da9e7bbbfeb7fd16fa4fd9d), built 2025-04-02T15:43:01Z
        
        # NodePort로 공개한 30000 Port로 설정
        export VAULT_ADDR='http://localhost:30000'
        
        # vault 상태확인
        vault status
        
        # Root Token으로 로그인
        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.egeVgnhMKgnFqof6YLfiPtLa
        token_accessor       wWpBsO3TqQEybFF0le2YmNGX
        token_duration       ∞
        token_renewable      false
        token_policies       ["root"]
        identity_policies    []
        policies             ["root"]
         
         

        2.2. KV 시크릿 엔진 활성화 및 샘플 구성 → Static Secret

        → Vault KV version 2 엔진을 활성화하고 샘플 데이터를 저장합니다. → Version1 : KV 버전관리 불가 / Version2 : KV 버전관리 가능

        Step 1. 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
        Step2. Vault UI : [Secrets Engine] 탭에 접속 후 [sampleapp - config] 접속하여 실제 저장된 Key / Value 확인
        • username : demo
        • password : p@ssw0rd
        image
        Step3. (참고) 경로 확인하는 명령 가이드
        image
        # get kv secret with CLI
        vault kv get -mount="secret" "sampleapp/config"
        
        ======== Secret Path ========
        secret/data/sampleapp/config
        
        ======= Metadata =======
        Key                Value
        ---                -----
        created_time       2025-04-12T05:28:41.258214793Z
        custom_metadata    <nil>
        deletion_time      n/a
        destroyed          false
        version            1
        
        ====== Data ======
        Key         Value
        ---         -----
        password    p@ssw0rd
        username    demo
         
        1. Vault Sidecar 연동(Vault agent) - 링크1 링크2
        • Vault Agent Sidecar 패턴을 이해하고, 앱(Pod)이 시크릿을 볼륨으로 마운트하여 사용하도록 구성한다.
        • Vault Agent Injector 구성을 위해 Helm Chart(Embed GitHubEmbed GitHub) 에서 활성화 해야하며, 을 활용한다.

         

        3.1. 공식문서 요약(ChatGPT)

        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에 접근할 수 있도록 적절한 PolicyRole이 설정되어야 합니다.
        • 예를 들어, 특정 서비스 어카운트가 특정 경로의 시크릿에만 접근할 수 있도록 제한할 수 있습니다.

        5. 애플리케이션 Pod에 주입할 주석(annotation)을 추가해야 합니다

        • Vault Agent Injector는 특정 주석이 있는 Pod에 대해서만 Vault Agent를 주입합니다.
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "example-role"

         

        3.2. Vault Kubernetes Sidecar 아키텍처 및 워크플로우

        이미지 출처: 이미지 출처:
        이미지 출처: 이미지 출처:
        Vault Agent 동작방식Vault Agent 동작방식
        Vault - Kubernetes 연동시 동작흐름(출처: Vault - Kubernetes 연동시 동작흐름(출처: )

         

        3.3. 실습

        Step1. Vault AppRole 방식 인증 구성 - AppRole 인증이란?
        • 인증 구성 및 정책 적용
        # 1. AppRole 인증 방식 활성화
        vault auth enable approle || echo "AppRole already enabled"
        
        vault auth list
        Path        Type       Accessor                 Description                Version
        ----        ----       --------                 -----------                -------
        approle/    approle    auth_approle_45429d98    n/a                        n/a
        token/      token      auth_token_0e40cfed      token based credentials    n/a
        
        # 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"
        
        ROLE_ID: b49cb2f2-ff99-7e31-2bb7-a3c63ce7cd5d
        SECRET_ID: 2b650c0b-d68a-6f5e-931b-dca81ae26684
        
        # 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 연동

        Vault Agent는 vault-agent-config.hcl 설정을 통해 연결할 Vault의 정보와, Template 구성, 렌더링 주기, 참조할 Vault KV 위치정보 등을 정의한다.

         
        1. Vault Agent 설정 파일 작성 및 생성 (vault-agent-config.hcl) - HCL
        2. 샘플 애플리케이션 + Sidecar 배포(수동방식)
        3. SVC 생성
        4. 생성된 컨테이너 확인
        5. 실제 배포된 화면 확인
        6. KV 값 변경 후 확인
        (참고) Annotation을 활용한 Vault Sidecar Injection - Docs
         

        3.4. 📖 추가 학습자료

        Vault Proxy는 애플리케이션이 Vault와 통합하는 초기 진입 장벽을 낮추고, 더 확장 가능하고 단순한 방식을 제공하기 위해 만들어졌습니다. Vault Proxy는 Vault의 API 프록시 역할을 하며, 클라이언트가 자동 인증된 토큰을 사용하도록 허용하거나 강제할 수 있습니다.

        Vault Proxy는 클라이언트 데몬으로 다음과 같은 기능을 제공합니다:

        • Auto-Auth: Vault에 자동으로 인증하고, 로컬에서 가져온 동적 비밀의 토큰 갱신 프로세스를 관리합니다.
        • API Proxy: Vault의 API에 대한 프록시 역할을 하며, Auto-Auth 토큰을 선택적으로 또는 강제로 사용하게 할 수 있습니다.
        • 캐싱(Caching): 새로 생성된 토큰이나 이 토큰으로부터 생성된 리스 비밀(leased secrets)에 대한 응답을 클라이언트 측에서 캐싱할 수 있도록 합니다. 또한, 에이전트는 캐시된 토큰과 리스의 갱신도 관리합니다.
        image
        image
        Capability
        Vault Agent
        Vault Proxy
        Auto-auth
        Caching
        Templating
        API proxy
        Will be deprecated
        Run as a Windows Service
         
         
        1. Jenkins + Vault(AppRole) - CI
          • Vault KV Store에 저장한 username, password을 Jenkins을 활용해서 획득하는 방안
          • CI 파이프라인에서 정적(Static) 시크릿을 외부에 저장하고 관리할 경우 사용할 수 있습니다.
         

        4.1. 🔐 CI/CD 보안 고려사항

        image

         

        4.2. Vault - Jenkins Plugin with AppRole 인증방식 워크플로우 - Docs

        image
        공식문서 요약(ChatGPT)

        젠킨스는 Vault에 시크릿으로 분류된 데이터를 필요로 하는 작업(job)을 실행해야 합니다. 젠킨스는 마스터 노드와 워커 노드를 가지고 있으며, 워커 노드는 짧은 시간 동안 실행되는 컨테이너 러너에서 작업을 실행합니다.

        • 프로세스는 다음과 같습니다:
          1. 젠킨스 워커가 Vault에 인증
          2. Vault는 토큰을 반환
          3. 워커는 이 토큰을 사용해 작업에 해당하는 역할의 Wrapped SecretID를 요청
          4. Vault는 Wrapped SecretID를 반환
          5. 워커는 작업 러너를 생성하고, Wrapped SecretID를 변수로 전달
          6. 러너 컨테이너는 Wrapped SecretID의 unwrap을 요청
          7. Vault는 SecretID를 반환
          8. 러너는 RoleID와 SecretID를 사용해 Vault에 인증
          9. Vault는 필요한 시크릿 정보를 읽을 수 있는 정책이 포함된 토큰을 반환
          10. 러너는 이 토큰을 사용해 Vault에서 시크릿을 가져옴

         

        4.3. 실습

        Step1. Jenkins에서 Vault Plugin 설치
          1. Jenkins UI 접속
          2. 상단 메뉴에서 Manage JenkinsPlugins
          3. Available 탭에서 Vault 검색
          4. HashiCorp Vault Plugin 설치 후 Jenkins 재시작
        image
        Step2. Vault AppRole 정보 확인 ⇒ Secret ID는 1시간 만료이므로, 그냥 다시 생성해서, 해당 값을 젠킨스에 설정하고 빌드 실습 하자.
        • Vault에서 발급된 ROLE_ID, SECRET_ID는 이전에 생성한 role_id.txt secret_id.txt 값을 참고하여 사용할 수 있습니다.
        # 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"
        (참고) Role ID, Secret ID 획득방안
        # Role ID
        vault read auth/approle/role/<role-name>/role-id
        
        # Secret ID
        vault write -f auth/approle/role/<role-name>/secret-id
        
        # 예시
        vault read auth/approle/role/sampleapp-role/role-id
        Key        Value
        ---        -----
        role_id    678c0c6e-57df-bb23-1427-f6318843a514
         
        Step3. Jenkins에서 Vault 설정 및 Credentials 추가
          1. Jenkins UI(admi/qwe123) → Manage JenkinsConfigure System
        image
        1. 스크롤 하단의 Vault Plugin Configuration 섹션으로 이동
          • Vault URL 입력 후 [Add] 버튼 클릭 : IP입력할것!
        image
          1. Vault Credential 다음 값 입력:
            • 종류: Vault AppRole Credential
            • Role ID & Secret ID 입력 → 생성해놓은 변수 또는 파일참고
            • ID는 기억하기 쉬운 이름으로 지정 (vault-approle-creds 등)
        image
        Step4. Jenkins Pipeline Job 생성
          1. Jenkins UI → New Item → Pipeline 선택
          2. jenkins-vault-kv 입력 후 생성
          3. Jenkinsfile 작성
        Jenkinsfile 예시
        pipeline {
          agent any
        
          environment {
            VAULT_ADDR = 'http://192.168.0.10:30000' // 실제 Vault 주소로 변경!!!
          }
        
          stages {
            stage('Read Vault Secret') {
              steps {
                withVault([
                  vaultSecrets: [
                    [
                      path: 'secret/sampleapp/config', // version2는 data path가 없음!!
                      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}"
                  }
                }
              }
            }
          }
        }
          • Jenkins 실행결과 → 보안상 취약하므로 마스킹처리됨. 우회방안은 있음(파일로 저장)
        image
        유의사항
          • KV Version1은 경로에 data을 넣고 Version2는 경로에 data을 넣지 않습니다! - 참고링크
            • Version 1 : secret/data/sampleapp/config
            • Version 2 : secret/sampleapp/config
          • sh 블록 vs script 블록
        상황
        사용 방식
        sh 블록
        $USERNAME, $PASSWORD
        script 블록
        ${env.USERNAME}, ${env.PASSWORD}
         
          1. ArgoCD + Vault Plugin (Kubernetes Auth/AppRole) - CD

        📖 Vault + ArgoCD Plugin 패턴 - 링크1 링크2

        ArgoCD Vault Plugin 소개
        • Argo CD에는 다양한 시크릿 관리 도구(HashiCorp Vault, IBM Cloud Secrets Manager, AWS Secrets Manager 등)플러그인을 통해 Kubernetes 리소스에 주입할 수 있도록 지원합니다.
        • 플러그인을 통해 Operator 또는 CRD(Custom Resource Definition)에 의존하지 않고 GitOps와 Argo CD로 시크릿 관리 문제를 해결할 수 있습니다.
        • 특히 Secret 뿐만 아니라, deployment, configMap 또는 기타 Kubernetes 리소스에도 사용할 수 있습니다.
         
        설치/구성관련 내용 요약(ChatGPT) - Docs

        Argo CD Vault Plugin의 공식 문서에서는 Argo CD에 플러그인을 설치하는 방법으로 네 가지를 제시하고 있습니다:

        1. argocd-cm ConfigMap을 통한 설치:
          • argocd-repo-server에 InitContainer를 추가하여 플러그인을 다운로드하고 설정합니다.
          • 또는 플러그인이 사전 설치된 커스텀 이미지를 생성하여 사용합니다.
        2. 사이드카 컨테이너를 통한 설치:
          • 사이드카 컨테이너를 추가하여 플러그인과 필요한 도구들을 포함시킵니다.
          • 또는 플러그인이 사전 설치된 커스텀 사이드카 이미지를 생성하여 사용합니다.

        이 중 사이드카 컨테이너를 활용한 방법은 Argo CD v2.4.0부터 도입된 최신 방식으로, 보안성과 유지보수 측면에서 권장됩니다.

         

        5.1. 실습

        Step 1. ArgoCD Vault Plugin을 위한 Credentials 활성화 - AppRole 인증
        • 이전 실습에서 획득한 Role_ID, Secret_ID활용
        echo "ROLE_ID: $ROLE_ID"
        echo "SECRET_ID: $SECRET_ID"
        
        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: b49cb2f2-ff99-7e31-2bb7-a3c63ce7cd5d #Role_ID
          AVP_SECRET_ID: 1114778c-014d-b61f-5afd-d137a1a48484 #Secret_ID
        EOF
        Step 2. ArgoCD Vault Plugin 설치 - Blog
        참고사항
        • ArgoCD Helm 설치시 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 .  
         
        k exec -it -n vault vault-0 -- sh
        
        # vault pod shell에 접속 후 root token으로 로그인
        vault login
        Token (will be hidden): <토큰입력>
            
        # 확인명령
        vault read auth/kubernetes/role/argocd
         
        Step 3. 샘플 Application 배포하여 Vault와 동기화
        • (참고) luafanti/spring-boot-debug-app:main 이미지는 amd64 CPU만 가능 (arm CPU는 기동 실패) - Link
        Step 3-1) Application.yaml 작성
        • GitHub에 저장된 Helm Repo을 배포하며, Helm 메니페스트 내에 변수로 치환된 값(username/password)을 CD 단계에서 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
        Step 3-2) Application 배포시 참조하는 new-values.yaml 확인 - GitHub
        serviceAccount:
          create: true
        
        image:
          repository: luafanti/spring-boot-debug-app
          tag: main
          pullPolicy: IfNotPresent
        
        replicaCount: 1
        
        resources:
          memoryRequest: 256Mi
          memoryLimit: 512Mi
          cpuRequest: 500m
          cpuLimit: 1
        
        probes:
          liveness:
            initialDelaySeconds: 15
            path: /actuator/health/liveness
            failureThreshold: 3
            successThreshold: 1
            timeoutSeconds: 3
            periodSeconds: 5
          readiness:
            initialDelaySeconds: 15
            path: /actuator/health/readiness
            failureThreshold: 3
            successThreshold: 1
            timeoutSeconds: 3
            periodSeconds: 5
        
        ports:
          http:
            name: http
            value: 8080
          management:
            name: management
            value: 8081
        
        envs:
          - name: VAULT_SECRET_USER
            value: <path:secret/data/sampleapp/config#username>
          - name: VAULT_SECRET_PASSWORD
            value: <path:secret/data/sampleapp/config#password>
        
        log:
          level:
            spring: "info"
            service: "info"
        Step 3-3) 실제 배포시 적용된 화면
          • ArgoCD Vault Plugin 적용된 화면 : [DETAILS] - [PARAMETERS]
        image
          • Application 배포화면
          • Deployment에 적용된 env 값 확인 :
        envs:
          - name: VAULT_SECRET_USER
            value: <path:secret/data/sampleapp/config#username>
          - name: VAULT_SECRET_PASSWORD
            value: <path:secret/data/sampleapp/config#password>
            
        # argocd application에서 deployment live manifest 정보
            spec:
              containers:
                - env:
                    - name: LOG_LEVEL_SERVICE
                      value: info
                    - name: LOG_LEVEL_SPRING
                      value: info
                    - name: JSON_LOGS_ENABLED
                      value: 'false'
                    - name: VAULT_SECRET_USER
                      value: demo-1
                    - name: VAULT_SECRET_PASSWORD
                      value: p@ssw0rd
        image
        image
        • ArgoCD App 삭제 kubectl delete applications demo
         
        (참고) Unknown 에러 발생시 redis 파드 재배포 후 필요
        • ArgoCD repo-server 재기동 → Redis 재기동 → Application 재생성
        image
        📖 추가 학습자료
        • Exploring GitOps with Argo CD and HashiCorp Vault in Kubernetes - Link1, Link2 👉 Vault Plugin 패턴은 아니지만 위와 같은 방법도 좋아보이네요

         

        6. Vault Secrets Operator

        6.1. VSO란? - Docs

        Vault Secrets Operator(VSO)는 Kubernetes Secrets에서 Vault secrets 및 HCP Vault Secrets Apps를 네이티브하게 사용할 수 있도록 Pods에 제공해줍니다.

        개요

        Vault Secrets Operator는 지원하는 Custom Resource Definitions(CRD) 집합의 변경 사항을 감시하여 작동합니다. 각 CRD는 시크릿의 지원되는 소스 중 하나에서 Kubernetes Secret으로 동기화할 수 있도록 필요한 사양을 제공합니다.

        오퍼레이터는 소스 시크릿 데이터를 대상 Kubernetes Secret에 직접 작성하며, 소스에 변경 사항이 발생할 경우 해당 내용을 대상에도 수명 주기 동안 지속적으로 반영합니다. 이렇게 함으로써 애플리케이션은 대상 시크릿에만 접근하면 그 안의 시크릿 데이터를 사용할 수 있습니다.

        기능

        Vault Secrets Operator가 지원하는 주요 기능은 다음과 같습니다:

        • 여러 시크릿 소스로부터의 동기화 지원
        • 자동 시크릿 일탈 감지 및 수정
        • Deployment, ReplicaSet, StatefulSet Kubernetes 리소스 유형에 대한 자동 시크릿 교체
        • 오퍼레이터 모니터링을 위한 Prometheus 전용 계측 지원
        • Helm 또는 Kustomize를 통한 설치 지원
        • 시크릿 데이터 변환 지원
        지원되는 Kubernetes 배포판

        Vault Secrets Operator는 다음과 같은 호스팅된 Kubernetes 환경에서 성공적으로 테스트되었습니다:

        • Amazon Elastic Kubernetes Service (EKS)
        • Google Kubernetes Engine (GKE)
        • Microsoft Azure Kubernetes Service (AKS)
        • Red Hat OpenShift (공식 인증됨)
        유사한 오픈소스 프로젝트는? - ESO(External Secrets Operator)
        image

         

        5.2. VSO 구성도 - 개발자(Developer) / 운영자(Operator)의 역할

        Vault Secrets Operator(출처: Vault Secrets Operator(출처: )
         

        5.3. VSO - Vault 매핑구조

        image
        image
         

        5.4. VSO 주요 CRD 정보 및 예시

        VSO CRD 관계도
        image
        image
        ---
        apiVersion: secrets.hashicorp.com/v1beta1
        kind: VaultConnection
        metadata:
          namespace: vso-example
          name: vault-connection
        spec:
          # required configuration
          # address to the Vault server.
          address: http://vault.vault.svc.cluster.local:8200
        ---
        apiVersion: secrets.hashicorp.com/v1beta1
        kind: VaultAuth
        metadata:
          namespace: vso-example
          name: vault-auth
        spec:
          # required configuration
          # VaultConnectionRef of the corresponding VaultConnection CustomResource.
          # If no value is specified the Operator will default to the `default` VaultConnection,
          # configured in its own Kubernetes namespace.
          vaultConnectionRef: vault-connection
          # Method to use when authenticating to Vault.
          method: kubernetes
          # Mount to use when authenticating to auth method.
          mount: kubernetes
          # Kubernetes specific auth configuration, requires that the Method be set to kubernetes.
          kubernetes:
            # role to use when authenticating to Vault
            role: example
            # ServiceAccount to use when authenticating to Vault
            # it is recommended to always provide a unique serviceAccount per Pod/application
            serviceAccount: default
        ---
        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
        
        # KV Version 1
        ---
        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 Version 2
        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
        
        # 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
        ---
        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

         

        5.5. VSO Static Secrets

        • 운영자가 단일 Vault 정적 시크릿을 단일 Kubernetes 시크릿으로 동기화하는 데 필요한 구성입니다.
        • 지원되는 시크릿 엔진: kv-v2, kv-v1
        워크플로우 및 아키텍처
        image

         

        5.6. VSO Dynamic Secrets

          • Vault의 Dynamic Secret Engine을 활용하여 동적으로 변경되는 Secrets을 K8s Secrets에 동기화
          • 지원되는 시크릿 엔진: DB Credentials, Cloud Credentials(AWS, Azure, GCP 등)
           

          5.6.1. 시나리오

              1. Spring(Web Application) → DB 접근하기 위해서는 DB Credentials을 K8s Secrets으로 참조해야함
              2. 대상 DB에 접근하기 위한 DB Credentials을 Vault의 Dynamic Secrets 기능을 활용하여 주기적으로 변경하고 VSO을 통해 K8s Secets에 갱신(업데이트)
              3. Spring(Web Application)에서는 갱신된 DB Credentials 정보를 K8s Secret을 통해서 읽어오기 위해 재기동(rolloutRestartTargets 설정)
          image

           

          실습
          Step1. 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"]
          
          Values 구성요소 분석
          • defaultVaultConnection: 기본 Vault 연결 설정을 구성
            • address: vault.vault.svc.cluster.local:8200 (Helm으로 설치된 Vault의 ClusterIP)
            • skipTLSVerify: false: TLS 검증 비활성화 안 함 (Vault에 TLS 적용된 경우 주의 필요)
          • clientCache 설정
            • persistenceModel: direct-encrypted: 암호화된 데이터를 직접 저장
            • storageEncryption.enabled: true: 암호화 기능 활성화
            • transitMount: demo-transit: 앞에서 Vault에 만든 Transit 엔진 mount path
            • keyName: vso-client-cache: Transit에서 사용하는 암호화 키
            • mount: k8s-auth-mount: Kubernetes 인증 방식에서 사용할 auth path
            • kubernetes.role: auth-role-operator 라는 Role에 지정된 정책으로 암복호화 가능
            • serviceAccount: VSO가 사용하는 ServiceAccount 이름
            • tokenAudiences: Vault 서버에서 사용하는 audience 설정
          • 위와 같은 설정으로 VSO는 Vault에 인증된 후, 동적/정적 시크릿을 Kubernetes 리소스로 가져오고, 가져온 시크릿 데이터를 자체적으로 암호화해 캐시 가능
          Step2. VSO 배포
          helm install vault-secrets-operator hashicorp/vault-secrets-operator \
            -n vault-secrets-operator-system \
            --create-namespace \
            --values vault-operator-values.yaml
            
          #
          kubectl get-all -n vault-secrets-operator-system
          
          #
          kubectl get pod -n vault-secrets-operator-system      
          NAME                                                         READY   STATUS    RESTARTS   AGE
          vault-secrets-operator-controller-manager-7f67cd89fd-ds5jc   2/2     Running   0          11m
          
          kubectl describe pod -n vault-secrets-operator-system                                       
          ...
          Service Account:  vault-secrets-operator-controller-manager
          ...
          Containers:
            kube-rbac-proxy:
              Container ID:  containerd://db3eae7b836fb4f1b4236c494c8fa96ada94769a6c602e1a150c75293a6a4162
              Image:         quay.io/brancz/kube-rbac-proxy:v0.18.1
            ...
            manager:
              Container ID:  containerd://1ab1545fb4bd86ac52d6c7609a3e962cd2d1a81daa9bbd9c82f79d9a0d8b6466
              Image:         hashicorp/vault-secrets-operator:0.10.0
          ...
          
          #
          kubectl rbac-tool lookup vault-secrets-operator-controller-manager
            SUBJECT                                   | SUBJECT TYPE   | SCOPE       | NAMESPACE                     | ROLE                                        | BINDING                                             
          --------------------------------------------+----------------+-------------+-------------------------------+---------------------------------------------+-----------------------------------------------------
            vault-secrets-operator-controller-manager | ServiceAccount | ClusterRole |                               | vault-secrets-operator-proxy-role           | vault-secrets-operator-proxy-rolebinding            
            vault-secrets-operator-controller-manager | ServiceAccount | ClusterRole |                               | vault-secrets-operator-manager-role         | vault-secrets-operator-manager-rolebinding          
            vault-secrets-operator-controller-manager | ServiceAccount | Role        | vault-secrets-operator-system | vault-secrets-operator-leader-election-role | vault-secrets-operator-leader-election-rolebinding  
          
          #
          kubectl rolesum vault-secrets-operator-controller-manager -n vault-secrets-operator-system
          ServiceAccount: vault-secrets-operator-system/vault-secrets-operator-controller-manager
          Secrets:
          
          Policies:
          • [RB] vault-secrets-operator-system/vault-secrets-operator-leader-election-rolebinding ⟶  [R] vault-secrets-operator-system/vault-secrets-operator-leader-election-role
            Resource                    Name  Exclude  Verbs  G L W C U P D DC  
            configmaps                  [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            events                      [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✔ ✖ ✖   
            leases.coordination.k8s.io  [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
          
          
          • [CRB] */vault-secrets-operator-manager-rolebinding ⟶  [CR] */vault-secrets-operator-manager-role
            Resource                                                Name  Exclude  Verbs  G L W C U P D DC  
            configmaps                                              [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖   
            daemonsets.apps                                         [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✔ ✖ ✖   
            deployments.apps                                        [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✔ ✖ ✖   
            events                                                  [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✔ ✖ ✖   
            hcpauths.secrets.hashicorp.com                          [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            hcpauths.secrets.hashicorp.com/finalizers               [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            hcpauths.secrets.hashicorp.com/status                   [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            hcpvaultsecretsapps.secrets.hashicorp.com               [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            hcpvaultsecretsapps.secrets.hashicorp.com/finalizers    [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            hcpvaultsecretsapps.secrets.hashicorp.com/status        [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            rollouts.argoproj.io                                    [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✔ ✖ ✖   
            secrets                                                 [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔   
            secrettransformations.secrets.hashicorp.com             [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            secrettransformations.secrets.hashicorp.com/finalizers  [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            secrettransformations.secrets.hashicorp.com/status      [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            serviceaccounts                                         [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖   
            serviceaccounts/token                                   [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✖ ✖ ✖ ✖   
            statefulsets.apps                                       [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✔ ✖ ✖   
            vaultauthglobals.secrets.hashicorp.com                  [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultauthglobals.secrets.hashicorp.com/finalizers       [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultauthglobals.secrets.hashicorp.com/status           [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            vaultauths.secrets.hashicorp.com                        [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultauths.secrets.hashicorp.com/finalizers             [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultauths.secrets.hashicorp.com/status                 [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            vaultconnections.secrets.hashicorp.com                  [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultconnections.secrets.hashicorp.com/finalizers       [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultconnections.secrets.hashicorp.com/status           [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            vaultdynamicsecrets.secrets.hashicorp.com               [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultdynamicsecrets.secrets.hashicorp.com/finalizers    [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultdynamicsecrets.secrets.hashicorp.com/status        [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            vaultpkisecrets.secrets.hashicorp.com                   [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultpkisecrets.secrets.hashicorp.com/finalizers        [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultpkisecrets.secrets.hashicorp.com/status            [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
            vaultstaticsecrets.secrets.hashicorp.com                [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖   
            vaultstaticsecrets.secrets.hashicorp.com/finalizers     [*]     [-]     [-]   ✖ ✖ ✖ ✖ ✔ ✖ ✖ ✖   
            vaultstaticsecrets.secrets.hashicorp.com/status         [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✔ ✔ ✖ ✖   
          
          
          • [CRB] */vault-secrets-operator-proxy-rolebinding ⟶  [CR] */vault-secrets-operator-proxy-role
            Resource                                   Name  Exclude  Verbs  G L W C U P D DC  
            subjectaccessreviews.authorization.k8s.io  [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖   
            tokenreviews.authentication.k8s.io         [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖   
          
          #
          kubectl get vaultauth -n vault-secrets-operator-system vault-secrets-operator-default-transit-auth -o jsonpath='{.spec}' | jq
          {
            "kubernetes": {
              "audiences": [
                "vault"
              ],
              "role": "auth-role-operator",
              "serviceAccount": "vault-secrets-operator-controller-manager",
              "tokenExpirationSeconds": 600
            },
            "method": "kubernetes",
            "mount": "k8s-auth-mount",
            "storageEncryption": {
              "keyName": "vso-client-cache",
              "mount": "demo-transit"
            },
            "vaultConnectionRef": "default"
          }
          
          kubectl get vaultconnection -n vault-secrets-operator-system default -o jsonpath='{.spec}' | jq
          {
            "address": "http://vault.vault.svc.cluster.local:8200",
            "skipTLSVerify": false
          }
          
          Step3. PostgreSQL 설치 (Bitnami Helm Chart)
          kubectl create ns postgres
          
          helm repo add bitnami https://charts.bitnami.com/bitnami
          
          helm upgrade --install postgres bitnami/postgresql \
            --namespace postgres \
            --set auth.audit.logConnections=true \
            --set auth.postgresPassword=secret-pass
            
          # psql 로그인 확인
          kubectl exec -it -n postgres postgres-postgresql-0 -- sh -c 'PGPASSWORD=secret-pass psql -U postgres -h localhost'
          kubectl exec -it -n postgres postgres-postgresql-0 -- sh -c "PGPASSWORD=secret-pass psql -U postgres -h localhost -c '\l'"
          
          Step4. Kubernetes Auth Method 설정
          #
          kubectl exec -it vault-0 -n vault -- cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          -----BEGIN CERTIFICATE-----
          MIIDBTCCAe2gAwIBAgIIfA5oV86RmOswDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
          AxMKa3ViZXJuZXRlczAeFw0yNTA0MTAwMDUzMTdaFw0zNTA0MDgwMDU4MTdaMBUx
          EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
          AoIBAQDSUCHyBXVhBb91uZKdqwFAussfSxqPadYhrj659fp/XuJQrRrOMLZAh5eP
          6MCkeYbHeMY2stwBzuwzSzyaxkJdKiR5yKhtIHT7vpYn4XT0bNdyWWKAHkjyqjsk
          DYkAbwQ1xksL3DwArRfUSdZPCVsDLhu+G3wbGKiW64q0Rb1pEk/gK2AhxnSSqoeR
          YNzh10FA/CxS2wiLFfsm8NAn4KHG134AKY0Vxb/EkXnL9b2jRK+BfSh/sSpuEzN3
          16Xy1fC5UX/xCdTvwx+57xOoFhymaF0aVISSavzrkaYd8kaPwAKtoAlxvDmDrVhv
          YKRfCTerHUCOL3IPQqChIZQIUvoVAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
          BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSDK0FYEL+FNdgIpMhCnj9g2CkAIjAV
          BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQC5/EdWTRD6
          SoghjPe/bKKfQzFxPmEZVTb0JI0CWVUZorGzFcHCMCXMOf/XuECkK5tqn7QR/Nw8
          yy3XvmT6DY+J2GshrusJXfMEOJ9RQIwDBJKHoZqbcyI/w294Ecp1Mpivb8WeI2FW
          wMsaDoswQ3H/0zrEBwhhpUAWcmjm6w4/7Tsid9t1DsQrp9xH37wU/uP07HyEIKPS
          TCQ2tUueHSVihNhCg7RejjbiGy8EUZV6aGIrtFgss9Mzk+5m+1KXm8o+Lj/YNYFx
          JFeII2h3ZptO4I9vHrohXKVw0esHNzdHQPeGEXCWHTd+K38jIJPfggA8Yu1htbUa
          MKEIbcT53UHH
          -----END CERTIFICATE-----
          
          # 해당 ca.crt 는 k8s 의 루트인증서 정보
          kubectl exec -it vault-0 -n vault -- cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt > vso-ca.crt
          openssl x509 -in vso-ca.crt -noout -text
          Certificate:
              Data:
                  Version: 3 (0x2)
                  Serial Number: 5268734382662717808 (0x491e4e018e7f9170)
                  Signature Algorithm: sha256WithRSAEncryption
                  Issuer: CN=kubernetes
          ...
          
          # vault 서비스 어카운트의 token 확인
          kubectl exec -it vault-0 -n vault -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
          eyJhbGciOiJSUzI1NiIsImtpZCI6IlhQM2UxWmlFX2tqWEVzN3FqMXhscHJ1VFB2cVRUcDd0czliZTlsNlF4SWcifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzc1OTgyNTM5LCJpYXQiOjE3NDQ0NDY1MzksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiNDU3NzE3ODMtOTE3YS00OTQyLWFmYTAtMWY1ZmFlN2YxOWVkIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJ2YXVsdCIsIm5vZGUiOnsibmFtZSI6Im15azhzLXdvcmtlcjIiLCJ1aWQiOiI0YjQ0ZDgyMS1hM2UzLTQ4NzQtOTFhYi01MDQ2NjYxNjdkMjAifSwicG9kIjp7Im5hbWUiOiJ2YXVsdC0wIiwidWlkIjoiMjYyZTJlNGQtMjAxYy00YWU3LWEyZDktZTZiMDdmMDNmM2Y1In0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJ2YXVsdCIsInVpZCI6ImQ5MGYzMWI3LTIwYjYtNGNiNy04NjFlLWI4MDhhYjg5YWY2MyJ9LCJ3YXJuYWZ0ZXIiOjE3NDQ0NTAxNDZ9LCJuYmYiOjE3NDQ0NDY1MzksInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDp2YXVsdDp2YXVsdCJ9.tSEOCNGIge6tVmoNotiRnu2A77Bu76udz3uxYNEEMqjwM0aa4UnTaPrjFj_QCFKZ67Ebwwmy32AFAWKxTrf4w-un05k_Lz6huUMi7HtzoKQVwVlt6polMfAytu77ZbQ9PBMtTG7m_BR8Vc-KX7Y4CTT3cTUAbgp3M5uEsK07KQ9Pp0PIyO88ZW8eR50NihlAgNZdPVe7xSIaazJorE8z0QZ7amXi71RYc-qthStgiMXS8nLGGdkd6NzywNuDGOvAtD-6krNT9WS1qWMnmw_oDHY0gGEEMFuLIkkjJDVYsNJmWOJo-5WzD_XXPhz808msKrBgivpyWt842oGyC_rL5w
          
          # https://jwt.io/ 에서 token 디코드 확인 시 PAYLOAD 부분
          {
            "aud": [
              "https://kubernetes.default.svc.cluster.local"
            ],
            "exp": 1775982539,
            "iat": 1744446539,
            "iss": "https://kubernetes.default.svc.cluster.local",
            "jti": "45771783-917a-4942-afa0-1f5fae7f19ed",
            "kubernetes.io": {
              "namespace": "vault",
              "node": {
                "name": "myk8s-worker2",
                "uid": "4b44d821-a3e3-4874-91ab-504666167d20"
              },
              "pod": {
                "name": "vault-0",
                "uid": "262e2e4d-201c-4ae7-a2d9-e6b07f03f3f5"
              },
              "serviceaccount": {
                "name": "vault",
                "uid": "d90f31b7-20b6-4cb7-861e-b808ab89af63"
              },
              "warnafter": 1744450146
            },
            "nbf": 1744446539,
            "sub": "system:serviceaccount:vault:vault"
          }
          
          # vault SA 토큰 만료 기간 : 대략 1시간(3600초)+7초
          k get pod -n vault vault-0 -o yaml
          ...
           - name: kube-api-access-9rqgv
              projected:
                defaultMode: 420
                sources:
                - serviceAccountToken:
                    expirationSeconds: 3607
                    path: token
                - configMap:
                    items:
                    - key: ca.crt
                      path: ca.crt
                    name: kube-root-ca.crt
          
          
          
          kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh
          ----------------------------------------------------------------
          # 최초 설치시 획득한 vault root token 사용. 
          # 예시) hvs.hnlFKWjE10FOyrwLMeK9PrCC
          vault login
          
          # Kubernetes 인증 메서드 활성화
          vault auth enable -path k8s-auth-mount kubernetes
          
          #
          vault auth list
          Path               Type          Accessor                    Description                Version
          ----               ----          --------                    -----------                -------
          approle/           approle       auth_approle_45429d98       n/a                        n/a
          k8s-auth-mount/    kubernetes    auth_kubernetes_b6937d5c    n/a                        n/a
          token/             token         auth_token_0e40cfed         token based credentials    n/a
          
          
          # 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 read auth/k8s-auth-mount/config
          Key                                  Value
          ---                                  -----
          disable_iss_validation               true
          disable_local_ca_jwt                 false
          issuer                               n/a
          kubernetes_ca_cert                   -----BEGIN CERTIFICATE-----
          MIIDBTCCAe2gAwIBAgIISR5OAY5/kXAwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
          AxMKa3ViZXJuZXRlczAeFw0yNTA0MTIwNDM4MTBaFw0zNTA0MTAwNDQzMTBaMBUx
          EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
          AoIBAQC1OHyP0oqdQ+aTC7WMaCx7BfWN8/elTzEq3PeFAwP8GdliFVJnCXHF7kfk
          91YDTUZDsTO0Sg1Wg2N5B0KI9Bn2fzni5SK+WpCmtDHomeg3ejDRKxZlR6NN3yHe
          2b8SBsks8iqOa4x1RQkYLekW0V4Rb39hdtddSAdwinIcRGZZ2npGTsxOFcBx1H1J
          Z1bP5XzBB3oT72FXvD0YVPLpovuSYM1gUhfNDp/ciiCmRqugwkz1e+BJy8PSvwPh
          UedHX1mXoQJE7f9b7JE0MOd0JqOnMVh6SgyP9Np2i51TB/kw4qS6RwQql2WTUyBw
          /UNCp+M1icctg+KdhpIr61eu6hdlAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
          BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRGCrk8aIWMI0GhAjekQN28AZZNSzAV
          BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQBSKsX17U7M
          Tcle6jcpAD+10Tyan3gwuQRYEDx8PxI2cDcsnJKahRI3j94bRGQM0KgIabc9ngGp
          oZv8i0UICoZJzikP8Mo8f2J0iiCR3G+yicVeHxC5Imdfdpuki8iHvncT8knoD36x
          njpWF8BIIn5TwYkwZ8V9OA1vbRCjS/wo8K31MlSdUq0L6YIjkJB8Ng4no4lIhLgT
          asY8eMWr7WNF/uv1LPAonCix6zJn3uYOz8r0mf+6Le4JVS8RR4guXs+19Nk94ZuC
          758ubiAYE77tCtPYIxje5YDnsLyuigQ1t+8eIHTDYAF4J/s0/lKzVK9arpqYqUER
          mivt2SPk260L
          -----END CERTIFICATE-----
          kubernetes_host                      https://kubernetes.default.svc:443
          pem_keys                             []
          token_reviewer_jwt_set               true
          use_annotations_as_alias_metadata    false
          
          ----------------------------------------------------------------
          vault write 명령 분석
          • Vault가 K8s API 서버에 인증 요청을 보낼 수 있도록 설정
            • kubernetes_host: API 서버 주소
            • kubernetes_ca_cert: API 서버의 CA 인증서 (Pod 내 ServiceAccount에서 자동 주입됨)
            • token_reviewer_jwt: TokenReviewer 권한이 있는 토큰으로 Vault가 요청자의 토큰을 검증할 수 있도록 설정
          Step5. Vault Kubernetes Auth Role 설정

          실행 중인 애플리케이션이 Vault로부터 DB 자격증명(동적 사용자)을 받아올 수 있도록 권한을 연결을 위한 설정

          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
          # auth-role 생성
          vault write auth/k8s-auth-mount/role/auth-role \
             bound_service_account_names=demo-dynamic-app \ # demo-dynamic-app 서비스 어카운트를 사용하는 Pod에서만 인증 허용, Pod 내부에서 Vault에 로그인하려면 이 서비스 어카운트를 써야 함
             bound_service_account_namespaces=demo-ns \ # 이 Role은 오직 demo-ns 네임스페이스에서 오는 요청만 허용
             token_ttl=0 \ # 발급되는 Vault 토큰의 기본 TTL 없음(0). 일반적으로 token_ttl=0이면 token_period가 사용됨
             token_period=120 \ # Lease 기간이 120초인 Renewable Token 발급. TTL이 없는 대신, 2분마다 갱신 가능한 토큰을 생성. 보통 이 설정은 "periodic token"이라 불리며, long-lived session에 적합.
             token_policies=demo-auth-policy-db \ # 인증에 성공하면 발급되는 토큰에 demo-auth-policy-db 정책이 적용
             audience=vault # JWT 토큰의 aud (Audience) claim 검증에 사용.
           
          Step6. Vault Database Secret Engine 설정
          # demo-db라는 경로로 Database Secret Engine을 활성화
          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분)
          ## creation_statements=... : Vault가 계정을 자동 생성할 때 실행할 SQL 문. {{name}}, {{password}}, {{expiration}}은 Vault가 자동으로 채워줌.
          ## revocation_statements=... : Vault가 동적 사용자 계정을 폐기(revoke)할 때 실행할 SQL 문. 권한을 모두 회수.
          ## default_ttl="1m" / max_ttl="1m" : 기본 1분만 유효합니다. 갱신을 안 하면 1분 후 자동 만료 (계정도 자동 삭제). 최대 TTL도 1분이므로 연장도 최대 1분까지만.
          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"
          
          # 정책 설정: DB 자격증명 읽기 권한
          # 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
          
          Step7. Transit Secret Engine 설정 + VSO 연동 Role 구성 - Docs , Client-cache
          kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh
          ----------------------------------------------------------------
          # Transit Secret Engine 활성화
          # transit 엔진을 demo-transit 경로로 활성화.
          # 데이터를 저장하지 않고 암복호화 기능만 제공하는 Vault의 기능
          # 클라이언트 캐시는 리더십 변경 시에도 Vault 토큰 및 동적 비밀 임대를 계속 추적하고 갱신할 수 있으므로 원활한 업그레이드를 지원합니다
          ## Vault 서버에 클라이언트 캐시를 저장하고 암호화할 수 있습니다.
          ## Vault Dynamic Secret을 사용하는 경우 클라이언트 캐시를 영구적으로 저장하고 암호화하는 것이 좋습니다.
          ## 이렇게 하면 재시작 및 업그레이드를 통해 Dynamic Secret 임대가 유지됩니다.
          vault secrets enable -path=demo-transit transit
          vault secrets list -detailed
          
          # 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
          
           
          Step8. 샘플 애플리케이션 YAML 작성 및 배포
          demo-ns 네임스페이스 생성
          kubectl create ns demo-ns
          mkdir vso-dynamic
          cd vso-dynamic
          vault-auth-dynamic.yaml :
          • 앱이 Vault에 인증하기 위한 ServiceAccount 및 VaultAuth 리소스
          • Vault에서 발급한 동적 PostgreSQL 크레덴셜을 얻기 위해 반드시 필요
          ---
          # 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
          app-secret.yaml :
          • Spring App에서 PostgreSQL에 접속할 때 사용할 해당 시크릿에 username/password을 동적으로 생성
          ---
          # app-secret.yaml
          apiVersion: v1
          kind: Secret
          metadata:
            name: vso-db-demo
            namespace: demo-ns
          vault-dynamic-secret.yaml
          • Vault에서 동적으로 PostgreSQL 접속정보 생성하고 K8s Secret에 저장
          • 생성된 Secret(vso-db-demo)은 앱에서 환경 변수(env)로 사용
          • 애플리케이션에서 Dynamic Reloading을 지원하지 않을 경우 rolloutRestartTargets 을 사용하여 애플리케이션을 재배포하여 새로 업데이트된 시크릿을 사용하도록 할 수 있음
          • refreshAfter 설정을 통해 VSO가 소스 시크릿 데이터를 동기화 하는 주기 설정가능 - Docs → Event Notification 기능을 통해 변경이 있을 경우 즉시 반영할 수도 있음 - Docs
          ---
          # 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-spring-deploy.yaml :
          • DB 접속 테스트를 위한 Spring App →
          ---
          # 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
          • 애플리케이션 배포 : kubectl apply -f .
          Step9. 동작확인(UI) : postgres-postgresql.postgres.svc , db는 postgres
          • localhost:30003 접속 후 K8s Secrets에 생성된 username, password 값으로 연결 테스트
          image
           
          Step10. 동작확인(CLI)
          # 스크릿이 변경되고, 적용을 위해서 파드가 42~45초 사이로 재생성됨
          while true; do kubectl get pod -n demo-ns ; echo; kubectl view-secret -n demo-ns vso-db-demo --all; date; sleep 30 ; echo ; done 
          ...
          NAME                         READY   STATUS    RESTARTS   AGE
          vaultdemo-559494db6f-jw568   1/1     Running   0          42s
          
          _raw='{"password":"fv6wQbr7O-VpbVHAt2nO","username":"v-k8s-auth-dev-post-BfAGdVGRKRuriTjwnzVm-1744451233"}'
          password='fv6wQbr7O-VpbVHAt2nO'
          username='v-k8s-auth-dev-post-BfAGdVGRKRuriTjwnzVm-1744451233'
          Sat Apr 12 18:47:55 KST 2025
          
          NAME                         READY   STATUS    RESTARTS   AGE
          vaultdemo-559494db6f-jw568   1/1     Running   0          43s
          
          _raw='{"password":"fv6wQbr7O-VpbVHAt2nO","username":"v-k8s-auth-dev-post-BfAGdVGRKRuriTjwnzVm-1744451233"}'
          password='fv6wQbr7O-VpbVHAt2nO'
          username='v-k8s-auth-dev-post-BfAGdVGRKRuriTjwnzVm-1744451233'
          Sat Apr 12 18:47:56 KST 2025
          
          NAME                         READY   STATUS              RESTARTS   AGE
          vaultdemo-559494db6f-jw568   1/1     Running             0          45s
          vaultdemo-65f9fc7c7-vjrcg    0/1     ContainerCreating   0          1s
          
          _raw='{"password":"z--6WK-9OsWHxtEyxjl3","username":"v-k8s-auth-dev-post-jMSezyOc1CxcNag59yky-1744451277"}'
          password='z--6WK-9OsWHxtEyxjl3'
          username='v-k8s-auth-dev-post-jMSezyOc1CxcNag59yky-1744451277'
          Sat Apr 12 18:47:58 KST 2025
          ...
          
          # 만약 위의 secret이 변경되고 적용을 위해서 pod가 재생성되는 주기를 길게 하고 싶다면,
          # DB 사용자 동적 생성 Role에서 ttl을 아래와 같이 수정하면 된다.
          # 해당 Role 사용 시 Vault가 동적으로 사용자 계정과 비밀번호를 생성 하고 TTL마다 자동적으로 갱신하기 떄문에!!
          # TTL은 생성된 자격증명의 유효 시간 (30초~10분)
          ## 아래와 같이 수정하면
          ## default_ttl="1m" / max_ttl="5m" : 기본 1분만 유효합니다. 갱신을 안 하면 5분 후 자동 만료 (계정도 자동 삭제).
          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="5m"
          
          # 아래 동작처럼 최대 4분 30초 정도까지 같은 secret을 사용한다.
          while true; do kubectl get pod -n demo-ns ; echo; kubectl view-secret -n demo-ns vso-db-demo --all; date; sleep 1 ; echo ; done 
          
          NAME                        READY   STATUS    RESTARTS   AGE
          vaultdemo-f7c5d6b7d-rwvqp   1/1     Running   0          4m21s
          
          _raw='{"password":"uZwegj2lw-HsIsyE-TeQ","username":"v-k8s-auth-dev-post-coEagFro4iP9WSJNp4Ek-1744450286"}'
          password='uZwegj2lw-HsIsyE-TeQ'
          username='v-k8s-auth-dev-post-coEagFro4iP9WSJNp4Ek-1744450286'
          Sat Apr 12 18:35:47 KST 2025
          
          NAME                        READY   STATUS    RESTARTS   AGE
          vaultdemo-f7c5d6b7d-rwvqp   1/1     Running   0          4m22s
          
          _raw='{"password":"uZwegj2lw-HsIsyE-TeQ","username":"v-k8s-auth-dev-post-coEagFro4iP9WSJNp4Ek-1744450286"}'
          password='uZwegj2lw-HsIsyE-TeQ'
          username='v-k8s-auth-dev-post-coEagFro4iP9WSJNp4Ek-1744450286'
          Sat Apr 12 18:35:48 KST 2025
          
          NAME                         READY   STATUS              RESTARTS   AGE
          vaultdemo-6bff8f9b74-7x5qf   0/1     ContainerCreating   0          1s
          vaultdemo-f7c5d6b7d-rwvqp    1/1     Running             0          4m23s
          ...
          
          # 실제 postgresql 에 사용자 정보 확인 : 계속 추가되고 있음..
          kubectl exec -it -n postgres postgres-postgresql-0 -- sh -c "PGPASSWORD=secret-pass psql -U postgres -h localhost -c '\du'"
                                                            List of roles
                                Role name                      |                         Attributes                         
          -----------------------------------------------------+------------------------------------------------------------
           postgres                                            | Superuser, Create role, Create DB, Replication, Bypass RLS
           v-k8s-auth-dev-post-1kQf61zXMEn84Z1Bf8DX-1744449161 | Password valid until 2025-04-12 09:13:46+00
           v-k8s-auth-dev-post-1qw3jyZIEwUzpsY1gNCP-1744449116 | Password valid until 2025-04-12 09:13:01+00
           v-k8s-auth-dev-post-22iqnzn5QfoIB2Yybc6h-1744449290 | Password valid until 2025-04-12 09:15:55+00
           v-k8s-auth-dev-post-26Ospg823o9u8pMGnkWE-1744449895 | Password valid until 2025-04-12 09:26:00+00
           v-k8s-auth-dev-post-5l8roWsv9OFMl7aqNyuC-1744449072 | Password valid until 2025-04-12 09:12:17+00
           v-k8s-auth-dev-post-6iEacSDeIhKS3C4EeRlr-1744449853 | Password valid until 2025-04-12 09:25:18+00
           v-k8s-auth-dev-post-7rpNbjzsp9MucFjrJ7nI-1744449461 | Password valid until 2025-04-12 09:18:46+00
           v-k8s-auth-dev-post-9YeTsR3jWICkc9v9Vl9l-1744449591 | Password valid until 2025-04-12 09:20:56+00
           v-k8s-auth-dev-post-9ohPXw3YZlnkgpj827xH-1744450201 | Password valid until 2025-04-12 09:31:06+00
           v-k8s-auth-dev-post-AcPWt7isKrKfXNFpaHvm-1744449376 | Password valid until 2025-04-12 09:17:21+00
           v-k8s-auth-dev-post-BDdUDrT95AGy2BFfKWkW-1744449940 | Password valid until 2025-04-12 09:26:45+00
           v-k8s-auth-dev-post-DkJAhqwOTJGNj8JJjcAO-1744449028 | Password valid until 2025-04-12 09:11:33+00
           v-k8s-auth-dev-post-Dz4sZshOxk7ZVAHDhVw4-1744450548 | Password valid until 2025-04-12 09:40:53+00
           v-k8s-auth-dev-post-EyTNBS9mEojaBnB0FIXf-1744450242 | Password valid until 2025-04-12 09:31:47+00
           v-k8s-auth-dev-post-F2Wf5eQygtSRIdwFLCBA-1744449546 | Password valid until 2025-04-12 09:20:11+00
          ...
          
          
          # 로그 확인
          kubectl stern -n demo-ns -l app=vaultdemo
          ...
          
          kubectl stern -n vault vault-0
          ...
          vault-0 vault 2025-04-10T08:32:09.484Z [INFO]  expiration: revoked lease: lease_id=demo-db/creds/dev-postgres/Ph1sg8efnqssOU5FVIuAqhMW
          vault-0 vault 2025-04-10T08:32:54.229Z [INFO]  expiration: revoked lease: lease_id=demo-db/creds/dev-postgres/XKkHZ65ZYLeILvo8GqWfE7F3
          vault-0 vault 2025-04-10T08:33:36.804Z [INFO]  expiration: revoked lease: lease_id=demo-db/creds/dev-postgres/rk1KUFsV7SjZPNFsCqCHGZVx
          ...
          
          
          # vault-secrets-operator 가 clientCachePersistenceModel 설정 적용 정보 확인 : 참고로 해당 파드가 재시작되지는 않음.
          kubectl stern -n vault-secrets-operator-system -l app.kubernetes.io/name=vault-secrets-operator
          ...
          vault-secrets-operator-controller-manager-7f67cd89fd-ds5jc manager {"level":"info","ts":"2025-04-12T08:25:16Z","logger":"initCachingClientFactory","msg":"Initializing the CachingClientFactory"}
          vault-secrets-operator-controller-manager-7f67cd89fd-ds5jc manager {"level":"info","ts":"2025-04-12T08:25:16Z","logger":"setup","msg":"Starting manager","gitVersion":"0.10.0","gitCommit":"aebf0c1c59485059a9ea6c58340fd406afe4cbef","gitTreeState":"clean","buildDate":"2025-03-04T22:22:24+0000","goVersion":"go1.23.6","platform":"linux/arm64","clientCachePersistenceModel":"direct-encrypted","clientCacheSize":10000,"backoffMultiplier":1.5,"backoffMaxInterval":60,"backoffMaxElapsedTime":0,"backoffInitialInterval":5,"backoffRandomizationFactor":0.5,"globalTransformationOptions":"","globalVaultAuthOptions":"allow-default-globals"}
          ...
          vault-secrets-operator-controller-manager-7f67cd89fd-ds5jc manager {"level":"info","ts":"2025-04-12T09:10:28Z","logger":"lifetimeWatcher","msg":"Starting","id":"b65f02ff-d629-46f9-a86f-081a27fdc2c2","entityID":"80d85315-6023-0e81-a1af-7aa053a1ca44","clientID":"fcbea1e09f9cc64124845f2c898a39a3f6ec30619ede674dc01610ef1395cb05","cacheKey":"kubernetes-996f6ebc5943cecdc4a118"}...
          
          # 암호화된 캐시 저장소 확인 : vso-cc-<auth method>
          kubectl get secret -n vault-secrets-operator-system -l app.kubernetes.io/component=client-cache-storage 
          NAME                                       TYPE     DATA   AGE
          vso-cc-kubernetes-5aca8a85319d25f2b20f24   Opaque   2      31m
          
          kubectl get secret -n vault-secrets-operator-system -l app.kubernetes.io/component=client-cache-storage -o yaml
          ...
            data:
              messageMAC: px4SelUKuVElPzlhEFq8nUhm9LdIlyRbZpr0LL2VzVQ=
              secret: eyJjaXBoZXJ0ZXh0IjoidmF1bHQ6djE6YUFiSHh4Q0ZoTjJrLytRM0ZZUmE4VU5KQXFkUXArTnN1YjFCRFpiMisxUVNZR3IrR0dGdm5VUTVrbFpOTldOamRHL01sV1FFYUdrZExjMUpSdWJRS2tZV2RBb0I3aHdOUFkyaU54cUxIOEhJSGhuTWJGdHhYdXBmR0tnRko0bUlndVFQVXpyaXZpYys2aVVNK1YzZnhyMmtUa1UzZVZIYTZZMEVrbC9xVkR4cUZxMkdaVmVLNXkzRlNsS1h4alhia0JDRW1RQkdyRXY3VTVxTVRNdTlDUHEvSGg3NHNRNlZEOTRPNG5zZk9Jd2dNUVovTVd2RXRuck1RSzdNTW5ZTGxGdGd0VTdsSTdkVnVOd0hsRkNCN0lFdjROazJZeUc0cWFVODQ3VTNUMGY3KzJ6eFd3Y3FUajV1L2txd1c3TmlPbHBuVEduYmNtSVJSemZZekRRMzZzdjl0RG1FdWpFZzdwdExVWEVybXU4L3N1RHcwS08zSlFUTVQrLy9xalEwb1lGaWRPVU56cm1GSjl4L2dRRG03U0FqcXRHQUV1dFdYYTA3MDQzRHcvK1NRUFpiZm5CdjdBYzd2L2ZFSmo4MjloOFBlQnRHUlZPVkZWNXIxUFVsWFBRZVc3MVl3VlZUVzVPZktpdEhPQ3NnODdqTjJ1dGJycHU5M01uOFJILzZMYWZ5cVNQc2FUZlUwYjFJUVdoQmFBTGU5QjQyWHkrdHF5RWNrLzBoUUhuditEK0kxK0l3RHFBR1BvUGdqZEZ6bTZua0FrRWpqZi9paWtBbnpZMk52ZlJJQnQwZHpOTVl1UFpIdHVwRWpydGw2czVDSHpUYVRhZXEya1ArL0c4U2x4V3hTdHRGUnVWMzA1MTZWNEI5TGV3OHlUR0U5SkhvS0gxZkk2SFdURHdZZkRlajloUFZBS1REOXBKMjJ1YkxTc2NiKzBGMTZvdDBQOFh4Yk5YVmd0YzhrSmczZ0g1ZS9MaHdxb25oZkpDNGRQWDBMTmZuTVVncXBQakRodHpzVjFkaTBaT21CU2JIRDlVWkx5NFlwODJuOTBLZ2o4UzRTbEEvR1ZNRVdvVTlINXhOejlQeEw1eDBaYUZmSUs2bEhXUW5YMFNyQlcweDc2RmhKWERDaGhQYzBYRkQxTk5XREZmbUFrUjdmUVpJUmZub3RSbW50RTBwOXdlOWNlQktCM0x6bHV5eVhFMFBaY1VDSzNJeFlUckNNWTVLdWk4Q1VaZ2dPcFI1bEhuS2kwMVpva3ZmRThPYUFiRFQ4QkRvWERjeVF6dGdJUGxYNmRCVktNZENnT0dZSmUrd3F1eGM4K0dDVk1VRWM1NFlWUmg2K2NKQTE3bldEWHhpWTE3elBkQkJOWjdHRHFqakRGaklRYU1JQ1hwRGVOUTRaSDZnN3QwPSIsImtleV92ZXJzaW9uIjoxfQ==
            immutable: true
          ...
          
           

          5.7. PKI Secrets

          • 운영자가 단일 Vault PKI 시크릿을 단일 Kubernetes 시크릿으로 동기화하는 데 필요한 구성입니다.
          • Ingress, mTLS, Webapp 등 PKI 인증서를 사용하는 애플리케이션에서 동적으로 변경된 PKI 인증서를 사용할 수 있도록 지원합니다.

           

          5.8. 📖 추가 학습자료

          apiVersion: cert-manager.io/v1
          kind: Issuer
          metadata:
            name: vault-issuer
            namespace: sandbox
          spec:
            vault:
              path: pki_int/sign/example-dot-com
              server: https://vault.local
              caBundle: <base64 encoded CA Bundle PEM file>
              auth:
                ...
           
           
          image
           
          image
        Designed by Tistory.