Simple tutorial to setup a very basic Vault auth with Kubernetes. The following sample will
VAULT_TOKEN.This tutorial is very basic and just setups a simple configuration. For anything else, please see Vault Agent with Kubernetes and the blog “Announcing First-Class Kubernetes Support for HashiCorp Products”.
You can find the source here
You’ll need on your local system:
minikube start
minikube dashboard
https://www.vaultproject.io/docs/platform/k8s/run.html#installing-vault
git clone https://github.com/hashicorp/vault-helm.git
cd vault-helm
git checkout v0.1.2
helm init
# Wait for `tiller-deployment`
# kubectl get deployment -n kube-system
helm install --name=vault --set='server.dev.enabled=true' .
$ kubectl get statefulset,po
NAME                     READY   AGE
statefulset.apps/vault   1/1     29s
NAME          READY   STATUS    RESTARTS   AGE
pod/vault-0   1/1     Running   0          29s
$ kubectl exec -it vault-0 -- vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.2.2
Cluster Name    vault-cluster-6ecc74d7
Cluster ID      9dcc3b81-8939-cdbf-66d8-04a5ed454129
HA Enabled      false
The root Token in --dev mode here is “root”
$ kubectl logs vault-0
Unseal Key: Ndy4bIyqTNYyuPjxU16AB0ILMv7ZkpgshrfhGPINw6I=
Root Token: root
In a new window, create a tunnel to the Vault pod and export the required ENV vars
$ kubectl port-forward vault-0 8200:8200 & 
$ export VAULT_TOKEN=root
$ export VAULT_ADDR='http://localhost:8200'
$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.2.2
Cluster Name    vault-cluster-6ecc74d7
Cluster ID      9dcc3b81-8939-cdbf-66d8-04a5ed454129
HA Enabled      false
Check if vault Service Accounts are created
$  kubectl get secrets,serviceaccounts
NAME                         TYPE                                  DATA   AGE
secret/default-token-qc6cs   kubernetes.io/service-account-token   3      54m
secret/vault-token-ghg9n     kubernetes.io/service-account-token   3      25m
NAME                     SECRETS   AGE
serviceaccount/default   1         54m
serviceaccount/vault     1         25m
This will allow Vault’s Service account (serviceaccount/vault ) permissions to check authorizations:
system:auth-delegator: Allows delegated authentication and authorization checks. This is commonly used by add-on API servers for unified authentication and authorization.
cat <<EOF > vault-auth-service-account.yaml
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
  namespace: default
EOF
kubectl apply -f vault-auth-service-account.yaml
We are creating two ServiceAccounts here
vault-auth: This service account will run in a POD that will have access to Vaultpod-auth:  This is just a test ServiceAccount that is bound to a kubernetes Role that allows list access to Podscat <<EOF > role-binding.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-auth
  namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-robot
  namespace: default
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: role-pod-reader-binding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader-role
subjects:
- kind: ServiceAccount
  name: pod-robot
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader-role
rules:
- apiGroups: [""] 
  resources: ["pods"]
  verbs: ["list"]
EOF
kubectl apply -f role-binding.yaml 
Now create the Pods that will have these ServiceAccounts bound to them.
cat <<EOF > pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: echoserver
spec:
  containers:
  - image: k8s.gcr.io/echoserver:1.10
    name: echoserver
    env:
      - name: MY_POD_SERVICE_ACCOUNT
        valueFrom:
          fieldRef:
            fieldPath: spec.serviceAccountName
  serviceAccountName: pod-robot
  automountServiceAccountToken: true
---
apiVersion: v1
kind: Pod
metadata:
  name: vaultclient
spec:
  containers:
  - image: k8s.gcr.io/echoserver:1.10
    name: vaultclient
  serviceAccountName: vault-auth
  automountServiceAccountToken: true
EOF
kubectl apply -f pod.yaml 
Enable Vault Kubernetes auth configure with the kubernetes master.  Specify the ServiceAccount JWT to use to
authenticate itself to the master (in our case, its the vault Kubernetes Service account we setup earler)
export VAULT_SA_NAME=$(kubectl get sa vault -o jsonpath="{.secrets[*]['name']}")
export SA_JWT_TOKEN=$(kubectl get secret $VAULT_SA_NAME -o jsonpath="{.data.token}" | base64 --decode; echo)
export SA_CA_CRT=$(kubectl get secret $VAULT_SA_NAME -o jsonpath="{.data['ca\.crt']}" | base64 --decode; echo)
export K8S_HOST=$(minikube ip)
echo $VAULT_SA_NAME
echo $SA_JWT_TOKEN
echo $SA_CA_CRT
echo $K8S_HOST
Now enable the kv secret and kubernetes auth and bootstrap its config
vault secrets enable -version=2  -path=kv kv
vault auth enable kubernetes
vault write auth/kubernetes/config \
        token_reviewer_jwt="$SA_JWT_TOKEN" \
        kubernetes_host="https://$K8S_HOST:8443" \
        kubernetes_ca_cert="$SA_CA_CRT"
