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
Network Security
Secure Kubernetes Install
User Security
Image Security
  • Part1: Image security Admission Controller
  • Part2: Image security Admission Controller V2
  • Part3: Image security Admission Controller V3
  • Part4: Continuous Image security
  • Part5: trivy-operator 1.0
  • Part6: trivy-operator 2.1: Trivy-operator is now an Admisssion controller too!!!
  • Part7: trivy-operator 2.2: Patch release for Admisssion controller
  • Part8: trivy-operator 2.3: Patch release for Admisssion controller
  • Part8: trivy-operator 2.4: Patch release for Admisssion controller
  • Part8: trivy-operator 2.5: Patch release for Admisssion controller
  • Part9_ Image Signature Verification with Connaisseur
  • Part10: Image Signature Verification with Connaisseur 2.0
  • Part11: Image Signature Verification with Kyverno
  • Part12: How to use imagePullSecrets cluster-wide??
  • Part13: Automatically change registry in pod definition
  • Part14: ArgoCD auto image updater
    Pod Security
    Secret Security
    Monitoring and Observability
    Backup

    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.