Introduction 🔗
In this post I describe the steps taken to enable a Kubernetes authentication backend for Hashicorp Vault and configure a PKI role for cert-manager to use to issue certificate signing requests.
Process 🔗
Start by enabling the auth method.
vault auth enable --path=k8s-yourdomain-production kubernetes
You should see:
Success! Enabled kubernetes auth method at: k8s-yourdomain-production/
The cluster needs a ’token reviewer’ service account that Vault can use to validate tokens presented by clients that claim to have been authenticated by the cluster.
The YAML for this is as follows:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: token-reviewer
namespace: cert-manager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: vault-issuer-tokenreview-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: token-reviewer
namespace: cert-manager
---
apiVersion: v1
kind: Secret
metadata:
name: token-reviewer
namespace: cert-manager
annotations:
kubernetes.io/service-account.name: token-reviewer
type: kubernetes.io/service-account-token
This will generate a service account token in the token-reviewer
secret.
And a ClusterIssuer that uses that service token to request certificates from a PKI role in Vault:
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: vault
spec:
vault:
#server: https://vault.yourdomain.lan
server: http://10.68.5.53:8200
path: pki/sign/internal-certs
auth:
kubernetes:
mountPath: /v1/auth/k8s-yourdomain-production
role: cert-manager
secretRef:
name: token-reviewer
key: token
Obtain the token and CA cert.
K8SURL=https://10.96.4.1:6443 # Or whatever
TOKEN=$(kubectl -n cert-manager get secret token-reviewer -ojsonpath='{.data.token}' | base64 -d)
kubectl -n cert-manager get secret token-reviewer -ojsonpath='{.data.ca\.crt}' | base64 -d >ca.crt
Create a policy that allows issuing certs:
cat <<EOF | vault policy write yourdomain-lan-certs /dev/stdin
path "pki/sign/internal-certs" {
capabilities = ["create", "update"]
}
EOF
Also, create the PKI role that will sign the cert.
vault write pki/roles/internal-certs \
allowed_domains="yourdomain.lan" \
allow_subdomains=true \
key_type=ec \
max_ttl="2160h"
Configure the auth method:
vault write auth/k8s-yourdomain-production/config \
token_reviewer_jwt="$TOKEN" \
kubernetes_host="$K8SURL" \
kubernetes_ca_cert="$(cat ca.crt)"
Create an authentication role to identify ‘cert-manager’ on the cluster by it’s presentation of the ’token-reviewer’ token:
vault write auth/k8s-yourdomain-production/role/cert-manager \
bound_service_account_names=token-reviewer \
bound_service_account_namespaces=cert-manager \
policies=yourdomain-lan-certs \
ttl=24h
If all’s well you should now see the ClusterIssuer showing as ‘ready’.
kubectl get clusterissuers
Output should look something like this:
NAME READY AGE
vault True 10h