anpanman
Published on

Vault 在 Kubernetes 上的部署指南:使用 AWS EFS 實現持久化存儲

Vault 服務部署說明

本文件提供在 AWS EKS Fargate 環境下部署 HashiCorp Vault 的詳細步驟,包含持久化儲存設定、自動解封、集群同步以及 Kubernetes 認證配置。部署完成後,Vault 可與 External Secrets Operator (ESO) 整合,用於管理帳號密碼。

環境需求

  • AWS EKS Fargate 叢集
  • AWS EFS 用於持久化儲存
  • Helm 用於 Vault 安裝
  • ArgoCD 用於應用程式部署
  • kubectl 用於 Kubernetes 資源管理
  • Vault CLI 用於初始化與配置

部署步驟

1. 安裝 AWS EFS CSI Driver

Vault 需要持久化儲存,在 EKS Fargate 中僅支援 AWS EFS。請先安裝 AWS EFS CSI Driver 以支援 EFS 掛載。

建立好 arn:aws:iam::xxxxxxxx:role/EKS_EFS_CSI_DriverRole

並增加對應的 turst policy 和 KS_EFS_CSI_Driver_Policy

  helm upgrade --install aws-efs-csi-driver --namespace kube-system aws-efs-csi-driver/aws-efs-csi-driver \
    --set controller.replicas=2 \
    --set node.enabled=false \
    --set sidecars.nodeDriverRegistrar.enabled=false \
    --set controller.securityContext.privileged=false \
    --set controller.containerSecurityContext.privileged=false \
    --set serviceAccount.create=true \
    --set serviceAccount.name=efs-csi-controller-sa
    --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"="arn:aws:iam::xxxxxxxxx:role/EKS_EFS_CSI_DriverRole"

詳見 https://github.com/kubernetes-sigs/aws-efs-csi-driver

2. 建立 StorageClass

透過 Helm 安裝 Vault 時,會自動建立 EFS 的 Access Point 以及 PersistentVolumeClaim (PVC) 和 PersistentVolume (PV)。無需手動定義,但需確保 StorageClass.yaml 已正確配置 EFS ID、GID 和 UID。

kubectl apply -f aws-deployment/vault-step/StorageClass.yaml

注意:請確認 StorageClass.yaml 中需要根據實際需求設定 EFS ID、GID 和 UID。

3. 建立 Vault Namespace

為 Vault 建立專屬命名空間:

kubectl create namespace vault

4. 配置 AWS KMS 自動解封

為 Vault 設定 AWS KMS 自動解封功能:

  1. 建立 KMS 資源並取得 kms_id
  2. kms_id 填入 aws-deployment/application/vault.yamlseal "awskms" 區段。

5. 部署 Vault 應用程式

使用 ArgoCD 部署 Vault,啟動三個 Pod(vault-0、vault-1、vault-2):

kubectl apply -f aws-deployment/application/vault.yaml

6. 檢查 Vault pod 狀態

確認三個 Vault Pod 均已啟動並運行:

kubectl get pods -n vault

出現這個問題可能是 pv, pvc 沒有刪除乾淨,請先刪除,它們會自動重建

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  10m   fargate-scheduler  Pod not supported on Fargate: volumes not supported: data not supported because: PVC data-vault-0 not bound
kubectl get pvc -n vault
kubectl delete pvc -n vault --all
kubectl get pv
kubectl delete pv pvc-1a5e124f-2df9-4d3d-9878-52a8e08ef594

7. 同步 Vault 集群

vault-1vault-2 加入 vault-0 的 Raft 集群:

去其中一個 Pod 執行以下指令:

kubectl -n vault exec -it vault-0 -- /bin/sh

init 之後記下 key 跟 root token

vault operator init

初始化後會產生 5 個 Unseal KeyRoot Token,請妥善記錄這些資訊。

接著做以下指令:

export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=hvs.XXXXXXXXXXXXXXX
vault operator raft list-peers

會出現以下訊息:

Node       Address                        State     Voter
----       -------                        -----     -----
vault-0    vault-0.vault-internal:8201    leader    true

去另外兩台做以下指令:

kubectl -n vault exec -it vault-1 -- /bin/sh
export VAULT_TOKEN=hvs.XXXXXXXXXXXXXXX
vault operator raft join http://vault-0.vault-internal:8200
vault operator unseal
Unseal Key (will be hidden): XXXXXX (輸入其中一組在第一台 init 時產生的 key)
vault operator raft list-peers

檢查集群狀態,確認所有 Pod 已正確加入 Raft 集群。會看到有 leader, followers:

Node       Address                        State       Voter
----       -------                        -----       -----
vault-0    vault-0.vault-internal:8201    leader      true
vault-1    vault-1.vault-internal:8201    follower    true
vault-2    vault-2.vault-internal:8201    follower    true

建立 ingress

kubectl apply -f aws-deployment/alb-ingress/vault/ingress.yaml

查地址

kubectl get ingress -n vault

預期輸出:

NAME                               CLASS   HOSTS   ADDRESS                                                                PORTS   AGE
vault-ha-cluster-service-ingress   alb     *       k8s-vault-vaulthac-0e9b13acef-2021229786.ap-east-2.elb.amazonaws.com   80      8s

8. 配置 Kubernetes 認證

為 Vault 設定 Kubernetes 認證,需取得以下三個值:

  • JWT_TOKEN:從 Secret 中取得。
  • K8S_HOST:Kubernetes API 伺服器地址。
  • K8S_CA_CERT:secret 的 CA 證書。

步驟:

  1. 建立 Service Account Secret:
kubectl apply -f aws-deployment/vault-step/vault-sa-token.yaml
  1. 提取認證所需值(在 Linux-like 環境下):
export VAULT_TOKEN=hvs.XXXXXXXXXXXXXXX
export VAULT_ADDR=http://127.0.0.1:8200
export JWT_TOKEN=$(kubectl get secret vault-sa-token -n vault -o jsonpath='{.data.token}' | base64 --decode)
export K8S_HOST=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
export K8S_CA_CERT=$(kubectl get secret vault-sa-token -n vault -o jsonpath='{.data.ca\.crt}' | base64 --decode)
echo $JWT_TOKEN      # 顯示 JWT 內容
echo $K8S_HOST       # 顯示 Kubernetes API 地址
echo $K8S_CA_CERT    # 顯示 CA 證書內容

  1. 在 Vault 中配置 Kubernetes 認證:
kubectl -n vault exec -it vault-0 -- vault auth enable kubernetes

vault write auth/kubernetes/config \
    token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:$KUBERNETES_PORT_443_TCP_PORT" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

注意事項

  • 確保 EFS CSI Driver 已正確安裝並配置,否則 Vault 無法持久化資料。
  • 妥善保存初始化時產生的 Unseal Key 和 Root Token,遺失將無法恢復。
  • 檢查 Vault 集群狀態,確保所有 Pod 正常運行並加入 Raft 集群。
  • Kubernetes 認證配置需確保 vault-sa-token Secret 正確生成。