Vault
Vault
Issuer
は、認証局である Vault を表します。Vault は、公開鍵基盤 (PKI) の証明書に署名するために使用できる多目的シークレットストアです。 Vault は cert-manager の外部プロジェクトであるため、このガイドでは、署名できるよう正しく構成およびデプロイされていることを前提としています。 Vault を認証局として構成する方法の詳細については、こちら をご覧ください。
この Issuer
タイプは、通常、Vault が既にインフラストラクチャ内で使用されている場合、または CA Issuer 単独では提供できない機能セットを利用したい場合に使用されます。
デプロイメント
すべての Vault Issuer は、証明書の要求に関する共通の構成、つまりサーバー、パス、および CA バンドルを共有します。
- サーバーは、Vault にアクセスできる URL です。
- パスは、署名に使用される Vault パスです。パスは
sign
エンドポイントを*必ず*使用する必要があります。 - CA バンドルは、Vault 接続を信頼するための認証局の base64 エンコードされた文字列を含むオプションのフィールドを示します。これは通常、
https
URL を使用する場合に*常に*必要です。
以下は、Vault サーバーに接続するための構成の例です。
**警告**: この構成は、認証方式が追加されていないため、不完全です。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: sandboxspec:vault:path: pki_int/sign/example-dot-comserver: https://vault.localcaBundle: <base64 encoded CA Bundle PEM file>auth:...
mTLS が適用された Vault サーバーへのアクセス
特定のユースケースでは、Vaultサーバーは、クライアントがクライアント証明書を提示することを強制するように構成できます。これらのクライアント証明書はトランスポート層の強制に過ぎず、Vault API自体に認証および承認メカニズムを提供するものではありません。
📖 VaultサーバーTCPリスナーの構成について読む。
mTLS が適用された Vault を構成するには、以下の手順に従ってください。
- バンドルCAとサーバーTLS証明書を生成する
step certificate create "Example Server Root CA" server_ca.crt server_ca.key \--profile root-ca \--not-after=87600h \--no-password \--insecurestep certificate create vault.vault server.crt server.key \--profile leaf \--not-after=8760h \--ca ./server_ca.crt \--ca-key server_ca.key \--no-password \--insecure
- Vaultクライアント証明書とCAを生成する
step certificate create "Example Client Root CA" client_ca.crt client_ca.key \--profile root-ca \--not-after=87600h \--no-password \--insecurestep certificate create client.vault client.crt client.key \--profile leaf \--not-after=8760h \--ca ./client_ca.crt \--ca-key client_ca.key \--no-password \--insecure
- 公式Helmチャートを使用して Kubernetes クラスターに Vault をインストールすると仮定して、Vault インストールを準備します。
- Vault 名前空間を作成する
kubectl create ns vault
- Vault がインストールされるのと同じ名前空間に Kubernetes Secret を作成し、以下のように生成された PKI ファイルを追加します。
kubectl create secret generic vault-tls \--namespace vault \--from-file=server.key \--from-file=server.crt \--from-file=client_ca.crt \--from-file=client.crt \--from-file=client.key
- 次の値ファイルを使用して Vault をデプロイします。
⚠️ これらの設定は、迅速なローカルテストのみを目的としています。安全ではなく、本番環境での使用には適していません。
# vault-values.yamlglobal:tlsDisable: falseinjector:enabled: falseserver:dataStorage:enabled: falsestandalone:enabled: trueconfig: |listener "tcp" {address = "[::]:8200"cluster_address = "[::]:8201"tls_disable = falsetls_client_ca_file = "/vault/tls/client_ca.crt"tls_cert_file = "/vault/tls/server.crt"tls_key_file = "/vault/tls/server.key"tls_require_and_verify_client_cert = true}extraArgs: "-dev-tls -dev-listen-address=[::]:8202"extraEnvironmentVars:VAULT_TLSCERT: /vault/tls/server.crtVAULT_TLSKEY: /vault/tls/server.keyVAULT_CLIENT_CERT: /vault/tls/client.crtVAULT_CLIENT_KEY: /vault/tls/client.keyvolumes:- name: vault-tlssecret:defaultMode: 420secretName: vault-tlsvolumeMounts:- mountPath: /vault/tlsname: vault-tlsreadOnly: true
helm upgrade vault hashicorp/vault --install --namespace vault --create-namespace --values vault-values.yaml
- Kubernetes 認証用に Vault サーバーを構成する
kubectl -n vault exec pods/vault-0 -- \vault auth enable --tls-skip-verify kuberneteskubectl -n vault exec pods/vault-0 -- \vault write --tls-skip-verify \auth/kubernetes/role/vault-issuer \bound_service_account_names=vault-issuer \bound_service_account_namespaces=application-1 \audience="vault://application-1/vault-issuer" \policies=vault-issuer \ttl=1mkubectl -n vault exec pods/vault-0 -- \vault write --tls-skip-verify \auth/kubernetes/config \kubernetes_host=https://kubernetes.default
- アプリケーション名前空間を作成する
kubectl create ns application-1
- サービスアカウントを作成する
kubectl create serviceaccount -n application-1 vault-issuer
- ロールとバインディングを作成する
# rbac.yamlapiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: vault-issuernamespace: application-1rules:- apiGroups: ['']resources: ['serviceaccounts/token']resourceNames: ['vault-issuer']verbs: ['create']---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: vault-issuernamespace: application-1subjects:- kind: ServiceAccountname: cert-managernamespace: cert-managerroleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: vault-issuer
kubectl apply -f rbac.yaml
- Vaultクライアント証明書シークレットを作成する
kubectl create secret generic vault-client-tls \--namespace application-1 \--from-file=client.crt \--from-file=client.key \--from-file=server_ca.crt
- Issuer を作成する
# vault-issuer.yamlapiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: application-1spec:vault:path: pki_int/sign/application-1server: https://vault.vault:8200caBundleSecretRef:key: server_ca.crtname: vault-client-tlsclientCertSecretRef:name: vault-client-tlskey: client.crtclientKeySecretRef:name: vault-client-tlskey: client.keyauth:kubernetes:role: vault-issuermountPath: /v1/auth/kubernetesserviceAccountRef:name: vault-issuer
kubectl apply -f vault-issuer.yaml
- Issuer のステータスを確認する
kubectl describe issuer -n application-1
認証
Vault による証明書の署名リクエストを発行するには、発行者が Vault に対して適切に認証できる必要があります。 cert-manager は、Vault に対して認証するための複数の方法を提供しており、以下で詳しく説明します。
Vault 認証タイプ | cert-manager Issuer 構成 |
---|---|
AppRole | A. Vault AppRole での認証 |
トークン | B. Vault トークンでの認証 |
JWT/OIDC | C. Kubernetes サービスアカウントでの認証 > JWT/OIDC 認証を使用する |
Kubernetes | C. Kubernetes サービスアカウントでの認証 > Kubernetes 認証を使用する |
A. AppRole を使用した認証
AppRole は、内部ロールポリシーシステムを使用して Vault に対して認証する方法です。 この認証方法では、発行者がSecretID
秘密鍵、引き受けるロールのRoleID
、およびアプリロールパスを所有している必要があります。 まず、秘密IDキーは、Issuer
と同じ名前空間に存在する Kubernetes Secret
内に、またはClusterIssuer
の場合はCluster Resource Namespace
内に保存する必要があります。
apiVersion: v1kind: Secrettype: Opaquemetadata:name: cert-manager-vault-approlenamespace: sandboxdata:secretId: "MDI..."
Secret
が作成されると、この Secret
と、秘密 ID を格納するフィールドのデータキーを参照する Issuer
をデプロイする準備が整います。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: sandboxspec:vault:path: pki_int/sign/example-dot-comserver: https://vault.localcaBundle: <base64 encoded caBundle PEM file>auth:appRole:path: approleroleId: "291b9d21-8ff5-..."secretRef:name: cert-manager-vault-approlekey: secretId
B. トークンを使用した認証
この認証方法は、Vault がサポートする多くの認証バックエンドのいずれかから生成されたトークン文字列を使用します。 これらのトークンには有効期限があるため、定期的に更新する必要があります。 Vault トークンの詳細については、こちら をご覧ください。
**注**: cert-manager はこれらのトークンを自動的に更新しないため、これを行うための別のプロセスを導入する必要があります。
まず、トークンは、Issuer
と同じ名前空間内、または ClusterIssuer
を使用する場合は Cluster Resource Namespace
内の Kubernetes Secret
内に保存されます。
apiVersion: v1kind: Secrettype: Opaquemetadata:name: cert-manager-vault-tokennamespace: sandboxdata:token: "MjI..."
送信されると、この Secret
と、トークンデータが格納されているフィールドのキーを参照することにより、トークン認証を使用して Vault Issuer を作成できます。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: sandboxspec:vault:path: pki_int/sign/example-dot-comserver: https://vault.localcaBundle: <base64 encoded caBundle PEM file>auth:tokenSecretRef:name: cert-manager-vault-tokenkey: token
C. Kubernetes サービスアカウントを使用した認証
ℹ️ このドキュメントは、cert-manager >= v1.12.0 で有効です。
Vault JWT/OIDC 認証 および Vault Kubernetes 認証 を使用すると、cert-manager は Kubernetes サービスアカウントトークンを使用して Vault に対して認証し、Vault を認証局として使用して証明書を発行できます。
Vault 認証方法
オプション 1. Vault 認証方法: JWT/OIDC 認証を使用
JWT/OIDC 認証方式 は、以下の場合に Kubernetes 認証方式 の代わりに使用してください。
- Kubernetes クラスタの OIDC ディスカバリーエンドポイントが Vault サーバーから到達可能な場合 (セルフホスト型の Kubernetes または OpenShift クラスタを実行している場合は、これが当てはまらない可能性があります)。
- Vault サーバーが Kubernetes クラスタ内で実行されていない場合。
注: Kubernetes 認証の代わりに JWT 認証を使用すると、トークンの失効はチェックされなくなります。
「注: JWT 認証エンジンは、認証中に Kubernetes の TokenReview API を使用せず、公開鍵暗号を使用して JWT の内容を検証します。 つまり、Kubernetes によって失効されたトークンは、有効期限が切れるまで Vault では有効と見なされます。 このリスクを軽減するには、サービスアカウントトークンに短い TTL を使用するか、TokenReview API を使用する Kubernetes 認証を使用してください。」
cert-manager は 10 分後に有効期限が切れる短命のトークンを使用するため、これは問題ありません。
以下の手順では、JWT 認証方式の設定 (Vault のドキュメントに基づく) と cert-manager での使用する方法について説明します。
Vault の JWT 認証を設定するには、発行者 URL を取得する必要があります。
ISSUER="$(kubectl get --raw /.well-known/openid-configuration | jq -r '.issuer')"
URL が機能し、Vault サーバーからアクセスできることを確認してください。 例えば、レスポンスは次のようになります。
$ curl "$ISSUER/.well-known/openid-configuration"{"issuer": "https://container.googleapis.com/v1/projects/project001/locations/europe-west1-b/clusters/cert-manager-cluster","jwks_uri": "https://container.googleapis.com/v1/projects/project001/locations/europe-west1-b/clusters/cert-manager-cluster/jwks",...}$ curl "<jwks_uri value>"{"keys": [{"kty": "RSA","e": "AQAB","use": "sig","kid": "key-id","alg": "RS256","n": "..."}]}
次のステップは、Vault で JWT 認証を設定することです。 各クラスタには独自の JSON Web Key Set と OIDC ディスカバリーエンドポイントがあるため、Kubernetes クラスタごとに 1 つの JWT 認証パスを作成する必要があります。
vault auth enable -path=jwt-cluster001 jwtkubectl config view --minify --flatten -ojson \| jq -r '.clusters[].cluster."certificate-authority-data"' \| base64 -d >/tmp/cacrtvault write auth/jwt-cluster001/config \oidc_discovery_url="${ISSUER}" \oidc_discovery_ca_pem=@/tmp/cacrt
次に、Kubernetes サービスアカウントと一致する Vault ロールを作成します。
kubectl create serviceaccount -n sandbox vault-issuer
次に、cert-manager がサービスアカウントのトークンを取得できるように RBAC ロールを追加します。
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: vault-issuernamespace: sandboxrules:- apiGroups: ['']resources: ['serviceaccounts/token']resourceNames: ['vault-issuer']verbs: ['create']---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: vault-issuernamespace: sandboxsubjects:- kind: ServiceAccountname: cert-managernamespace: cert-managerroleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: vault-issuer
次に、Vault ロールを作成します。
vault write auth/jwt-cluster001/role/vault-issuer-role \role_type="jwt" \bound_audiences="vault://sandbox/vault-issuer" \user_claim="sub" \bound_subject="system:serviceaccount:sandbox:vault-issuer" \policies="default" \ttl=1m
Issuer または ClusterIssuer ごとに異なる Vault ロールを使用することをお勧めします。 audience
を使用すると、Vault ロールを単一の Issuer または ClusterIssuer に制限できます。 構文は次のとおりです。
"vault://<namespace>/<issuer-name>" # For an Issuer."vault://<cluster-issuer-name>" # For a ClusterIssuer.
最後に、Issuer を作成できます。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: sandboxspec:vault:path: pki_int/sign/example-dot-comserver: https://vault.localauth:kubernetes:role: vault-issuer-rolemountPath: /v1/auth/jwt-cluster001serviceAccountRef:name: vault-issuer
オプション 2. Vault 認証方法: Kubernetes 認証を使用
Kubernetes 認証方式 は、以下の場合に使用する必要があります。
- Vault サーバーが Kubernetes クラスタ内で実行されている場合。
- または、Kubernetes クラスタの OIDC ディスカバリーエンドポイントが Vault サーバーから到達できないが、Vault が Kubernetes API サーバーに到達できる場合。
以下の手順では、Kubernetes 認証方式の設定 (Vault のドキュメントに基づく) と cert-manager での使用する方法について説明します。
Kubernetes 認証方式では、token_reviewer_jwt
が必要です。これは、Vault が Kubernetes API サーバーの TokenReview API を呼び出すために使用する JWT トークンです。 このエンドポイントは、cert-manager によって提供される JWT トークンを検証するために使用されます。 この token_reviewer_jwt
トークンを提供するには、3 つの方法があります。
- Vault を Kubernetes クラスタ内で実行している場合は、Vault ポッドにマウントされている Kubernetes サービスアカウントトークンを使用できます。
✅ は、Vault が Kubernetes クラスタ内で実行されていることを自動検出した場合に有効になります。 - Vault を Kubernetes クラスタ外で実行している場合は、有効期間の長いサービスアカウントトークンを作成し、Vault に提供できます。
✅ は、token_reviewer_jwt
パラメータを設定した場合に有効になります。 - Vault を Kubernetes クラスタ外で実行している場合は、cert-manager によって提供される JWT トークンを再利用して Vault に認証できます。 この場合、その JWT トークンの audience には、Kubernetes API サーバーの audience も含まれている必要があります。
✅ は、token_reviewer_jwt
パラメータが省略され、Vault が Kubernetes クラスタ内で実行されていない場合に有効になります。
vault auth enable -path=kubernetes-cluster001 kuberneteskubectl config view --minify --flatten -ojson \| jq -r '.clusters[].cluster."certificate-authority-data"' \| base64 -d >/tmp/cacrtvault write auth/kubernetes-cluster001/config \kubernetes_host=<kubernetes-api-server-url> \kubernetes_ca_cert=@/tmp/cacrt
注: Vault が Kubernetes クラスタ外で実行されている場合は、
token_reviewer_jwt
トークンを提供できます。これは、Vault が Kubernetes API サーバーに認証するために使用されます。 このトークンは、ここで説明されているように取得できる有効期間の長いサービスアカウントトークンにすることができます。 トークンが、TokenReview API を呼び出すために必要な権限を持つサービスアカウントにリンクされていることを確認してください。 vault コマンドは次のようになります。vault write auth/kubernetes-cluster001/config \token_reviewer_jwt="<TokenReview API SA token>"kubernetes_host=<kubernetes-api-server-url> \kubernetes_ca_cert=@/tmp/cacrt
次に、Kubernetes サービスアカウントと一致する Vault ロールを作成します。
kubectl create serviceaccount -n sandbox vault-issuer
次に、cert-manager がサービスアカウントのトークンを取得できるように RBAC ロールを追加します。
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: vault-issuernamespace: sandboxrules:- apiGroups: ['']resources: ['serviceaccounts/token']resourceNames: ['vault-issuer']verbs: ['create']---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: vault-issuernamespace: sandboxsubjects:- kind: ServiceAccountname: cert-managernamespace: cert-managerroleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: vault-issuer
次に、Vault ロールを作成します。
vault write auth/kubernetes/role/vault-issuer-role \bound_service_account_names=vault-issuer \bound_service_account_namespaces=sandbox \audience="vault://sandbox/vault-issuer" \policies=default \ttl=1m
Issuer または ClusterIssuer ごとに異なる Vault ロールを使用することをお勧めします。 audience
を使用すると、Vault ロールを単一の Issuer または ClusterIssuer に制限できます。 構文は次のとおりです。
"vault://<namespace>/<issuer-name>" # For an Issuer."vault://<cluster-issuer-name>" # For a ClusterIssuer.
最後に、Issuer を作成できます。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: vault-issuernamespace: sandboxspec:vault:path: pki_int/sign/example-dot-comserver: https://vault.localauth:kubernetes:role: vault-issuer-rolemountPath: /v1/auth/kubernetes-cluster001serviceAccountRef:name: vault-issuer
注: cert-manager によって提供される JWT トークンを再利用して Vault に認証する場合は、Kubernetes Vault 認証方式を設定する際に
token_reviewer_jwt
パラメータを省略できます。 ただし、JWT トークンに Kubernetes API サーバーの audience を含めるように cert-manager を追加設定する必要があります。 これは、serviceAccountRef
フィールドのaudiences
フィールドを設定することで行います。 このオプションは、cert-manager >= v1.15.0 でのみ使用できます。KUBE_API_AUDIENCE="$(kubectl create token default | jq -R 'gsub("-";"+") | gsub("_";"/") | split(".") | .[1] | @base64d | fromjson | .aud[0]')"...kubernetes:...serviceAccountRef:name: vault-issueraudiences: [ $KUBE_API_AUDIENCE ]
audiences
を使用する場合、JWT には、生成された audiencevault://namespace/issuer-name
またはvault://cluster-issuer
が引き続き含まれます。 生成された audience は、Vault ロールのアクセスを特定の issuer に制限するのに役立ちます。
Issuer デプロイメントの検証
Vault issuer がデプロイされると、設定が有効であれば ready としてマークされます。 デプロイされているのが clusterissuers
の場合は、以下の issuers
を clusterissuers
に置き換えてください。
Vault issuer は、証明書をリクエストする前に Vault インスタンスが unseal され、初期化されていることを確認するために、v1/sys/health
エンドポイントをクエリすることによって Vault インスタンスをテストします。 そのクエリの結果は、STATUS
列に表示されます。
$ kubectl get issuers vault-issuer -n sandbox -o wideNAME READY STATUS AGEvault-issuer True Vault verified 2m
証明書は、sandbox
名前空間内の vault-issuer
という名前の Vault issuer を使用してリクエストできるようになりました。