Authorization of developers working on a Kubernetes cluster
When a lot of developers need to work on your Kubernetes cluster, we need a way to:
- identify a single developer
- grant proper permissions to each of them (as a group or as a single user)
- remove/modify grants
In Kubernetes a developer can interact with the API using self-generated certificates, provided that they're signed by the cluster authority certificate. Using certificates we can rely on Kubernetes' built-in mechanisms (RBAC) to fulfill our three requirements.
The following image shows the process involving every single developer and the Kubernetes cluster administrator.
Step 1: as developer
- Create private key for user:
openssl genrsa -out nicola.key 2048
- Create certificate signing request (CSR):
openssl req -new -key nicola.key -out nicola.csr -subj "/CN=nbenaglia@sorint.it/O=devs/O=archs"
Common Name (CN) will be treated by Kubernetes as User
Organization (O) will be treated by Kubernetes as Group (in the above command the developer belongs to two groups)
- Send the CSR to the administrator
Step 2: as K8S admin
- Check the content and the declared groups with the command:
openssl req -new -key nicola.key -out nicola.csr -subj "/CN=nbenaglia@sorint.it/O=devs/O=archs"
The output will be similar to:
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN = nbenaglia@sorint.it, O = devs, O = archs
Subject Public Key Info: [...]
- Download the cluster authority certificate (on your master in /etc/kubernetes/pki/ca.crt), which is a public distributable certificate. You can see its content with the following:
openssl x509 -in ca.crt -noout -text
- Create certificate from CSR using the cluster authority and set certificate expiration:
openssl x509 -req -in nicola.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out nicola.crt -days 500
-
Send ca.crt and nicola.crt to developer
-
Grant the User or the Group in RoleBinding or ClusterRoleBinding.
Take the following file role.yml as example for a role in a namespace devs
:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: devs
name: devs-reader
rules:
- apiGroups: [""]
verbs: ["get", "list"]
resources: ["pods","services"]
kubectl create -f role.yml
Group binding:
kubectl create rolebinding devs-rb -n devs --group devs --role devs-reader
User binding:
kubectl create rolebinding devs-reader-nbenaglia -n devs --user nbenaglia@sorint.it --role devs-reader
Step 3: as developer
- Add the new cluster to kubectl config:
kubectl config set-cluster devs-cluster --certificate-authority=ca.crt --embed-certs=true --server=https://PUBLIC_ADDRESS_OF_CLUSTER:6443
The PUBLIC_ADDRESS_OF_CLUSTER is provided by the k8s admin.
- Add the new credentials to kubectl config:
kubectl config set-credentials nicola --client-certificate=nicola.crt --client-key=nicola.key --embed-certs=true
- Add the new context to kubectl config:
kubectl config set-context dev-nicola --cluster=devs-cluster --user=nicola
- Check the config:
kubectl config view
- Set the context:
kubectl config use-context dev-nicola
Pros and cons
We could set fine-graned permissions for each developer to work on our kubernetes cluster. The above described process, like every solution, has pros and cons:
Pros
- Fine-grained permissions to a single developer or group
- Developer self-generates his private key and CSR
Cons
- Belonging organizations (K8S groups) must be carefully designed before CSR generation
- Admin cannot revoke a single user from a group binding (thanks to Maxim Filatov for the note)
- Admin must check the developer self-generated certificate
- Generation and distribution of a certificate for each developer
- When Kubernetes CA expires, we need to regenerate and redistribute all certificates
Conclusion
Embedding Organization units (O) inside the certificate may lead to a overhead for the K8S administrator, because every change inside the organization requires a new certificate.
So in my opinion it's better to use only Common Name (CN) during the CSR:
openssl req -new -key nicola.key -out nicola.csr -subj "/CN=nbenaglia@sorint.it"
and manage roles using Kubernetes' RoleBindings and ClusterRoleBindings.
The described flow can be further simplified by using the Kubernetes' CertificateSigningRequest
object. We'll see that in another post.
Simplicity is a better approach.