X.509 client certificates in K8s

Introduction

Using X.509 client certificates, restrict access to the kube-system namespace of developer users and grant

  • authority only in a specific namespace.
  • Developer’s authority setting.
    • All authorization of the Default Namespace

You can move to another name space later.
Kubernetics users.
All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users.
In Kubernetes, there are largely two categories of users.

  1. Service account
  2. Normal User

Normal User

A few steps are required in order to get a normal user to be able to authenticate and invoke an API. First, this user must have a certificate issued by the Kubernetes cluster, and then present that certificate to the Kubernetes API.

Create private key

The following scripts show how to generate PKI private key and CSR. It is important to set CN and O attribute of the CSR. CN is the name of the user and O is the group that this user will belong to. You can refer to RBAC for standard groups.

$ sudo su
$ openssl genrsa -out developer.key 2048
$ openssl req -new -key developer.key -out developer.csr -subj "/CN=developer"
  • CN: User Name is mandatory

If you have error in Ubuntu 18

$ sudo openssl req -new -key developer.key -out developer.csr

Can't load /home/ubunut.rnd into RNG
140373280158144:error 2406F079:random number generator:RAND_load_file:Cannot open file:../crypoto/rand/randfile.c88:Filename=/home/ubuntu/.rnd
  • Removing comment out `RANDFILE = $ENV::HOME/.rnd from /etc/ssl/openssl.cnf

Create CertificateSigningRequest

Create a CertificateSigningRequest and submit it to a Kubernetes Cluster via kubectl. Below is a script to generate the CertificateSigningRequest.

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: developer
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dUQ0NBVUVDQVFBd0ZERVNNQkFHQTFVRUF3d0paR1YyWld4dmNHVnlNSUlCSWpBTkJna3Foa2lHOXcwQgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxQ1RNMjNmYkdmZkk5bys1anZmWlY1UFZabGZnMmVVWWk4Rmk2RFh1ClJNYzlEVnZ5aXVzTUc3LzlWbjJEQXU4UkRHUzJrZC93OUEzWGR6cEhidWR5aDJvaTU3MHVHeWVNT3NnV3EycFMKYmdRUmV6MWx5Zk9ROE5DYm1WSnpYNlZCR2NGaEt6aGdjcnpwb2tzTkJnZHk4Y3ZKVkZiYzJFWi9HbXFWU2ZJbQp4R1J1S0FoL05HSitzbDRkUjg3MlIwYm80dE85QzdKRHFKV2VVdE11ckxLZ05ZdXBWeHI0VnUwK3h1MUl2WEFHCm90SnM1MTNVZjZsWCt4VGtGbjd6VmFmSndqdkEvQU1Vd2syV0NBZ3k1UUFmZDdoNGFtUlZKQmhkOXlObEdWNHkKUTE5TjFhWUptb0pwZUxadFFBbDRGd1V3ZFczbzIyUjBFeVJkenAvZWRyVWtOd0lEQVFBQm9BQXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQUR6eEM1TlBDdTA2blJOcHhUNXRrdmEzOGVNREJSVnhNSXlvdHNlUjkzd1VIWGw0ClVSeERUNmVGYmNYU1M3RXZodjRJa0NBTkVWTHZyMFJzQ294bXJ4NXBrUjRHOG45aG1KMy9YQitVa1JvZzBETXoKWldTRmQ0VVh3MW1VcGZhK3FLNjhsK05GWkQ4VWpWcktEUzBpRWhzbTRGeUtES1c3b1crUWo2RVZ4ZlJsZERhbQpnT1dmWVQ1V1RYRndNRjJWV3ljMEg3TXNjbDUzMlpXYU5vM0RNamRUdkxid2JXUVBKNnVvOTkzaUJwNkF0c0lUCk56UTlnTHVRbmI2Nm9kR25UYjNiM21kRFZ3MlJEaFBZRjBiLzZJWHFDV3ptQ05KZ0ROYUprQzYySnAvMzJ2bFcKc01zNjdaSmNLVTQ0a2ZhaG80d0VQVk5GOHdPOG5pdDhNTjR0bEcwPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth
  • cat developer.csr | base64 | tr -d "\n"

Some points to note:

  • usages has to be ‘client authexpirationSeconds could be made longer (i.e. 864000 for ten days) or shorter (i.e. 3600 for one hour)request is the base64 encoded value of the CSR file content. You can get the content using this command: cat developer.csr | base64 | tr -d "\n"
certificatesigningrequest.certificates.k8s.io/developer created

Approve certificate signing request

Use kubectl to create a CSR and approve it.

Get the list of CSRs:

$ kubectl get csr

Approve the CSR:

kubectl certificate approve developer

Get the certificate

Retrieve the certificate from the CSR:

$ kubectl get csr/developer -o yaml

The certificate value is in Base64-encoded format under status.certificate.

Export the issued certificate from the CertificateSigningRequest.

$ kubectl get csr developer -o jsonpath='{.status.certificate}'| base64 -d > developer.crt

Create Role and RoleBinding

With the certificate created it is time to define the Role and RoleBinding for this user to access Kubernetes cluster resources.

This is a sample command to create a Role for this new user:

$ kubectl create role developer --verb=* --resource=* -n default
kubectl describe role developer
Name:         developer
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *          []                 []              [*]

This is a sample command to create a RoleBinding for this new user:

$ kubectl create rolebinding developer-binding --role=developer --user=developer
rolebinding.rbac.authorization.k8s.io/developer-binding created

Add to kubeconfig

The last step is to add this user into the kubeconfig file.

First, you need to add new credentials:

$ kubectl config set-credentials developer --client-key=developer.key --client-certificate=developer.crt --embed-certs=true

Then, you need to add the context:

$ kubectl config set-context developer --cluster=kubernetes --user=developer

To test it, change the context to developer:

$ kubectl config use-context developer

Check

$ kubectl config use-context developer

Switched to context "developer".
$ kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
web-one   1/1     Running   0          24h
web-two   1/1     Running   0          24h

$ kubectl get pods -n kube-system
Error from server (Forbidden): pods is forbidden: User "developer" cannot list resource "pods" in API group "" in the namespace "kube-system"

Good Job! it is working

Learn more: https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/

Leave a Reply

Your email address will not be published.

ANOTE.DEV