Creating a deployer ServiceAccount for your Kubernetes deployment
Kubernetes can be confusing and creating service accounts for deployment is no exception. In this quick guide, I show you how to create an authenticated service account for deploying to Kubernetes!
This is a quick and dirty guide to creating a service account that will allow you to deploy to your Kubernetes cluster, without having to use higher privileged accounts.
To achieve this, you'll need to create a service account (just a name really), a role (what permissions you'd like to grant), a role binding (linking the account and role together) and finally you can create a secret to bring together your Kubernetes context file - which will allow your user to authenticate and bind to a given namespace.
To keep things simple, I always call my deploy user deployer-sa - the primary function of this user is simply to deploy projects to the namespace its been scoped to.
Creating the privileged user
All you need to do is run the below using the kubectl utility and defining the namespace you'd like to scope by. Lets write the below into a file called deployer.yaml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: deployer-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer-role
rules:
- apiGroups: ["", "apps"]
resources: ["deployments", "pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-rb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deployer-role
subjects:
- kind: ServiceAccount
name: deployer-sa
Now, lets run that file against our chosen namespace. The NAMESPACE environment variable that you define is important, because we'll be using it in scripts further down! You also need to make sure you've already created this namespace.
NAMESPACE=your-namespace
# optionally create the namespace
# kubectl create ns $NAMESPACE
kubectl apply -f deployer.yaml -n $NAMESPACE
Once you've done this, you should see something like the below:
serviceaccount/deployer-sa created
role.rbac.authorization.k8s.io/deployer-role created
rolebinding.rbac.authorization.k8s.io/deployer-rb created
Great, we've created our service account, our role and our role binding. We've now got a user that has the privileges to manage and deploy to our namespace! The next problem - creating our context file.
Creating the context file
A context file is the piece of the puzzle that brings together the authentication. Its critical that you keep this safe! To create this, we need to generate a token for our service account, and build out our context file. We'll do this using a series of bash commands. For the purpose of this deployment profile, we'll give the token a lifetime of ~10 years.
# step one: generate our users token and extract it into a variable
USER_TOKEN=$(kubectl create token deployer-sa --duration 90000h --namespace $NAMESPACE -o jsonpath='{.status.token}')
# step two: determine the URL for this cluster
CLUSTER_URL=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# step three: extract the clusters CA certificate data
CA_CERT_DATA=$(kubectl config view --raw -o json | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
# step four: generate our context file using the variables we've defined
cat <<EOF > context.yaml
apiVersion: v1
clusters:
\- cluster:
certificate-authority-data: ${CA_CERT_DATA}
server: ${CLUSTER_URL}
name: ${NAMESPACE}-cluster
contexts:
\- context:
cluster: ${NAMESPACE}-cluster
namespace: ${NAMESPACE}
user: deployer-sa
name: ${NAMESPACE}-context
current-context: ${NAMESPACE}-context
kind: Config
preferences: {}
users:
\- name: deployer-sa
user:
token: ${USER_TOKEN}
EOF
This command will write the context file to the current directory in a file called context.yaml.
And that's it! Using this context file, you'll be able to deploy to your cluster but only for the namespace we defined. Happy deploying!