新着情報:TwitterMastodonでプロジェクトの最新情報を入手してください。

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/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: sandbox
spec:
vault:
path: pki_int/sign/example-dot-com
server: https://vault.local
caBundle: <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 \
--insecure
step 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 \
--insecure
step 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.yaml
global:
tlsDisable: false
injector:
enabled: false
server:
dataStorage:
enabled: false
standalone:
enabled: true
config: |
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_disable = false
tls_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.crt
VAULT_TLSKEY: /vault/tls/server.key
VAULT_CLIENT_CERT: /vault/tls/client.crt
VAULT_CLIENT_KEY: /vault/tls/client.key
volumes:
- name: vault-tls
secret:
defaultMode: 420
secretName: vault-tls
volumeMounts:
- mountPath: /vault/tls
name: vault-tls
readOnly: 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 kubernetes
kubectl -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=1m
kubectl -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.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: vault-issuer
namespace: application-1
rules:
- apiGroups: ['']
resources: ['serviceaccounts/token']
resourceNames: ['vault-issuer']
verbs: ['create']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: vault-issuer
namespace: application-1
subjects:
- kind: ServiceAccount
name: cert-manager
namespace: cert-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: 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.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: application-1
spec:
vault:
path: pki_int/sign/application-1
server: https://vault.vault:8200
caBundleSecretRef:
key: server_ca.crt
name: vault-client-tls
clientCertSecretRef:
name: vault-client-tls
key: client.crt
clientKeySecretRef:
name: vault-client-tls
key: client.key
auth:
kubernetes:
role: vault-issuer
mountPath: /v1/auth/kubernetes
serviceAccountRef:
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 構成
AppRoleA. Vault AppRole での認証
トークンB. Vault トークンでの認証
JWT/OIDCC. Kubernetes サービスアカウントでの認証 > JWT/OIDC 認証を使用する
KubernetesC. Kubernetes サービスアカウントでの認証 > Kubernetes 認証を使用する

A. AppRole を使用した認証

AppRole は、内部ロールポリシーシステムを使用して Vault に対して認証する方法です。 この認証方法では、発行者がSecretID秘密鍵、引き受けるロールのRoleID、およびアプリロールパスを所有している必要があります。 まず、秘密IDキーは、Issuer と同じ名前空間に存在する Kubernetes Secret 内に、またはClusterIssuer の場合はCluster Resource Namespace 内に保存する必要があります。

apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: cert-manager-vault-approle
namespace: sandbox
data:
secretId: "MDI..."

Secret が作成されると、この Secret と、秘密 ID を格納するフィールドのデータキーを参照する Issuer をデプロイする準備が整います。

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: sandbox
spec:
vault:
path: pki_int/sign/example-dot-com
server: https://vault.local
caBundle: <base64 encoded caBundle PEM file>
auth:
appRole:
path: approle
roleId: "291b9d21-8ff5-..."
secretRef:
name: cert-manager-vault-approle
key: secretId

B. トークンを使用した認証

この認証方法は、Vault がサポートする多くの認証バックエンドのいずれかから生成されたトークン文字列を使用します。 これらのトークンには有効期限があるため、定期的に更新する必要があります。 Vault トークンの詳細については、こちら をご覧ください。

**注**: cert-manager はこれらのトークンを自動的に更新しないため、これを行うための別のプロセスを導入する必要があります。

まず、トークンは、Issuer と同じ名前空間内、または ClusterIssuer を使用する場合は Cluster Resource Namespace 内の Kubernetes Secret 内に保存されます。

apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: cert-manager-vault-token
namespace: sandbox
data:
token: "MjI..."

送信されると、この Secret と、トークンデータが格納されているフィールドのキーを参照することにより、トークン認証を使用して Vault Issuer を作成できます。

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: sandbox
spec:
vault:
path: pki_int/sign/example-dot-com
server: https://vault.local
caBundle: <base64 encoded caBundle PEM file>
auth:
tokenSecretRef:
name: cert-manager-vault-token
key: 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 jwt
kubectl config view --minify --flatten -ojson \
| jq -r '.clusters[].cluster."certificate-authority-data"' \
| base64 -d >/tmp/cacrt
vault 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/v1
kind: Role
metadata:
name: vault-issuer
namespace: sandbox
rules:
- apiGroups: ['']
resources: ['serviceaccounts/token']
resourceNames: ['vault-issuer']
verbs: ['create']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: vault-issuer
namespace: sandbox
subjects:
- kind: ServiceAccount
name: cert-manager
namespace: cert-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: 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/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: sandbox
spec:
vault:
path: pki_int/sign/example-dot-com
server: https://vault.local
auth:
kubernetes:
role: vault-issuer-role
mountPath: /v1/auth/jwt-cluster001
serviceAccountRef:
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 つの方法があります。

  1. Vault を Kubernetes クラスタ内で実行している場合は、Vault ポッドにマウントされている Kubernetes サービスアカウントトークンを使用できます。
    ✅ は、Vault が Kubernetes クラスタ内で実行されていることを自動検出した場合に有効になります。
  2. Vault を Kubernetes クラスタ外で実行している場合は、有効期間の長いサービスアカウントトークンを作成し、Vault に提供できます。
    ✅ は、token_reviewer_jwt パラメータを設定した場合に有効になります。
  3. Vault を Kubernetes クラスタ外で実行している場合は、cert-manager によって提供される JWT トークンを再利用して Vault に認証できます。 この場合、その JWT トークンの audience には、Kubernetes API サーバーの audience も含まれている必要があります。
    ✅ は、token_reviewer_jwt パラメータが省略され、Vault が Kubernetes クラスタ内で実行されていない場合に有効になります。
vault auth enable -path=kubernetes-cluster001 kubernetes
kubectl config view --minify --flatten -ojson \
| jq -r '.clusters[].cluster."certificate-authority-data"' \
| base64 -d >/tmp/cacrt
vault 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/v1
kind: Role
metadata:
name: vault-issuer
namespace: sandbox
rules:
- apiGroups: ['']
resources: ['serviceaccounts/token']
resourceNames: ['vault-issuer']
verbs: ['create']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: vault-issuer
namespace: sandbox
subjects:
- kind: ServiceAccount
name: cert-manager
namespace: cert-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: 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/v1
kind: Issuer
metadata:
name: vault-issuer
namespace: sandbox
spec:
vault:
path: pki_int/sign/example-dot-com
server: https://vault.local
auth:
kubernetes:
role: vault-issuer-role
mountPath: /v1/auth/kubernetes-cluster001
serviceAccountRef:
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-issuer
audiences: [ $KUBE_API_AUDIENCE ]

audiences を使用する場合、JWT には、生成された audience vault://namespace/issuer-name または vault://cluster-issuer が引き続き含まれます。 生成された audience は、Vault ロールのアクセスを特定の issuer に制限するのに役立ちます。

Issuer デプロイメントの検証

Vault issuer がデプロイされると、設定が有効であれば ready としてマークされます。 デプロイされているのが clusterissuers の場合は、以下の issuersclusterissuers に置き換えてください。

Vault issuer は、証明書をリクエストする前に Vault インスタンスが unseal され、初期化されていることを確認するために、v1/sys/health エンドポイントをクエリすることによって Vault インスタンスをテストします。 そのクエリの結果は、STATUS 列に表示されます。

$ kubectl get issuers vault-issuer -n sandbox -o wide
NAME READY STATUS AGE
vault-issuer True Vault verified 2m

証明書は、sandbox 名前空間内の vault-issuer という名前の Vault issuer を使用してリクエストできるようになりました。