2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[k8s] External Secret + VaultでkubernetesのSecret管理基盤を作成した話

Last updated at Posted at 2023-12-25

はじめに

前回は自宅サーバーで k8s クラスタを立てました。

今回は kubernetes の ExternalSecret と vault を連携して Secret 管理の基盤を作っていこうと思います。

完成品は Github 上に公開してありますので参考程度にどうぞ

環境

OS:
Ubuntu22.04

kubeadm:

$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", GitCommit:"89a4ea3e1e4ddd7f7572286090359983e0387b2f", GitTreeState:"clean", BuildDate:"2023-09-13T09:34:32Z", GoVersion:"go1.20.8", Compiler:"gc", Platform:"linux/amd64"}

helm:

$ helm version
version.BuildInfo{Version:"v3.13.1", GitCommit:"3547a4b5bf5edb5478ce352e18858d8a552a4110", GitTreeState:"clean", GoVersion:"go1.20.8"}

flux:

$ flux version
flux: v2.2.0
distribution: flux-v2.2.0
helm-controller: v0.37.0
image-automation-controller: v0.37.0
image-reflector-controller: v0.31.1
kustomize-controller: v1.2.0
notification-controller: v1.2.2
source-controller: v1.2.2

前提

  • flux の helm controller・kustomize controller が動作している
  • ingress-nginx が動作している

vault のインストール

公式ドキュメントに従って kubernetes に vault をインストールしていきます。

公式では helm コマンドを用いてインストールしていきますが、ここでは flux の helm controller を使ってインストールします。

vault/helm.yamlに次のように記述します。

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: hashicorp
  namespace: vault
spec:
  interval: 1h
  url: https://helm.releases.hashicorp.com
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: vault
  namespace: vault
spec:
  interval: 1h
  chart:
    spec:
      chart: vault
      sourceRef:
        kind: HelmRepository
        name: hashicorp
  values:
    server:
      ingress:
        enabled: true
        ingressClassName: nginx
        pathType: Prefix
        hosts:
          - host: vault.example.com

最後の行のspec.values/server/ingress/hosts[].hostにはご自身の vault 用のホストアドレスを記述してください。
なお、公式ドキュメントでは vault サーバー 3 台の HA 構成となっていますが、今回はメモリ節約のため 1 台で構成していきます。

External Secret Operator のインストール

公式ドキュメントを参考にインストールしていきます。

external-secrets/helm.yamlに次のように記述します。

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: external-secrets
  namespace: external-secrets
spec:
  interval: 1h
  url: https://charts.external-secrets.io
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: external-secrets
  namespace: external-secrets
spec:
  interval: 1h
  chart:
    spec:
      chart: external-secrets
      sourceRef:
        kind: HelmRepository
        name: external-secrets

vault のセットアップ

まずは vault の初期処理をします。

$ kubectl exec vault-0 -n vault -- vault operator init \
    -key-shares=1 \
    -key-threshold=1 \
    -format=json > cluster-keys.json

VAULT_UNSEAL_KEYに unseal 用の鍵を入れます。

$ VAULT_UNSEAL_KEY=$(jq -r ".unseal_keys_b64[]" cluster-keys.json)

unseal します。

$ kubectl exec vault-0 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY

これで vault が使えるようになります。

vault CLI のインストール

vaultに CLI で鍵の追加等を行えるように、vault の CLI をインストールします。
参考: https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-install

sudo apt update && sudo apt install gpg wget

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

gpg --no-default-keyring --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg --fingerprint

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update && sudo apt install vault

vault versionで正常にインストールできたことを確認します。

$ vault version
Vault v1.15.4 (9b61934559ba31150860e618cf18e816cbddc630), built 2023-12-04T17:45:28Z

vault にログインするために、root_tokenを確認します。

$ jq -r ".root_token" cluster-keys.json

また、VAULT_ADDRには vault を helm でインストールする際に指定した vault のホストアドレスを指定します。

$ export VAULT_ADDR=https://vault.example.com

vault loginでログインをします。ログイントークンを求められるので先程確認したroot_tokenを入力してください。

$ vault login

vault で kubernetes との接続を許可

vault auth enable kubernetes
export SA_SECRET_NAME=$(kubectl get secrets --output=json \
    | jq -r '.items[].metadata | select(.name|startswith("vault-auth-")).name')
export SA_JWT_TOKEN=$(kubectl get secret $SA_SECRET_NAME \
    --output 'go-template={{ .data.token }}' | base64 --decode)
export SA_CA_CRT=$(kubectl config view --raw --minify --flatten \
    --output 'jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
export K8S_HOST=$(kubectl config view --raw --minify --flatten \
    --output 'jsonpath={.clusters[].cluster.server}')
vault write auth/kubernetes/config \
     token_reviewer_jwt="$SA_JWT_TOKEN" \
     kubernetes_host="$K8S_HOST" \
     kubernetes_ca_cert="$SA_CA_CRT" \
     issuer="https://kubernetes.default.svc.cluster.local"

Policy, Role の設定

まず、vault の Policy と Role を作成します。
vault の管理画面(vault.example.com)にアクセスし、ログインします。

image.png

ログインしたら、Policies > ACL Policiesから Policy を追加します。

image.png

Name はk8s-cluster、Policy は

path "k8s/*" {
    capabilities = ["read", "list"]
}

と記述します。

次にAccess > Authentication Methods > kubernetes > Create roleからロールを作成します。

image.png
image.png

Name はk8s-cluster、Bound service account names はvault-auth、Bound service account namespaces はvault、Generated Token's Policies はk8s-cluster (先ほど作成した Policy の名前)、Generated Token's Initial TTL は86400 (24 時間)とします。

最後に、Secrets Engines > Enable new engineからKVを選択して作成します。Path はk8sとします。
image.png

今回は実験のためにk8s/portfolioに secret を作成しておきます。
image.png

kubernetes 側の設定

まず、kubernetes 側で ServiceAccount と Secret を作成します。
vault/service-account.yamlに次のように記述します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-auth
  namespace: vault
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-role-binding
  namespace: vault
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: vault-auth
    namespace: vault

vault/secret.yamlに次のように記述します。

apiVersion: v1
kind: Secret
metadata:
  name: vault-auth-secret
  annotations:
    kubernetes.io/service-account.name: vault-auth
type: kubernetes.io/service-account-token

external-secrets-store/secret-store.yamlに次のように記述します。

apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: vault-secret-store
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: k8s
      version: v2
      namespace: vault
      auth:
        kubernetes:
          mountPath: kubernetes
          role: k8s-cluster
          serviceAccountRef:
            name: vault-auth
            namespace: vault

今回は簡単のためSecretStoreではなくClusterSecretStoreを使うことにしました。

最後に、app/external-secret.yamlに次のように記述します。

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: portfolio-secret
spec:
  secretStoreRef:
    name: vault-secret-store
    kind: ClusterSecretStore
  refreshInterval: 1m
  data:
    - secretKey: fuga
      remoteRef:
        key: portfolio
        property: password

これで External Secret から key を取得できるようになりました。

最後に

今回は External Secret Operator と Vault を連携して kubernetes の secret 基盤を作成しました。次回は今回使った secret 基盤を活用してデータベースサーバーを作っていこうと思います。

参考資料

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?