kubernetes/practical

Using HashiCorp Vault with Kubernetes SecretStore: Hands-on Guide

blogger903 2024. 8. 21. 13:58
728x90

Using HashiCorp Vault with Kubernetes External Secrets: Hands-on Guide

 

"k8s 클러스터에 springboot application 배포 시리즈"의 시작 포스팅입니다

이번 포스트에서는 minikube에 배포한 Vault로 secret 정보를 관리하고 External Store 방식으로 k8s secret으로 연동해보겠습니다


이전에 포스트한  Kubernetes Vault Deployment: A Hands-on Guide with Minikube 에 k8s에 vault를 배포하는 과정이 포스팅되어있습니다

준비사항: Helm, k8s cluster, Vault

 

다루는 내용

  • ExternalStore로 vault secret과 k8s secret 연동
  • 연동과정 중 troubleshooting

 

ExternalStore로 vault secret와 k8s secret 연동

Vault의 secret을 k8s deployment의 환경변수로 주입하는 다양한 방법중에 "External Secrets Operator"을 이용한 Vault secret을 k8s secret으로 동기화를 다룹니다. ESO는 다양한 provider에 적용할 수 있는 범용 솔루션이어서 ESO로 연동했습니다

 

일련의 과정을 통해 vault secret와 k8s secret을 동기화합니다

  • Vault Secret 추가
  • Vault authentication
  • ExternalSecretsOperator 설치
  • Secret 정의
  • SecretStore 정의
  • ExternalSecrets 정의
  • Deployment에서 환경변수 주입 확인

Vault secret 추가

 Kubernetes Vault Deployment: A Hands-on Guide with Minikube 에서 다루었습니다

Vault authentication

다양한 authentication 중 approle을 이용한 인증방식을 통해 kubernetes와 vault의 secret engine을 연동하겠습니다

 

현재 KV secret engines을 생성후 특정 path로 secret을 생성한 상태입니다. policy를 생성한 후 role 생성시 policy를 연결해줍니다

 

policy 생성

 

Dashboard > Policies

 

Create ACL Policy
How to write a policy 보고 생성합니다

 

 

approle 활성화

approle을 사용하려면 활성화해줘야합니다

 

Dashboard > Access 클릭 > enable new method

 

enable new method approle을 생성합니다

 

vault shell에서 role을 생성해줍니다

 

vault write auth/approle/role/<생성할 role이름> token_policies=<생성한 policy이름>

 

role 생성 확인

vault read auth/approle/role/dev_role

 

roleId 확인

vault read /auth/approle/role/dev_role/role-id

 

secretId 발급

vault write /auth/approle/role/dev_role/secret-id -force

 

 

ExternalSecretsOperator 설치

helm repo add external-secrets https://charts.external-secrets.io

helm install external-secrets \
   external-secrets/external-secrets \
    -n external-secrets \
    --create-namespace \
  # --set installCRDs=true

 

Secret 정의

apiVersion: v1
kind: Secret
metadata:
  name: vault-approle-secret
type: Opaque
stringData:
  secretId: <approle secretId>

 

SecretStore 정의

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: dev-springboot-app
spec:
  provider:
    vault:
      server: "<Fully Qualified Domain Name>:<PORT>"
      path: "<secretEngines이름>"
      version: "v2"
      auth:
        appRole:
          path: "approle"
          roleId: "roleId"
          secretRef:
            name: "vault-approle-secret"
            key: "secretId"
---

 

 

ExternalSecrets 정의

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: dev-springboot-app
spec:
  refreshInterval: "15s"
  secretStoreRef:
    name: dev-springboot-app
    kind: SecretStore
  target:
    name: dev-springboot-app-secret # k8s에 생성될 secret 이름
  dataFrom:
    - extract:
        key: <vault secret path>
---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: bitnami/nginx:latest
          envFrom:
            - secretRef:
                name: dev-springboot-app-secret  # 이전에 생성한 Secret 이름

 

Deployment에서 환경변수 주입 확인

 

연동과정 중 troubleshooting

  • SecretStore - appRole authentication
  • ExternalSecrets - cannot read secret data from Vault

SecretStore - appRole authentication

secretStore의 spec에서 server와 auth roleId와 secretId를 매핑해야하고, secretId는 secret을 별도로 빼서 적용해주었습니다

 

ExternalSecrets - cannot read secret data from Vault

external secret이 api로 vault를 찌릅니다 그래서 policy의 path를 지정하는데 보이는 path와 api path가 다르기 때문에 파악하는게 어려웠습니다

예를 들어, secret path가 <secret engine이름>/bbb/** 이면 api path는 <secret engine이름>/data/bbb/** 입니다

이것은 vault-ui에서 secret의 config에서 확인할 수 있습니다

 

그리고 policy에서 path를 <secret engine이름>/bbb/** 가 아닌 <secret engine이름>/data/bbb/** api path로 맞춰야합니다

ExternalSecret의 spec.dataFrom.extract.key 는 vault에서 보이는 path를 매핑해줘야 합니다

SecretStore의 spec.provider.vault.path: <secret engine name>을 매핑해줘야 합니다