Controlling Access to the Kubernetes API

Users access the API using kubectl, client libraries, or by making REST requests. Both human users and Kubernetes serevice accounts can be authorized for API access. When a request reaches the API, it goes through several stages, illustrated in the following diagram:

Diagram of request handling steps for Kubernetes API request

For more information, see Controlling Access to the Kubernetes API.

Users in Kubernetes

All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users.

Normal users are assumed to be managed by an outside, independent service. An admin distributing private keys, a user store like Keystone or Google Accounts, even a file with a list of usernames and passwords. In this regard, Kubernetes does not have objects which represent normal user accounts. Normal users cannot be added to a cluster through an API call.

In contrast, service accounts are users managed by the Kubernetes API. They are bound to specific namespaces, and created automatically by the API server or mannually through API calls. Service accounts are tied to a set of credential stored as Secret, which are mounted into pods allowing in-cluster processed to talk to the Kubernetes API.

API requests are tied to either a normal user or a service account, or are treated as anonymous requests. This means every process inside or outside the cluster, from a human user typing kubectl on a workstation, to kubelets on nodes, to members of the control plane, must authenticate when making requests to the API server, or be treated as an anonymous user.

For more information, see Authenticating in Kubernetes

Authentication strategies

Kubernetes uses client certificates, bearer tokens, an authenticating proxy, or HTTP basic auth to authenticate API requests through authentication plugins. As HTTP request are made to the API server, plugins attempt to associate the following attributes with the request:

  • Username: a string which identifies the end user. Common values might be kube-admin or jane@example.com.
  • UID: a string which identifies the end user and attempts to be more consistent and unique than username.
  • Groups: a set of strings which associate users with a set of commonly grouped users.
  • Extra fields: a map of strings to list of strings which holds additional information authorizers may find useful.

X509 Client Certs

Client certificate authentication is enabled by passing the –client-ca-file=SOMEFILE option to API server. The referenced file must contain one or more certificates authorities to use to validate client certificates presented to the API server. If a client certificate is presented and verified, the common name of the subject is used as the user name for the request. As of Kubernetes 1.4, client certificates can also indicate a user’s group memberships using the certificate’s organization fields. To include multiple group memberships for a user, include multiple organization fields in the certificate.

For example, using the openssl command line tool to generate a certificate signing request:

openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"

This would create a CSR for the username “jbeda”, belonging to two groups, “app1” and “app2”.

See Managing Certificates for how to generate a client cert.

Determine Whether a Request is Allowed or Denied

Kubernetes authorizes API requests using the API server. It evaluates all of the request attributes against all policies and allows or denies the request. All parts of an API request must be allowed by some policy in order to proceed. This means that permissions are denied by default.

For more information, see Authorization Overview

RBAC Authorization

Role and ClusterRole

In the RABC API, a role contains rules that represent a set of permissions. Perminssions are purely additive (there are no “deny” rules). A role can be defined within a namespace with a Role, or cluster-wide with a ClusterRole.

A Role can only be used to grant access to resources within a single namespace.

A ClusterRole can be used to grant the same permissions as a Role, but because they are cluster-scoped, they can also be used to grant access to:

  • cluster-scoped resources (like nodes)
  • no-resource endpoints (like “/healthz”)
  • namespaced resources (like pods) across all namespaces (need to kubectl get pods –all-namespaces, for example)

RoleBinding and ClusterRoleBinding

A role binding grants the permissions defined in a role to a user or set of users. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted. Permissions can be granted within a namespace with a RoleBinding, or cluster-wide with a ClusterRoleBinding.

roleRef is how you will actually create the binding. The kind will be either Role or ClusterRole, and the name will reference the name of the specific Role or ClusterRole you want.

A RoleBinding may reference a Role in the same namespace.

A RoleBinding may also reference a ClusterRole to grant the permissions to namespaced resources defined in the ClusterRole within the RoleBinding’s namespace. This allows administrators to define a set of common roles for the entire cluster, then reuse them with multiple namespaces.

Finally, a ClusterRoleBinding may be used to grant permissions at the cluster level and in all namespaces.

For more information, see Using RBAC Authorization.

Configure Access to Kubernetes Cluster

1. Create a Normal User with X.509 Client Certificate

# Generate a certificate signing request
openssl req -newkey rsa:2048 -nodes -keyout kube-ops.key -out kube-ops.csr -subj "/CN=kube-ops"
# Sign the certificate signing request kube-ops.csr with Kubernetes CA certificate.
sudo openssl x509 -req -in kube-ops.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out kube-ops.crt -days 1000

You can also use CertificateSigningRequest:

  1. Create CertificateSigningRequest

     # Generate a certificate signing request
     openssl req -newkey rsa:2048 -nodes -keyout kube-ops.key -out kube-ops.csr -subj "/CN=kube-ops"
    
     # kube-ops-csr.yaml
     apiVersion: certificates.k8s.io/v1
     kind: CertificateSigningRequest
     metadata:
       name: kube-ops
     spec:
       groups:
         - system:authenticated
           # request is the base64 encoded value of the CSR file content.
           # You can get the content using this command: cat kube-ops.csr | base64 | tr -d '\n'
       request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1dEQ0NBVUFDQVFBd0V6RVJNQThHQTFVRUF3d0lhM1ZpWlMxdmNITXdnZ0VpTUEwR0NTcUdTSWIzRFFFQgpBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREJyNEJmZXVIMG5OTTRwT0NYOG9oNTY1bmsyandLS0RDcW9wbGZRT1J4CnhTM29ZbjduU0ZSUXM3b2RldGtlYktIU3ZibWlpMDF1d25vTStXTW5RRGhzTzA3clNOQ09ocHlzZlhiRnhyZW4KTnhmeGtwUjBCRTNvczNwL1pLOUNXU051bEtmd0owRUg0T24xU29sSFY0T21CR2dLNEY5WnBXcXpKWHdPaHY3bApnN2FGeTM0NHVMRzEwM2tud1o0eGQ2eStrTEk4Ny9zbmd6WUh2OGxXU3kvVDBPdVV1Nk1xN0hURXE3SGQrZ09XCk4xbml0aE92ZUErUWNxSGdZNlJZWnI3cmhkVzV0aEx3aGxlSTI3amtDSGNpdXEvS014QnJpbXEyaDcyakFtVC8KQmRqYjM0MWxJOEhzd0UwTlNUUnJuVzk3Qk1VVzhuc2VQM1A0RkhNcnYzNGpBZ01CQUFHZ0FEQU5CZ2txaGtpRwo5dzBCQVFzRkFBT0NBUUVBVjRJd0VweW0wS0ZJVkNrQXRKbkdwT3JVNVpBbXd5bTR2TDZxWTY4a0l5anMxVDRFCmNGdmNwTUFxVXpXNU1BeC9TVXN4R081NEFkZWlpbWRuMTZQaWhZbXFRNmh6UnhJSEdZY0xmNGg3ajZvMjN2S3YKUzNzd3JvVnpsa3liUEhTcVNoc0ZHejVQRE1HdWhNS0dRM2dFZklzUThHZnF0b3NiRVhLSWdQZTI5ZGVRcXRZMgpxTFh4WnJsTjZJSldwdU9hN3BRd1ZvSWFpTlEvc2t1ZGtScHFKSWRTWjBtNFNyYkVYZjdhaStoM0xKVU55MXlTCmJhZEI0dnl0clR0elNxdzE5eTdEQU1xU3VTOE44S0hMOU13djZYOEZ4Zno0L2FRZWsvcVhZZXNQc2xOVlNwS3YKKzhZYUh6MlRaOWtqYkp2WjI5WmNBUVlFbFdaUmtBVG44aWNCNGc9PQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
       signerName: kubernetes.io/kube-apiserver-client
       usages:
         - client auth
    
     $ kubectl apply -f kube-ops-csr.yml 
     certificatesigningrequest.certificates.k8s.io/kube-ops created
     $ kubectl get csr
     NAME       AGE   SIGNERNAME                            REQUESTOR          CONDITION
     kube-ops   4s    kubernetes.io/kube-apiserver-client   kubernetes-admin   Pending
    
  2. Approve certificate signing request

     $ kubectl certificate approve kube-ops
     certificatesigningrequest.certificates.k8s.io/kube-ops approved
     $ kubectl get csr
     NAME       AGE     SIGNERNAME                            REQUESTOR          CONDITION
     kube-ops   2m28s   kubernetes.io/kube-apiserver-client   kubernetes-admin   Approved,Issued
    
  3. Get the certificate

       $ kubectl get csr kube-ops -ojsonpath='{.status.certificate}' | base64 -d > kube-ops.crt
    

2. Create a KUBECONFIG file.

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <CA-DATA>
    server: https://<APISERVER-HOST>:<APISERVER-PORT>
  name: <CLUSTER-NAME>
contexts:
- context:
    cluster: <CLUSTER-NAME>
    user: <USER> # e.g. kube-ops
  name: <USER>@<CLUSTER-NAME>
kind: Config
users:
- name: <USER> # e.g. kube-ops
  user:
    client-certificate-data: <CLIENT-CRT-DATA>
    client-key-data: <CLIENT-KEY-DATA>
  1. Update <APISERVER-HOST> and <APISERVER-PORT> with you Kubernetes API server (i.e. master) host and port.
  2. Update <CLUSTER-NAME> with your Kubernetes cluster name.
  3. Update <USER> with “kube-ops”
  4. Update <CA-DATA> with the based64 encoded Kubernetes CA certificate.
  5. Update <CLIENT-CRT-DATA> with the based64 encoded client certificate kube-ops.crt.
  6. Update <CLIENT-KEY-DATA> with the based64 encoded cleint key kube-ops.key.

You can generate <CA-DATA>, <CLIENT-CRT-DATA> and <CLIENT-KEY-DATA with the following command:

# Generate the <CA-DATA>
sudo cat /etc/kubernetes/pki/ca.crt | base64 | tr -d '\n'
# Generate the <CLIENT-CRT-DATA>
cat kube-ops.crt | base64 | tr -d '\n'
# Generate the <CLIENT-KEY-DATA>
cat kube-ops.key | base64 | tr -d '\n'

3. Grant the cluster-admin ClusterRole to a user named “kube-ops”

# Gives the user *kube-ops* full control over every resource in the cluster and in all namespace with a **ClusterRoleBinding** with the default **ClusterRole** *cluster-admin*.
kubectl create clusterrolebinding kube-ops --clusterrole=cluster-admin --user=kube-ops

4. Test the config and RBAC rule.

# Update <CLUSTER-NAME> with your Kubernetes cluster name.
kubectl --kubeconfig=./config --context=kube-ops@<CLUSTER-NAME> get clusterrolebindings kube-ops

References

  1. https://kubernetes.io/docs/reference/access-authn-authz/controlling-access/
  2. https://kubernetes.io/docs/reference/access-authn-authz/authentication/
  3. https://kubernetes.io/docs/reference/access-authn-authz/authorization/
  4. https://kubernetes.io/docs/reference/access-authn-authz/rbac/
  5. https://kubernetes.io/docs/concepts/cluster-administration/certificates/
  6. https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/
  7. https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
  8. https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/
  9. https://blog.codefarm.me/2019/01/31/public-key-cryptography-and-x509/