3 minutes
Integrate an external Vault with kubernetes
In my homelab I have a couple private git repositories containing some sensitive data. I decided to finally clean this up and install a Vault server where I can safely put my secrets, api-keys, credentials,… The Vault is installed on a VM using the official documentation process.
Vault secret operator (VSO)
Hashicorp created an official operator that can be integrated with a kubernetes cluster. This operator makes it really easy to utilize secrets stored on the Vault server.
Initial steps
I started off by creating a new “secret engine” and some secrets in Vault:
# Create secret engine
vault secrets enable -path=homelab-kube kv-v2
# Create secret
vault kv put kvv2/homelab-kube/testing username="web-user" password="secretPass"
I also need a policy that will be used later on:
# Create policy
vault policy write vso-policy - <<EOF
path "homelab-kube/*" {
capabilities = ["read"]
}
EOF
Next up I need to get some needed credentials from kubernetes and use them to configure the auth method:
# Populate env variables
TOKEN_REVIEW_JWT=$(kubectl get secret vault-auth --output='go-template={{ .data.token }}' | base64 --decode)
KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
KUBE_HOST=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')
# Enable auth method kube
vault auth enable -path=vso kubernetes
# Write config
vault write auth/vso/config \
token_reviewer_jwt="$TOKEN_REVIEW_JWT" \
kubernetes_host="$KUBE_HOST" \
kubernetes_ca_cert="$KUBE_CA_CERT" \
disable_issuer_verification=true
Now I just need a role to read the secrets:
# Creating
vault write auth/vso/role/vso-role \
bound_service_account_names=vault-auth \
bound_service_account_namespaces=default \
policies=vso-policy \
ttl=24h
# Checking
vault list auth/vso/role
vault read auth/vso/role/vso-role
Installation
Now that the initial steps are ready and the connection between Vault and kubernetes is setup, I can install the operator using helm:
# Install operator
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault-secrets-operator hashicorp/vault-secrets-operator
After that I need some resources in the kubernetes cluster:
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: vault-auth
---
apiVersion: v1
kind: Secret
metadata:
namespace: default
name: vault-auth
annotations:
kubernetes.io/service-account.name: vault-auth
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
namespace: default
name: role-tokenreview-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault-auth
namespace: default
This will create a dedicated service account with a secret and the right binding.
And ofcourse it still needs to be applied:
kubectl apply -f resources.yaml
Next up, we will use the newly created CRD’s that we installed using helm:
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
namespace: default
name: vault-connection
spec:
# address to the Vault server.
address: http://xxx:8200
skipTLSVerify: true
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
namespace: default
name: vault-auth
spec:
vaultConnectionRef: vault-connection
method: kubernetes
mount: vso
kubernetes:
role: vso-role
serviceAccount: vault-auth
Also apply this one:
kubectl apply -f crd.yaml
Verification
To check if this all worked, I can try and receive the secret I created in the beginning using a VaultStaticSecret
:
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
namespace: default
name: vault-static-secret
spec:
vaultAuthRef: vault-auth
mount: homelab-kube
type: kv-v2
path: testing
refreshAfter: 10s
destination:
create: true
name: vso-handled
Now apply this and try to receive the created secret:
# Create secret
kubectl apply -f vss.yaml
# Check secret
kubectl get secret vso-handled -o jsonpath='{.data._raw}' | base64 --decode
{"data":{"password":"secretPass","username":"web-user"}...
Succes! I can now store secrets in my Vault and retrieve them inside kubernetes using the VSO.