Create a ServiceAccount, a Token, Role and RoleBinding¶
Tip
This guide will walk you through setting up kind
and Vault
and its Kubernetes Secret Engine to create a ServiceAccount, Token, Role and RoleBinding.
Prerequisites¶
You will need the following tools to be installed:
Setup kind
¶
cat <<EOF >>kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerAddress: "127.0.0.1"
apiServerPort: 6443
EOF
kind create cluster --config=kind-config.yaml
you should now be able to run kubectl
commands:
kubectl get ns
NAME STATUS AGE
default Active 64m
kube-node-lease Active 64m
kube-public Active 64m
kube-system Active 64m
local-path-storage Active 63m
Configure Vault
access¶
The following manifest, creates a ServiceAccount vault-auth
and assigns it the role role-creator
, which allows to create Service Account, Tokens, Roles and RoleBindings.
Tip
This Service Account is going to be used by Vault
Note
**Kubernetes prevents users (including service accounts) from granting RBAC permissions they do not already have themselves.
Thats why we have to assign bind
and escalate
as verbs
for roles
and rolebindings
.
cat <<EOF | kubectl apply -f -
# SA used by vault to create new service account + token
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-auth
automountServiceAccountToken: true
---
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: vault-auth-token
annotations:
kubernetes.io/service-account.name: vault-auth
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-creator
rules:
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["create"]
- apiGroups: [""]
resources: ["serviceaccounts/token"]
verbs: ["create"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles"]
verbs: ["bind", "create", "update", "delete", "escalate"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["bind", "create", "update", "delete", "escalate"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: service-account-creator-binding
subjects:
- kind: ServiceAccount
name: vault-auth
roleRef:
kind: Role
name: role-creator
apiGroup: rbac.authorization.k8s.io
EOF
Configure Vault
¶
Lastly, we will need to start and configure a local Vault Server
:
Authenticate to Vault
and check with vault status
:
export VAULT_ADDR="http://127.0.0.1:8200"
export VAULT_TOKEN="root"
> vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 1
Threshold 1
Version 1.18.3
Build Date 2024-12-16T14:00:53Z
Storage Type inmem
Cluster Name vault-cluster-4cab3957
Cluster ID 597257da-8e8d-6147-c379-e93e3a6013c7
HA Enabled false
Now, we will configure the Kubernetes Secrets Engine to connect to the local kind
Cluster with the vault-auth
ServiceAccount and create a role kind
that will create the ServiceAcccount, Token, Role and RoleBinding:
Tip
The role allows to list all pods in the default namespace
Important
Note the generated_role_rules
#!/usr/bin/env bash
set -ex
K8S_JWT_TOKEN=$(kubectl get secret vault-auth-token -o jsonpath="{.data.token}" | base64 -d)
K8S_CA_CERT=$(kubectl get secret vault-auth-token -o jsonpath="{['data']['ca\.crt']}" | base64 -d)
vault secrets enable kubernetes
vault write -f kubernetes/config \
kubernetes_host="https://127.0.0.1:6443" \
kubernetes_ca_cert="$K8S_CA_CERT" \
service_account_jwt="$K8S_JWT_TOKEN"
vault write kubernetes/roles/kind \
allowed_kubernetes_namespaces="default" \
generated_role_rules='{"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["list"]}]}' \
token_default_ttl="10m"
Putting it together¶
Write kind
s kubeconfig
to a file:
and update it, to use kubectl-vault-login
for authentication:
KUBECONFIG=./kubeconfig.yml kubectl config set-credentials vault \
--exec-interactive-mode=Never \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-command=kubectl \
--exec-arg=vault-login
--exec-arg=--role=kind
> cat kubeconfig.yml
[...]
users:
- name: vault
user:
exec:
apiVersion: client.authentication.k8s.io/v1
args:
- vault-login
- --role=kind
command: kubectl
env: null
interactiveMode: Never
provideClusterInfo: false
# create a pod to see some results
> kubectl run nginx --image=nginx
# use the updated kubeconfig to list pods in the default namespace
> KUBECONFIG=kubeconfig.yml kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 73s
You can also use curl
to communicate with the Kubernetes API directly:
> curl -sk \
-H "Authorization: Bearer $(./kubectl-vault-login -r kind | jq -r .status.token)" \
$(kubectl config view --minify -o 'jsonpath={.clusters[].cluster.server}')/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "707"
},
"items": []
}
The role allows listing pods for the default
namespace, but not for kube-system
:
> KUBECONFIG=kubeconfig.yml k get pod -n kube-config
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:v-token-kind-1739680669-u5x0uqreffqt8hf2qdydpksf" cannot list resource "pods" in API group "" in the namespace "kube-system"
Teardown¶
Tear everything down by running: