Creating credentials for Kubernetes users

It is considered best practice to create a new credential for each user of the cluster. This topic covers how to create a kubeconfig file for a user, which enables the user to connect into the cluster using their own credential.

user icon z/OS® security administrator Kubernetes administrator

The IBM® z/OS Control Plane Appliance (zCPA) supports X509 certificates to enable users of the cluster to be authenticated. The following example demonstrates how an X509 certificate for a new user can be signed by the cluster's certificate authority and embedded in a kubeconfig file, which the user can then use with the Kubectl for IBM z/OS (kubectl) command line utility, to interact with the cluster.

The example uses tools available on Linux® to generate a certificate signing request and create the kubeconfig file. Alternative tools are available for different operating systems. For more information, see https://kubernetes.io/docs/tasks/administer-cluster/certificates/.

Pre-requisite tools:
  • cfssl (generates a certificate signing request (CSR) and private key for the certificate)
  • cfssljson (takes the JSON output from the cfssl tool and writes the private key and CSR to disk)
  • base64 (converts output to/from base64)
  • kubectl (CLI to manage the kubernetes cluster. Typically the kubectl user will need cluster administrator level access to add additional users to the cluster.)
This example creates a kubeconfig file for a systems programmer that is called zos-user1 and adds zos-user1 to a group of system programmers called zos-admins. Kubernetes role based access controls can then be configured for either zos-user1 or the group zos-admins. For more information on Kubernetes role based access controls, see Giving role based access control.

Create a certificate signing request and private key

Run the following commands on a Linux system. The commands construct a certificate signing request for the user zos-user1 to add the user to a group called zos-admins. The output from the commands is two files: zos-user1.csr and zos-user1-key.pem (the certificate signing request and private key).

mkdir -p /tmp/zoscp/csrs
chmod 700 /tmp/zoscp
cd /tmp/zoscp/csrs

cat <<EOF >zos-user1-csr.json
{
  "CN": "zos-user1",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "O": "zos-admins"
    }
  ]
}
EOF

cfssl genkey zos-user1-csr.json | cfssljson -bare zos-user1
Example output:

# cfssl genkey zos-user1-csr.json | cfssljson -bare zos-user1
2023/06/13 09:33:22 [INFO] generate received request
2023/06/13 09:33:22 [INFO] received CSR
2023/06/13 09:33:22 [INFO] generating key: rsa-2048
2023/06/13 09:33:24 [INFO] encoded CSR

# ls -l
-rw-r--r-- 1 root root  920 Jun 13 09:33 zos-user1.csr
-rw-r--r-- 1 root root  131 Jun 13 09:33 zos-user1-csr.json
-rw------- 1 root root 1679 Jun 13 09:33 zos-user1-key.pem

You have now created a certificate that has added the zos-user1 to the group called zos-admins.

Sign the certificate with the cluster's certificate authority

Run the following commands to create an environment variable holding the base64 encoded version of the certificate signing request, and then use that environment variable when creating a Kubernetes CertificateSigningRequest object in the cluster.
  1. 
    CSR=$(cat zos-user1.csr | base64 -w 0)
    
    cat <<EOF | kubectl apply -f -
    apiVersion: certificates.k8s.io/v1
    kind: CertificateSigningRequest
    metadata:
      name: zos-user1
    spec:
      request: $CSR
      signerName: kubernetes.io/kube-apiserver-client
      usages:
        - client auth
    EOF
    
    Example output:
    
    certificatesigningrequest.certificates.k8s.io/zos-user1 created
    
  2. Issue the following kubectl commands to view the certificate signing request (note that its in Pending state) and then to approve the certificate signing request. Wait until the csr is shown as Approved, Issued.
    kubectl get csr
    kubectl certificate approve zos-user1
    kubectl get csr
    Example output:
    # kubectl get csr
    NAME       AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
    zos-user1   98s   kubernetes.io/kube-apiserver-client   kubernetes-admin   <none>              Pending
    # kubectl certificate approve zos-user1
    certificatesigningrequest.certificates.k8s.io/zos-user1 approved
    # kubectl get csr
    NAME       AGE    SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
    zos-user1   111s   kubernetes.io/kube-apiserver-client   kubernetes-admin   <none>              Approved,Issued

Create a kubeconfig file for zos-user1

  1. Run the following commands to setup environment variables containing the signed certificate, the private key (base64 encoded), and cluster information from the current users kubeconfig file, then create a new kubeconfig file for zos-user1, using the contents of those environment variables.
    
    CERTIFICATE=$(kubectl get csr zos-user1 -o go-template='{{index .status "certificate" }}')
    PRIVATE_KEY=$(cat /tmp/zoscp/csrs/zos-user1-key.pem | base64 -w 0)
    CLUSTER_NAME=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''$(kubectl config current-context)'''"}}{{.context.cluster}}{{end}}{{end}}')
    CLUSTER_CERT_AUTH_DATA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CLUSTER_NAME}'''"}}{{index .cluster "certificate-authority-data" }}{{end}}{{end}}')
    CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CLUSTER_NAME}'''"}}{{.cluster.server}}{{end}}{{end}}')
    
    cat << EOF >/tmp/zoscp/zos-user1.kubeconfig
    apiVersion: v1
    kind: Config
    clusters:
    - name: ${CLUSTER_NAME}
      cluster:
        certificate-authority-data: ${CLUSTER_CERT_AUTH_DATA}
        server: ${CLUSTER_SERVER}
    contexts:
    - name: ${CLUSTER_NAME}
      context:
        cluster: ${CLUSTER_NAME}
        user: zos-user1
    current-context: ${CLUSTER_NAME}
    users:
    - name: zos-user1
      user:
        client-certificate-data: $CERTIFICATE
        client-key-data: $PRIVATE_KEY
    EOF
    chmod 700 /tmp/zoscp/zos-user1.kubeconfig
  2. The file /tmp/zoscp/zos-user1.kubeconfig should now exist. Check that it exists by using the following command:
    ls -l /tmp/zoscp/zos-user1.kubeconfig
    Example output:
    -rw------- 1 root root 5540 Jun 13 09:49 /tmp/zoscp/zos-user1.kubeconfig

Test the new kubeconfig file

  1. Run the following command to try out the new kubeconfig file and check if the user is authorized to view pods in the cluster.
    kubectl --kubeconfig /tmp/zoscp/zos-user1.kubeconfig auth can-i get pods
    Example output:
    # kubectl --kubeconfig /tmp/zoscp/zos-user1.kubeconfig auth can-i get pods
    no

You have now created an additional kubeconfig file for the user zos-user1. The kubeconfig file should be provided to the user who then makes a copy within ~/.kube/config on their system, and ensure the permissions are restricted to only their user ID. This kubeconfig enables the user to use kubectl to connect into the cluster using their own credential.

You should now configure zos-user1 to be part of a group. For more information, see Giving role based access control.