At this point, Vault is configured to understand and process a JWT provided to it that represents any other kubernetes service account.  The other service account in this case will be the vault-auth service account we specified earlier.
Configure an arbitrary kv endpoint for testing in vault
cat <<EOF > myapp-kv-ro.hcl
path "kv" {                                                                                                                                                 
    capabilities = ["list"]                                                                                                                                  
}                                                                                                                                                            
                                                                                                                                                             
path "kv/data/message" {
    capabilities = ["create", "update", "delete", "list", "read"]
}
EOF
Then bind the policy to the auth/kubernetes/role/example such that it will accept a JWT for vault-auth and return a policy for myapp-kv-ro
vault policy write myapp-kv-ro  myapp-kv-ro.hcl
vault write auth/kubernetes/role/example \
        bound_service_account_names=vault-auth \
        bound_service_account_namespaces=default \
        policies=myapp-kv-ro \
        ttl=24h
First make sure everythinhg is running
kubectl get po,roles,rolebinding,deployments,serviceaccounts,secrets
NAME              READY   STATUS    RESTARTS   AGE
pod/echoserver    1/1     Running   0          27m
pod/vault-0       1/1     Running   0          69m
pod/vaultclient   1/1     Running   0          27m
NAME                                             AGE
role.rbac.authorization.k8s.io/pod-reader-role   27m
NAME                                                            AGE
rolebinding.rbac.authorization.k8s.io/role-pod-reader-binding   27m
NAME                        SECRETS   AGE
serviceaccount/default      1         99m
serviceaccount/pod-robot    1         27m
serviceaccount/vault        1         69m
serviceaccount/vault-auth   1         27m
NAME                            TYPE                                  DATA   AGE
secret/default-token-qc6cs      kubernetes.io/service-account-token   3      99m
secret/pod-robot-token-zckrp    kubernetes.io/service-account-token   3      27m
secret/vault-auth-token-9qlsf   kubernetes.io/service-account-token   3      27m
secret/vault-token-ghg9n        kubernetes.io/service-account-token   3      69m
statefulset

pods

services

statefulset

Now acquire a shell to the vaultclient pod
kubectl exec -it vaultclient -- /bin/bash
Install a utility and get the serviceAccount bound to this pod
apt-get update && apt-get install jq -y
export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
Decode the token at jwt.io to see
{
  "alg": "RS256",
  "kid": ""
}.
{
  "iss": "kubernetes/serviceaccount",
  "kubernetes.io/serviceaccount/namespace": "default",
  "kubernetes.io/serviceaccount/secret.name": "vault-auth-token-9qlsf",
  "kubernetes.io/serviceaccount/service-account.name": "vault-auth",
  "kubernetes.io/serviceaccount/service-account.uid": "a232e082-de67-11e9-9174-e89a62c2a346",
  "sub": "system:serviceaccount:default:vault-auth"
}
Then use it to call the vault service
curl  -s  --request POST  \
     --data "{\"jwt\": \"$TOKEN\", \"role\": \"example\"}"  \
     http://vault:8200/v1/auth/kubernetes/login | jq '.' 
should give:
{
  "request_id": "30fc837f-a7c3-64e2-c916-885d343fb9ab",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": null,
  "wrap_info": null,
  "warnings": null,
  "auth": {
    "client_token": "s.aZ4OqO756iocvGNWGtMlM0FK",
    "accessor": "MsENzypoKt8lxSbVq4cKA0rS",
    "policies": [
      "default",
      "myapp-kv-ro"
    ],
    "token_policies": [
      "default",
      "myapp-kv-ro"
    ],
    "metadata": {
      "role": "example",
      "service_account_name": "vault-auth",
      "service_account_namespace": "default",
      "service_account_secret_name": "vault-auth-token-9qlsf",
      "service_account_uid": "a232e082-de67-11e9-9174-e89a62c2a346"
    },
    "lease_duration": 86400,
    "renewable": true,
    "entity_id": "a8d0b397-1d8d-d992-8985-b768613fe88f",
    "token_type": "service",
    "orphan": true
  }
}
Notice that we just returned a Vault token givne a kubernetes token.
In a new window, export the token and attempt to use it with the kv service
export VAULT_ADDR='http://localhost:8200'
export VAULT_TOKEN=s.aZ4OqO756iocvGNWGtMlM0FK
$ vault kv put kv/message foo=world
Key              Value
---              -----
created_time     2019-09-24T01:47:27.389037577Z
deletion_time    n/a
destroyed        false
version          1
$ vault kv get kv/message
====== Metadata ======
Key              Value
---              -----
created_time     2019-09-24T01:47:27.389037577Z
deletion_time    n/a
destroyed        false
version          1
=== Data ===
Key    Value
---    -----
foo    world
This step is entirely optional and not even related to Vault.  All we re doing here is accessing the k8s api from a POD.  SPecifically, we’ve granted a pod echoserver a serviceAccount pod-robot the ability to list pods
In a new window, exec to the echoserver pod and invoke the k8s API server
 kubectl exec -it echoserver -- /bin/bash
curl -v --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/default/pods
If you attempt to recall any other resource, you’ll see an error (thats expected!)
If you are interested in Vault integration to GCP (just secrets and auth), see Vault auth and secrets on GCP.
This site supports webmentions. Send me a mention via this form.