How to create Users in Kubernetes the right way?

Page content

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

Parts of the K8S Security Lab series

Container Runetime Security
Advanced Kernel Security
Container Network Security
Secure Kubernetes Install
User Security

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.