Vault Agent InjectorでKubernetes認証を試す
前回構築したvault
でkubernetes認証を試してみました。
前回構築した時は意識してませんでしたが
Vault Agent Injector
がデプロイされたのでそれを使います。
vault側の準備
Vault Agent Injectorの使い方は こちら を参考にさせていただきました。
まずvaultにsecretを作成します。
ubuntu@k8s1:~$ vault secrets enable -path=secret -description="my-secret" kv-v2
Success! Enabled the kv-v2 secrets engine at: secret/
ubuntu@k8s1:~$ vault kv put secret/my-app password=supersecret!
=== Secret Path ===
secret/data/my-app
======= Metadata =======
Key Value
--- -----
created_time 2025-05-31T09:14:45.104709193Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
ubuntu@k8s1:~$ vault kv get secret/my-app
=== Secret Path ===
secret/data/my-app
======= Metadata =======
Key Value
--- -----
created_time 2025-05-31T09:14:45.104709193Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password supersecret!
このpasswordをアノテーションでPodにマウントする感じです。
Kubernetes認証を設定します。
ubuntu@k8s1:~$ vault auth enable -description="my-cluster" kubernetes
Success! Enabled kubernetes auth method at: kubernetes/
ubuntu@k8s1:~$ vault auth list
Path Type Accessor Description Version
---- ---- -------- ----------- -------
kubernetes/ kubernetes auth_kubernetes_c14da5d7 my-cluster n/a
token/ token auth_token_f5c2071f token based credentials n/a
ubuntu@k8s1:~$ vault write auth/kubernetes/config kubernetes_host="https://kubernetes.default.svc.cluster.local:443"
Success! Data written to: auth/kubernetes/config
ubuntu@k8s1:~$ vault read auth/kubernetes/config
Key Value
--- -----
disable_iss_validation true
disable_local_ca_jwt false
issuer n/a
kubernetes_ca_cert n/a
kubernetes_host https://kubernetes.default.svc.cluster.local:443
pem_keys []
token_reviewer_jwt_set false
use_annotations_as_alias_metadata false
ubuntu@k8s1:~$ vault policy write my-policy - <<EOF
path "secret/data/my-app" {
capabilities = ["read"]
}
EOF
Success! Uploaded policy: my-policy
ubuntu@k8s1:~$ vault policy read my-policy
path "secret/data/my-app" {
capabilities = ["read"]
}
ubuntu@k8s1:~$ vault write auth/kubernetes/role/my-role bound_service_account_names=my-sa bound_service_account_namespaces=default policies=my-policy ttl=20m
Success! Data written to: auth/kubernetes/role/my-role
ubuntu@k8s1:~$ vault read auth/kubernetes/role/my-role
Key Value
--- -----
alias_name_source serviceaccount_uid
bound_service_account_names [my-sa]
bound_service_account_namespace_selector n/a
bound_service_account_namespaces [default]
policies [my-policy]
token_bound_cidrs []
token_explicit_max_ttl 0s
token_max_ttl 0s
token_no_default_policy false
token_num_uses 0
token_period 0s
token_policies [my-policy]
token_ttl 20m
token_type default
ttl 20m
試しにpodを起動してみます。
まずロール作成時に指定した名前とnamespaceでサービスアカウントを作成します。
ubuntu@k8s1:~$ kubectl create sa my-sa
serviceaccount/my-sa created
マニフェストは以下にしました。
こうすると/vault/secrets/my-appにマウントされます。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
annotations:
vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/role: 'my-role'
vault.hashicorp.com/agent-inject-secret-my-app: 'secret/my-app'
labels:
run: vault-test
name: vault-test
spec:
serviceAccountName: my-sa
containers:
- image: nginx
name: vault-test
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
無事起動しました。
ubuntu@k8s1:~$ k get pod -w
NAME READY STATUS RESTARTS AGE
vault-test 0/2 Init:0/1 0 7s
vault-test 0/2 PodInitializing 0 9s
vault-test 2/2 Running 0 13s
無事マウントされました。
ubuntu@k8s1:~$ k exec -it vault-test -c vault-test -- cat /vault/secrets/my-app
data: map[password:supersecret!]
metadata: map[created_time:2025-05-31T09:14:45.104709193Z custom_metadata:<nil> deletion_time: destroyed:false version:1]
これでsecretを使わなくても機密情報をPodにマウントできますね。
環境変数とかでマウントしたい場合は
サンプル
をご確認ください。
外部のvault serverからVault Agent InjectorでKubernetes認証を試す
上記は同じクラスタ内で試したのですが、
vaultとアプリは別のクラスタの場合が多いのではないかと思います。
今手元にある別のクラスタはk3sで構築したrancher用クラスタがあるのでそれを使いました。
root@rancher:~# k get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
rancher Ready control-plane,etcd,master 322d v1.27.10+k3s2 192.168.0.208 <none> Ubuntu 24.04 LTS 6.8.0-51-generic containerd://1.7.11-k3s2.27
構築方法は
こちら
にドキュメントがありました。
これを参考にrancherクラスタにVault Agent Injectorのみをインストールします。
root@rancher:~# helm repo add hashicorp https://helm.releases.hashicorp.com
root@rancher:~# helm repo update
設定は以下にしました。
root@rancher:~# cat override-vault-values.yaml
global:
externalVaultAddr: "http://vault.tsuchinokometal.com"
injector:
authPath: "auth/rancher-cluster"
logFormat: "json"
metrics:
enabled: true
externalVaultAddrには
前回vault serverを構築したとき
に
serverをingressで外部公開したのでそのホストを指定しています。
また、authpathはわかりやすいように変えておきます。
インストールします。
root@rancher:~# helm install vault hashicorp/vault --create-namespace -n vault --values override-vault-values.yaml
NAME: vault
LAST DEPLOYED: Sun Jun 1 12:00:02 2025
NAMESPACE: vault
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Thank you for installing HashiCorp Vault!
Now that you have deployed Vault, you should look over the docs on using
Vault with Kubernetes available here:
https://developer.hashicorp.com/vault/docs
Your release is named vault. To learn more about the release, try:
$ helm status vault
$ helm get manifest vault
root@rancher:~# k get pod -n vault
NAME READY STATUS RESTARTS AGE
vault-agent-injector-56dd76fc4f-9rzqp 1/1 Running 0 22m
ドキュメントの通りhelmでサービスアカウントが作成されているのでトークンを作成します。
root@rancher:~# cat > vault-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: vault-token-g955r
namespace: vault
annotations:
kubernetes.io/service-account.name: vault
type: kubernetes.io/service-account-token
EOF
root@rancher:~# kubectl apply -f vault-secret.yaml
secret/vault-token-g955r created
root@rancher:~# kubectl describe serviceaccount vault -n vault
Name: vault
Namespace: vault
Labels: app.kubernetes.io/instance=vault
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=vault
helm.sh/chart=vault-0.30.0
Annotations: meta.helm.sh/release-name: vault
meta.helm.sh/release-namespace: vault
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: vault-token-g955r
Events: <none>
root@rancher:~# VAULT_HELM_SECRET_NAME=$(kubectl get secrets --output=json -n vault | jq -r '.items[].metadata | select(.name|startswith("vault-token-")).name')
root@rancher:~# kubectl describe secret $VAULT_HELM_SECRET_NAME -n vault
Name: vault-token-g955r
Namespace: vault
Labels: <none>
Annotations: kubernetes.io/service-account.name: vault
kubernetes.io/service-account.uid: 91c16dad-0908-4c62-94b8-689312750828
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 570 bytes
namespace: 5 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjB4bFcta0NmR0FveXpJc3h1eGpHb2drNF9kQWcxek1lc1JvaXcyLTdRTFUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJ2YXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJ2YXVsdC10b2tlbi1nOTU1ciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ2YXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjkxYzE2ZGFkLTA5MDgtNGM2Mi05NGI4LTY4OTMxMjc1MDgyOCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDp2YXVsdDp2YXVsdCJ9.vykuTChl_qGA7kTEAFkVPkmOMdsWvoi4ht6p-YnWZ6Wx6fWeZmLAkCtdMlbeub03E9d9cmw1K7apQdgiUXFTtyS_AnfdfltwIe-ZmcKFZwDJh4VKjSFb5g85ZkUtVwrxhy_1OlL0E38uC0HAY5FEHd5znv10fa1nGEkpI2PXZtQu5rTrVQM5WBJEZCd_GyAC6nLYcblDaNvvD8tf3tYGvfp8Z2Z1-qO-9lMOwchGzR81wHDYQJIGP7nw82VWZrQMkeo5pmrv2zFmpIIeAa8UC-12B3vfmOdxbiCHqYkn_fNmoDsKvk0P2Xa2cPzbRffWtFC4v544OctILcJaUWLZsg
vault CLIをインストールしてまずはsecretを登録します。
インストールの仕方は
こちら
を参考にしてください。
シークレットもドキュメント通りにしています。
root@rancher:~# vault kv put secret/devwebapp/config username='giraffe' password='salsa'
root@rancher:~# vault kv get -format=json secret/devwebapp/config | jq ".data.data"
{
"password": "salsa",
"username": "giraffe"
}
root@rancher:~# vault policy write devwebapp - <<EOF
path "secret/data/devwebapp/config" {
capabilities = ["read"]
}
EOF
Success! Uploaded policy: devwebapp
kubernetes認証を設定します。
インストール時に指定したauthpathと一致するようにパスを変えています。
root@rancher:~# vault auth enable --path=rancher-cluster kubernetes
Success! Enabled kubernetes auth method at: rancher-cluster/
root@rancher:~# TOKEN_REVIEW_JWT=$(kubectl get secret $VAULT_HELM_SECRET_NAME -n vault --output='go-template={{ .data.token }}' | base64 --decode)
root@rancher:~# KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
root@rancher:~# KUBE_HOST=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')
root@rancher:~# vault write auth/rancher-cluster/config token_reviewer_jwt="$TOKEN_REVIEW_JWT" kubernetes_host="$KUBE_HOST" kubernetes_ca_cert="$KUBE_CA_CERT" issuer="https://kubernetes.default.svc.cluster.local"
Success! Data written to: auth/rancher-cluster/config
root@rancher:~# vault read auth/rancher-cluster/config
Key Value
--- -----
disable_iss_validation true
disable_local_ca_jwt false
issuer https://kubernetes.default.svc.cluster.local
kubernetes_ca_cert -----BEGIN CERTIFICATE-----
MIIBdzCCAR2gAwIBAgIBADAKBggqhkjOPQQDAjAjMSEwHwYDVQQDDBhrM3Mtc2Vy
dmVyLWNhQDE3MjA4NDgzOTcwHhcNMjQwNzEzMDUyNjM3WhcNMzQwNzExMDUyNjM3
WjAjMSEwHwYDVQQDDBhrM3Mtc2VydmVyLWNhQDE3MjA4NDgzOTcwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAASnJQQR/SpCe2mYi9QK32KDFGeuhV/Ee/aa+zqJVeeH
bfxEHji3MSleWILTt3LH5Ah9tge7XDb3TleIyivtRS35o0IwQDAOBgNVHQ8BAf8E
BAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOzXSamwjsbkRapEF2k/H
NrIXyj8wCgYIKoZIzj0EAwIDSAAwRQIhALIxIbuBBrcCHi0Cimo3AQZNpURfIXKt
cnS/Zd4h0VXzAiBwkjymuUxSMXEmdfdFh8+YASNT4wysiUT4NC4xFt2NJg==
-----END CERTIFICATE-----
kubernetes_host https://127.0.0.1:6443
pem_keys []
token_reviewer_jwt_set true
use_annotations_as_alias_metadata false
kubernetes_hostが127.0.0.1ですね。
ここはVault Agent Injectorがいるクラスタじゃないといけないようです。
みたところKubernetes APIには外部からアクセスできるようです。
root@rancher:~# lsof -i:6443 | grep LISTEN
k3s-serve 3816535 root 7u IPv6 886731924 0t0 TCP *:6443 (LISTEN)
なのでコントロールノードのIPに書き換えます。
root@rancher:~# vault write auth/rancher-cluster/config token_reviewer_jwt="$TOKEN_REVIEW_JWT" kubernetes_host="https://192.168.0.208:6443" kubernetes_ca_cert="$KUBE_CA_CERT" issuer="https://kubernetes.default.svc.cluster.local"
Success! Data written to: auth/rancher-cluster/config
root@rancher:~# vault read auth/rancher-cluster/config
Key Value
--- -----
disable_iss_validation true
disable_local_ca_jwt false
issuer https://kubernetes.default.svc.cluster.local
kubernetes_ca_cert -----BEGIN CERTIFICATE-----
MIIBdzCCAR2gAwIBAgIBADAKBggqhkjOPQQDAjAjMSEwHwYDVQQDDBhrM3Mtc2Vy
dmVyLWNhQDE3MjA4NDgzOTcwHhcNMjQwNzEzMDUyNjM3WhcNMzQwNzExMDUyNjM3
WjAjMSEwHwYDVQQDDBhrM3Mtc2VydmVyLWNhQDE3MjA4NDgzOTcwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAASnJQQR/SpCe2mYi9QK32KDFGeuhV/Ee/aa+zqJVeeH
bfxEHji3MSleWILTt3LH5Ah9tge7XDb3TleIyivtRS35o0IwQDAOBgNVHQ8BAf8E
BAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOzXSamwjsbkRapEF2k/H
NrIXyj8wCgYIKoZIzj0EAwIDSAAwRQIhALIxIbuBBrcCHi0Cimo3AQZNpURfIXKt
cnS/Zd4h0VXzAiBwkjymuUxSMXEmdfdFh8+YASNT4wysiUT4NC4xFt2NJg==
-----END CERTIFICATE-----
kubernetes_host https://192.168.0.208:6443
pem_keys []
token_reviewer_jwt_set true
use_annotations_as_alias_metadata false
ロールを作成します。
root@rancher:~# vault write auth/rancher-cluster/role/devweb-app bound_service_account_names=internal-app bound_service_account_namespaces=default policies=devwebapp ttl=24h
Success! Data written to: auth/rancher-cluster/role/devweb-app
root@rancher:~# vault read auth/rancher-cluster/role/devweb-app
Key Value
--- -----
alias_name_source serviceaccount_uid
bound_service_account_names [internal-app]
bound_service_account_namespace_selector n/a
bound_service_account_namespaces [default]
policies [devwebapp]
token_bound_cidrs []
token_explicit_max_ttl 0s
token_max_ttl 0s
token_no_default_policy false
token_num_uses 0
token_period 0s
token_policies [devwebapp]
token_ttl 24h
token_type default
ttl 24h
ではpodにマウントしてみます。
サービスアカウントを作成します。
root@rancher:~# kubectl create sa internal-app
serviceaccount/internal-app created
マニフェストはドキュメントと同じ内容にしました。
root@rancher:~# cat pod-devwebapp-with-annotations.yaml
apiVersion: v1
kind: Pod
metadata:
name: devwebapp-with-annotations
labels:
app: devwebapp-with-annotations
annotations:
vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/role: 'devweb-app'
vault.hashicorp.com/agent-inject-secret-credentials.txt: 'secret/data/devwebapp/config'
spec:
serviceAccountName: internal-app
containers:
- name: app
image: burtlo/devwebapp-ruby:k8s
root@rancher:~# kubectl apply --filename pod-devwebapp-with-annotations.yaml
pod/devwebapp-with-annotations created
無事マウントできました。
root@rancher:~# k get pod
NAME READY STATUS RESTARTS AGE
devwebapp-with-annotations 2/2 Running 0 70s
root@rancher:~# kubectl exec -it devwebapp-with-annotations -c app -- cat /vault/secrets/credentials.txt
data: map[password:salsa username:giraffe]
metadata: map[created_time:2025-05-31T12:18:54.282592425Z custom_metadata:<nil> deletion_time: destroyed:false version:1]
ちなみにvault serverのingressのホスト名を、
Vault Agent InjectorのPodが名前解決できないといけないのでご注意を。
クラスタ内のPodが名前解決できるかどうかは
こちら
を参考に確認するとよいと思います。
cat <<EOF | kubectl -n vault apply -f -
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
spec:
containers:
- name: dnsutils
image: registry.k8s.io/e2e-test-images/agnhost:2.39
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
root@rancher:~# kubectl exec -i -t dnsutils -n vault -- nslookup vault.tsuchinokometal.com
Server: 10.43.0.10
Address: 10.43.0.10#53
Name: vault.tsuchinokometal.com
Address: 192.168.0.52