kubernetes > add a user with tls
In this exercise we would add an extra user to kubeconfig, that uses TLS for authentication. Its good to have some fundamental understanding of OpenSSL, kubeadm and kubeconfig to benefit more from this post
To let a user authenticate via TLS with the kube-apiserver, we need to generate a TLS key for the user, and a signed TLS certificate for the user. The signature will be provided by the cluster CA, that should have been typically setup by kubeadm during the cluster launch.
Let’s create a new TLS RSA private key of modulus 4096 bit, for the new user, using OpenSSL
networkandcode@master $ openssl genrsa -out user2.key 4096
networkandcode@master $ cat user2.key
-----BEGIN RSA PRIVATE KEY-----
REDACTED
-----END RSA PRIVATE KEY-----
We now need to generate a CSR (certificate signing request) for this key, as the username is ‘user2’ it can be specified as the CN (common name)
networkandcode@master $ openssl req -new -out user2.csr -key user2.key -subj "/CN=user2"
networkandcode@master $ cat user2.csr
-----BEGIN CERTIFICATE REQUEST-----
REDACTED
-----END CERTIFICATE REQUEST-----
This CSR should now be signed by the cluster CA (cluster authority) so that we get a signed certificate. We could do this using the CertificateSignigRequest API object of Kubernetes.
We need to create a CSR object which has the base 64 encoded CSR in it. So, our first step is to encode the CSR
networkandcode@master $ cat user2.csr | base64 | tr -d '\n
The command above does the encoding, but we could better save it in a variable, let’s say user2_csr_base64
networkandcode@master $ export user2_csr_base64=$(cat ./user2.csr | base64 | tr -d '\n')
We now define our Kubernetes CSR object as follows
networkandcode@master $ cat > csr-user2.yaml <<EOF
---
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: csr-user2
spec:
groups:
- system:authenticated
request: ${user2_csr_base64}
usages:
- "client auth"
...
EOF
In the manifest above, we are importing data from the variable we defined earlier, the ‘cllient auth’ usage is enough as our user is only a client, the ‘system:authenticated’ allows only authentication to the cluster.
The CSR object can now be created after substituing the variable
networkandcode@master $ cat csr-user2.yaml | envsubst | kubectl create -f -
certificatesigningrequest.certificates.k8s.io/csr-user2 created
Our CSR object is created, but in pending state, as it has to be signed by the cluster CA
networkandcode@master $ kubectl get csr csr-user2
NAME AGE REQUESTOR CONDITION
csr-user2 2m17s kubernetes-admin Pending
The Requestor column has ‘kubernetes-admin’, as its the current user that kubectl is scoped to
Let’s approve it, a.k.a sign it
networkandcode@master $ kubectl certificate approve csr-user2
certificatesigningrequest.certificates.k8s.io/csr-user2 approved
networkandcode@master $ kubectl get csr csr-user2
NAME AGE REQUESTOR CONDITION
csr-user2 4m11s kubernetes-admin Approved,Issued
The CSR object would now have the base64 encoded, signed certificate within it, we may retrieve it
networkandcode@master $ kubectl get csr csr-user2 -o jsonpath={.status.certificate}
We could decode it and save it as a file
networkandcode@master $ kubectl get csr csr-user2 -o jsonpath={.status.certificate} | base64 --decode > user2.crt
ok, so by now we have the key and the signed certificate, as an optional step, we could move them both to the directory where other PKI data is stored
networkandcode@master $ mv user2.key /etc/kubernetes/pki/
networkandcode@master $ mv user2.crt /etc/kubernetes/pki/
It’s time to modify kubeconfig now, to add the new user, its key, and certificate
networkandcode@master $ kubectl config set-credentials user2 --client-key=/etc/kubernetes/pki/user2.key --client-certificate=/etc/kubernetes/pki/user2.crt
User "user2" set.
And now we need to add a new context, that maps this user with the cluster, note that the cluster name is ‘kubernetes’
networkandcode@master $ kubectl config set-context context2 --cluster kubernetes --user user2
Context "context2" created.
Finally switch context, to issue kubectl commands as the new user ‘user2’
networkandcode@master $ kubectl config use-context context2
Switched to context "context2".
Let’s try a command as ‘user2’
networkandcode@master $ kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:53:57Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:45:25Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
This works, but the following wouldn’t work
networkandcode@master $ kubectl get nodes
Error from server (Forbidden): nodes is forbidden: User "user2" cannot list resource "nodes" in API group "" at the cluster scope
This is because the ‘system:authenticated’ group we mentioned in the CSR object, would allow only authentication to the cluster, with no other authorization
–end-of-post–