LoginSignup
1
0

More than 1 year has passed since last update.

External Secret OperatorとVaultを組み合わせて利用する

Last updated at Posted at 2023-02-04

External Secret Operatorとは

External Secret Operator (ESO)とは外部のシークレットをKubernetes上で管理するためのソフトウェアです。
以下記事でいくつか特徴が挙げられていますが、一番はGitOpsを実施する際のシークレット管理がしやすくなることだと思います。GitHubにシークレット情報をコミットせずにGitOpsを実現できます。
https://atmarkit.itmedia.co.jp/ait/articles/2209/29/news015.html

今回はHashicorp Vaultを外部シークレットマネージャとして利用します。

前提

  • Vaultを知っている
  • Kubernetesを知っている

環境

  • Windows11 (wsl2)
  • Kubernetes version 1.25.3 (kind構築)
  • Vault version 1.12

検証

今回やること

  • ESOインストール
  • Vault のKubernetes authを利用する認証設定
  • 動作確認

ESOインストール

ESOのインストールはとても簡単で以下helmコマンドを実行するだけです。

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

シークレットデータ準備

Vaultにテストデータを登録します。
今回はESOの機能を確認できれば良いので「my-value=mysecret」を登録してます。

/ $ vault secrets enable -path=eso -version=2 -description="This secret engine is used the ESO to get secrets" kv
Success! Enabled the kv secrets engine at: eso/
/ $ vault kv put eso/foo my-value=mysecret
== Secret Path ==
eso/data/foo

======= Metadata =======
Key                Value
---                -----
created_time       2023-02-04T10:19:04.717624389Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

Kubernetes auth 準備

ESOが利用できる認証方式は5つあります。

  • token-based
  • appRole
  • kubernetes-native
  • ldap
  • jwt/oidc

今回は一番運用しやすそうなKubernetes authを検証します。理由は最後に少し触れます。
検証にあたっては以下のページを参考にしてます。
https://cloud.redhat.com/blog/vault-integration-using-kubernetes-authentication-method#:~:text=Kubernetes%20Auth%20Method%20The%20Kubernetes%20authentication%20method%20can,%2Fvar%2Frun%2Fsecrets%2Fkubernetes.io%2Fserviceaccount%2Ftoken%20and%20is%20sent%20to%20Vault%20for%20authentication.

「system:auth-delegator」はKubernetesのデフォルトロールです。
https://kubernetes.io/ja/docs/reference/access-authn-authz/rbac/#%E4%BB%96%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AErole

kubectl create sa vault-auth -n vault
kubectl create clusterrolebinding k8s-auth-client-for-vault --clusterrole=system:auth-delegator --serviceaccount=vault:vault-auth

Kubernetes authをするうえでVault側に必要なのは以下3つです。

  1. Service Accountのトークン
  2. kubernetes API Serverのエンドポイント
  3. Kubernetes ClusterのCA証明書

まずはService Accountのsecretを取得できるように以下のようなリソースを作成します。

kubectl apply -f vault-auth.yaml -n vault
vault-auth.yaml
apiVersion: v1
kind: Secret
metadata:
  name: vault-auth
  annotations:
    kubernetes.io/service-account.name: "vault-auth"
type: kubernetes.io/service-account-token

2, 3はそれぞれKubernetes configファイルから取得できるのでこれで準備ができました。
以下のように整形しつつ値を取得します。
Service AccountのトークンとCA証明書はbase64でエンコードされているので注意が必要です。ここを間違えると認証がうまくいきません。

token_reviewer_jwt=$(kubectl get secret -n vault -o jsonpath='{.data.token}' vault-auth | base64 -d)
kubernetes_host=https://kubernetes.default.svc.cluster.local  # vault がKubernetes API Serverにアクセスするために必要
kubernetes_ca_cert=$(kubectl config view -o jsonpath='{.clusters[].cluster.certificate-authority-data}' --minify=true --raw | base64 -d)

Kubernetes auth 設定

以下コマンドでkubernetes authを有効化します。
role名を「eso-vault」としてpolicyは先ほど作成したロールです。

vault auth enable -description="k8s secret engine for vault" kubernetes 
vault write auth/kubernetes/config \
    token_reviewer_jwt=$token_reviewer_jwt \
    kubernetes_host=$kubernetes_host \
    kubernetes_ca_cert=$kubernetes_ca_cert

vault write auth/kubernetes/role/eso-vault \
    bound_service_account_names=vault-auth \
    bound_service_account_namespaces=vault \
    policies=default,eso-vault-client \
    ttl=15m

ESO準備

ESOがリクエストするためのロールを設定します。

vault policy write eso-vault-client eso-vault-client.hcl
eso-vault-client.hcl
path "eso/data/*" {
  capabilities = ["read"]
}

