How to create Users in Kubernetes the right way?

I this post I will show you how you can create Users in Kubernetes the right way.

Parst of the K8S Security series

Users in Kubernetes

All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users. Kubernetes does not have objects which represent normal user accounts. Normal users cannot be added to a cluster through an API call.

So how we choud create an user account?

Any user that presents a valid certificate signed by the cluster’s certificate authority (CA) is considered authenticated. So you need to create a certificate for you username.

Why I need a user account insted of service account?

A service account is wisible and its token can be mounted in to a pod so theat pod has the same privileges as you.

Generate new certificate

First, we have to generate a private key and a certificate signing request:

openssl genrsa -out devopstales.pem
openssl req -new -key devopstales.pem -out devopstales.csr -subj "/CN=devopstales"

devopstales well be my username. You can add your user to specific groups by addin them as groups like devops-groupe:

openssl req -new -key ivnilv.pem -out ivnilv.csr -subj "/CN=devopstales/O=devops-groupe"

Signing the certificate

Use the csr file for generating a CertificateSigningRequest object n Kubernetes:

cat devopstales.csr | base64 | tr -d '\n'

cat <<'EOF'> devopstales-csr.yaml
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: user-request-devopstales
spec:
  groups:
  - system:authenticated
  request: LS0tLS1CRUdJTi...
  usages:
  - digital signature
  - key encipherment
  - client auth
EOF

OR from Kubernetes v1.22 (in this example it will expire after 10 years):

cat devopstales.csr | base64 | tr -d '\n'

cat <<'EOF'> devopstales-csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: user-request-devopstales
spec:
  groups:
  - system:authenticated
  request: LS0tLS1CRUdJTi...
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 315569260
  usages:
  - digital signature
  - key encipherment
  - client auth
EOF

Create the CertificateSigningRequest and approve it. Then the Kubernetes api server will generate the certificate theat you can use to authentication.

kubectl create -f devopstales-csr.yaml
kubectl certificate approve user-request-devopstales

kubectl get csr
NAME                       AGE       REQUESTOR   CONDITION
user-request-devopstales   1m        admin       Approved,Issued

Now the certificate should be signed. You can download the new signed public key from the csr resource:

kubectl get csr user-request-devopstales -o jsonpath='{.status.certificate}' | base64 -d > devopstales-user.crt

Create new user config file

kubectl --kubeconfig ~/.kube/config-devopstales config set-cluster preprod --insecure-skip-tls-verify=true --server=https://KUBERNETES-API-ADDRESS
kubectl --kubeconfig ~/.kube/config-devopstales config set-credentials devopstales --client-certificate=devopstales-user.crt --client-key=devopstales.pem --embed-certs=true
kubectl --kubeconfig ~/.kube/config-devopstales config set-context default --cluster=preprod --user=devopstales
kubectl --kubeconfig ~/.kube/config-devopstales config use-context default

Ofcourse you need rbac for this user:

cat <<'EOF'> devopstales-rbac.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: devopstales-ns
spec: {}
status: {}
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: devopstales
  namespace: devopstales-ns
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: devopstales
  namespace: devopstales-ns
subjects:
- kind: User
  name: devopstales
  apiGroup: rbac.authorization.k8s.io
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: devopstales
EOF

kubectl apply -f devopstales-rbac.yaml

Let’s test if the new kubeconfig we generated worked fine:

kubectl --kubeconfig ~/.kube/config-devopstales get pods

Conclusion

As we can see creating certificate for all the users is a hard task for the administratos if we hawe many users. A better solution to use an sso based authentication proxy like my Kubectl OpenID Connect.