This guide will walk you through how to configure Vault running on a Kubernetes cluster to exchange service accounts for a scoped client vault token. This can be useful when you want your services running on a kubernetes cluster to self auth against vault and not require the need to pass around vault credentials.
Auth Delgators
The first thing we want to setup is a ClusterRoleBinding that has a roleRef which uses system:auth-delagator
This role allows delegated authentication and authorization checks. This is commonly used by add-on API servers for unidified authentication and authorization.
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault-auth
namespace: default
Note change the namespace to something more appropriate than default
Next we can create a service account
which will get bound to this ClusterRoleBinding. Ensure the namespaces for the SA specified in the ClusterRoleBinding and the SA match.
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-auth
namespace: default
Required information
Before we continue to setup vault we need to extra some data from our cluster and newly created service account.
Service Account Token
export VAULT_SA_NAME=$(kubectl get sa vault-auth --output jsonpath="{.secrets[*]['name']}")
Service Account JWT
export SA_JWT_TOKEN=$(kubectl get secret $VAULT_SA_NAME --output 'go-template={{ .data.token }}'| base64 --decode)
Service Account CA CRT
export SA_CA_CRT=$(kubectl config view --raw --minify --flatten --output 'jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
K8 Hostname
export K8S_HOST=$(kubectl config view --raw --minify --flatten --output 'jsonpath={.clusters[].cluster.server}')
JWT Issuer
If the cluster is on K8 1.21+ you must pass in the following
https://kubernetes.default.svc
This is due to changes from 1.21 onward using a different auth method.
Vault Setup
Now we can setup our Kubernetes auth on vault.
In the Access
Section click on enable new method
this will take you to a selection screen. From here click on Kubernetes
.
The path that you should use here is kubernetes
. (This is the default path no need to change it unless we want to add different k8 auth engines).
The next page you will see is the configuration page there are only three fields that need to be filled out
- Kubernetes Host : equal to
echo ${K8S_HOST}
- Kubernetes SA CA Certificate : equal to
echo ${SA_CA_CRT}
- Token Reviewer JWT : equal to
echo ${SA_JWT_TOKEN}
(this is in theKubernetes Options
option)
With this configured there is now a accessible v1/auth/kubernetes/login
endpoint. This is what our services will have to send requests to get back a client token.
Role Setup
This will be on a per service basis as we will need to create policies and roles accordingly.
Here is an example flow of setting up getting a service a scoped token.
Policy creation
Go to the Policies section of vault and click create ACL Policy
give it a name and a policy. Here is a example policy for a path that would already exist on vault. Note that these paths must be created as new engines.
path "my-app/*" {
capabilities = ["read", "list"]
}
Service Account
While every namespace has a default service account that gets attached to a pod if you do not provide one, we will create one for the sake of this guide and the want/need to scope pods to Vault ACLs.
kubectl create sa {MY SA NAME} -n {NAMESPACE}
And lets pretend that this SA gets assigned to our pod.
Now over at Vault when we click view configuration
on our Kubernetes auth in access we get taken to a page where we see two tabs one of which being roles
.
If you click on roles -> create role we have a form that requires to be filled out. The fields we need to fill out are
- Name : name of this role. Let’s name it after the service that uses it
- Bound service account names : This will be the service account name
- Bound service account namespace : Namespace that the service account lives in
- Generated Tokens Policies : Name of the policy to use
Service integration
Now, our services can have scoped identities and no longer require the root client token be passed to them.
Instead we will have to setup the services to initial called /v1/auth/kubernetes/login
with a json body that consists of role
and jwt
- Role : name of role on vault
- JWT : this is the service account token that is mounted to the pod
Upon successfully validation Vault returns a json body that describes your auth status that includes your scoped client token among other things.