Kubernetes Basics #7 - Access Control

Last Edited: 6/3/2025

This blog post introduces concepts regarding access control in Kubernetes.

DevOps

So far, we have been developing applications and configuring Kubernetes clusters as a solo administrator/developer. However, for larger and more realistic clusters, we will need to collaborate with other developers and use automation tools. This opens up an opportunity for unverified contributors to access unrelated secrets, databases, and payment services within the cluster without proper access control. Therefore, in this article, we will cover the basics of access control in Kubernetes.

User Authentication

Access control is comprised of two processes: authentication and authorization. Authentication is the process of verifying a user's identity, and authorization is the process of applying rules regarding the access granted to the verified user. The authentication of users to services must be implemented, and there are multiple ways to set up user authentication, such as SSL, JSON Web Tokens (JWT), and OpenID Connect (OIDC) (OAuth2 supported by Microsoft, Salesforce, Google, etc.).

In the article, Network Engineering #4 - HTTP & HTTPS, we discussed the basics of TLS (the successor to SSL) in the context of verifying the identity of a server. We can apply this mechanism for verifying the identity of a user, where the user issues a Certificate Signing Request (CSR) from their certificate and key (by OpenSSL), the administrator signs the certificate as a Certificate Authority (CA), and the services verify the signed certificate with the CA's key to establish trust and connection. Kubernetes provides an API called certificates.k8s.io/v1, which allows users to easily create CSRs by applying a YAML file with sufficient information.

The administrator can check the CSR with get csr, check the details with describe, sign the certificate with certificate approve, and register the user with a particular username and the issued certificate to the API server using a kubeconfig file. Then, the user can provide credentials using set-credentials and switch to the new context to authenticate themselves. The API server can also be configured to receive JWT tokens from an OIDC provider for authentication (which is arguably smoother and recommended), though the details are outside the scope of this article.

Role-based Access Control (RBAC)

There are various methods for implementing authorization for a user, but role-based access control (RBAC), where a user or group is assigned a role with certain access permissions (also used in PostgreSQL), is a commonly used method. In Kubernetes, we can first define a Role with certain access permissions and then assign the role to a user by defining a RoleBinding. A role is namespace-scoped and can be defined using API groups (core API groups like v1 and other named API groups), resources (pods, services, deployments), and verbs (get, watch, list, create, update, delete, etc.).

pod-readonly.yaml
## Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-readonly
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
## Role Binding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: default
  name: pod-readonly
subjects:
  - kind: User
    name: example-user
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-readonly
  apiGroup: rbac.authorization.k8s.io

Since the roles are namespace-scoped, rules around resources across namespaces and nodes cannot be specified. Hence, there's another set of objects called ClusterRole and ClusterRoleBinding that allows us to specify those rules. There are several preset cluster roles and cluster role bindings, which we can customize by aggregating the rules, though the details are unfortunately outside the scope of this article.

Service Accounts

We're discussing how to authenticate and authorize users (developers) so far, but we also have build tools, monitoring, and logging services that need to interact with the resources of a cluster in a secure manner. For these non-human services, we provide the abstraction called service accounts and implement authentication and authorization. We can create a new service account for a monitoring service (aside from the default service accounts defined for each namespace) as follows.

monitor-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata: 
  name: monitor-sa
  namespace: default
---
apiVersion: v1
kind: Secret
metadata:
  name: monitor-sa-secret
  annotations:
    kubernetes.io/service-account.name: monitor-sa
type: kubernetes.io/service-account-token

The latter part creates a long-lived API token for authenticating the service account. Pods corresponding to the monitoring service can include the service account's name under spec and mount the secret as a volume to authenticate as the monitor-sa service account. We can also use an imagePullSecret, which is intended for a pod to load a container image from a private repository. We can create an imagePullSecret as follows.

kubectl create secret docker-registry myregistrykey --docker-server=<registry name> \
        --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \
        --docker-email=DUMMY_DOCKER_EMAIL

Then, the pod specification can include the name of the key created under the imagePullSecrets field to pull private images. The same secret can be used to authenticate the service account as well by including the name of the key under the imagePullSecrets field at the top level of monitor-sa.yaml. After authenticating the service account, we can assign roles and bind them to the service account using RBAC, just as we did for authorizing normal users.

Conclusion

In this article, we covered the basics of user authentication, role-based access control, and service accounts, which are fundamental concepts for administrators to set up a secure cluster and for developers to work with clusters with proper access control in place. However, many details are left out of this article due to the concepts and tools we're going to cover in the future that can partially eliminate the need for setting them up directly on the API server. If you're interested in the details, please check the official Kubernetes documentation cited below.

Resources