動作確認します。以下のような結果がかえってくればOKです。

/ $ vault write auth/kubernetes/login role=eso-vault jwt=$token_reviewer_jwt
Key                                       Value
---                                       -----
token                                     hvs.CAESIKQznRS1XNprF8eQjF_zZFlL8Da9jCHRmhCvTE3F5aP9Gh4KHGh2cy5IMGo1SHd0eU9ldzhIc00wZEJ2WG1MZGs
token_accessor                            dmRuQwUOUugmuXzqPEIwzVxl
token_duration                            1m
token_renewable                           true
token_policies                            ["default" "eso-vault-client"]
identity_policies                         []
policies                                  ["default" "eso-vault-client"]
token_meta_role                           eso-vault
token_meta_service_account_name           vault-auth
token_meta_service_account_namespace      vault
token_meta_service_account_secret_name    vault-auth
token_meta_service_account_uid            d35d56fd-24f3-45b8-a1e9-20b15a08f172

ここでやっとESOの設定が登場します。
ESOのリソースは3種類あり、それぞれClusterスコープのClusterSecretStoreとNamespaceスコープのSecretStore、ExternalSecretです。
ここではClusterSecretStoreとExternalSecretを組み合わせて利用します。
image.png

ESOサイトより引用
https://external-secrets.io/v0.7.2/provider/hashicorp-vault/

まずはそれぞれの設定をyamlで書きます。

secret-store-k8s-es.yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: vault-backend-k8s-auth
  labels:
    service: secret-manager
    version: 1.0.0
    env: prd
spec:
  provider:
    vault:
      server: http://vault.vault.svc.cluster.local:8200  # 接続先のVault Cluster
      path: eso
      version: v2
      auth:
        kubernetes:
          # Path where the Kubernetes authentication backend is mounted in Vault
          mountPath: kubernetes  # 有効にしたkubernetes auth。今回はデフォルトなのでkubernetes
          # A required field containing the Vault Role to assume.
          role: eso-vault  # 作成したvaultのrole名
          # Optional service account field containing the name
          # of a kubernetes ServiceAccount
          serviceAccountRef:
            name: vault-auth
            namespace: vault
secret-store-k8s-ss.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: vault-eso-example
spec:
  refreshInterval: 15s
  secretStoreRef:
    name: vault-backend-k8s-auth  # 利用するSecretStoreの名前
    kind: ClusterSecretStore
  target:
    name: output-secret  # 作成するsecretの名前
  data:
  - secretKey: foobar  # 作成するSecretのKeyの名前
    remoteRef:
      # vault kv put eso/foo my-value=mysecretで作成したシークレットを取得する設定
      key: eso/foo
      property: my-value

適用してエラーが出なければOK。Secretの動機まで10秒程度かかります。

kubectl apply -f ./secret-store-k8s-es.yaml
kubectl apply -f ./secret-store-k8s-ss.yaml

root@mypc02:/mnt/e/work/eso# kc get clustersecretstores.external-secrets.io,externalsecrets.external-secrets.io
NAME                                                            AGE   STATUS   CAPABILITIES   READY
clustersecretstore.external-secrets.io/vault-backend-k8s-auth   26m   Valid    ReadWrite      True

NAME                                                   STORE                    REFRESH INTERVAL   STATUS         READY
externalsecret.external-secrets.io/vault-eso-example   vault-backend-k8s-auth   15s                SecretSynced   True

動作確認

最後にSecretを取得してその値を確認します。

root@mypc02:/mnt/e/work/eso# kc get secret
NAME            TYPE     DATA   AGE
output-secret   Opaque   1      76s
root@mypc02:/mnt/e/work/eso# kc get secret output-secret -o yaml | grep data: -A1
data:
  foobar: bXlzZWNyZXQ=
root@mypc02:/mnt/e/work/eso# echo bXlzZWNyZXQ= | base64 -d
mysecret

おわりに

今回GitHubにKubernetesのSecret情報をコミットするのをうまく回避したくてESOの検証をしました。
現場で利用する際には検討する箇所がいくつかあるかとは思いますが、なかなか使いやすいと思いました。途中でkubernetes authを選んだ理由を後回しにしていたので最後に少し触れます。ただ未検証ですのであっているかどうかはわからないので、参考程度に聞いていただければと思います。
まず、ldapとjwt/oidcはM2Mの認証には適さないので除外しました。
token-based を利用した場合はstaticな認証方式であることとttl、max-ttlの更新が気になりました。ttl、max-ttlによっては定期的に手動で更新が必要になりそうだと思いました。
approleはdynamicな認証方式であるもののやはりttl、max-ttlの更新が必要になり別途更新する仕組みが必要になりそうでした。

以上です。最後まで読んでいただきありがとうございます。

1
0
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
1
0