Authorization of developers working on a Kubernetes cluster
- Nicola Benaglia
- 18 Aug, 2018
- 02 Mins read
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**
1. Fine-grained permissions to a single developer or group
2. Developer self-generates his private key and CSR
**Cons**
1. Belonging organizations (K8S groups) must be carefully designed before CSR generation
2. Admin cannot revoke a single user from a group binding (*thanks* to Maxim Filatov for the note)
3. Admin must check the developer self-generated certificate
4. Generation and distribution of a certificate for each developer
5. 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.