What is a ServiceAccount?
When deploying applications to Kubernetes, granting them only the necessary permissions is crucial for security. This is achieved through ServiceAccounts and Role-Based Access Control (RBAC). A ServiceAccount is an identity for applications running within a Kubernetes cluster, distinct from user accounts intended for humans. It allows pods to authenticate securely with the Kubernetes API, enabling them to perform actions like reading Pods, creating Jobs, accessing ConfigMaps and Secrets, watching Deployments, and integrating with cloud identity providers such as Azure Workload Identity, AWS IAM Roles for Service Accounts, and OCI Workload Identity.
The Agentic CLI, for instance, requires a ServiceAccount to authenticate with an AKS cluster when operating in cluster mode. This ensures that the CLI has the specific credentials needed to interact with the cluster's API server without relying on user credentials.
Understanding RBAC
RBAC is Kubernetes' authorization system. It allows administrators to define granular permissions for users, groups, and ServiceAccounts. RBAC operates on the principle of least privilege, ensuring that entities only have the permissions they absolutely need to perform their functions. This significantly reduces the attack surface and the potential impact of a compromised application or credential.
Key components of RBAC include:
- Roles: Define a set of permissions within a specific namespace. A Role can grant access to resources like Pods, Services, or Deployments, specifying actions like `get`, `list`, `watch`, `create`, `update`, `patch`, and `delete`.
- ClusterRoles: Similar to Roles but define permissions cluster-wide, not limited to a single namespace. These are useful for granting access to cluster-scoped resources or for permissions that should apply across all namespaces.
- RoleBindings: Grant the permissions defined in a Role to a specific subject (user, group, or ServiceAccount) within a namespace.
- ClusterRoleBindings: Grant the permissions defined in a ClusterRole to a subject cluster-wide.
Creating a ServiceAccount
Creating a ServiceAccount is a straightforward process using `kubectl`. You define a YAML manifest that specifies the ServiceAccount's name and, optionally, the namespace it belongs to. If no namespace is specified, it defaults to the `default` namespace.
Here's a basic example of a ServiceAccount manifest:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: default
To apply this manifest, you would use the following command:
kubectl apply -f serviceaccount.yaml
This command creates a ServiceAccount named `my-app-sa` in the `default` namespace. Kubernetes automatically creates a corresponding secret for this ServiceAccount, which contains the authentication token needed to interact with the API server. This token is mounted into pods that use the ServiceAccount.
Assigning Permissions with Roles and RoleBindings
Once a ServiceAccount is created, you need to grant it specific permissions. This is done by defining a Role and then binding that Role to the ServiceAccount using a RoleBinding.
Defining a Role
Let's say our application `my-app` needs to list and get Pods within the `default` namespace. We would create a Role like this:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "list", "watch"]
This Role, named `pod-reader`, grants permissions to `get`, `list`, and `watch` operations on `pods` resources within the `default` namespace.
Creating a RoleBinding
Now, we bind this `pod-reader` Role to our `my-app-sa` ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: default
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
This `RoleBinding` ensures that the `my-app-sa` ServiceAccount has the permissions defined in the `pod-reader` Role within the `default` namespace. Any pod running with `my-app-sa` will be able to list and get pods in that namespace.
Using the ServiceAccount in a Pod
To use the created ServiceAccount, you specify its name in the pod's definition:
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
namespace: default
spec:
serviceAccountName: my-app-sa
containers:
- name: my-app-container
image: nginx:latest
# ... other container configurations
When this pod starts, Kubernetes will automatically mount the ServiceAccount's token into the pod at `/var/run/secrets/kubernetes.io/serviceaccount/token`. Applications within the pod can then use this token to authenticate with the Kubernetes API server.
Cluster-Wide Permissions
For permissions that need to span multiple namespaces or apply to cluster-scoped resources, you would use ClusterRole and ClusterRoleBinding.
Creating a ClusterRole
A ClusterRole might grant permissions to list all nodes in the cluster:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
Creating a ClusterRoleBinding
This ClusterRole is then bound to a ServiceAccount (or user/group) cluster-wide:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-nodes-global
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default # The namespace where the ServiceAccount resides
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
This setup grants the `my-app-sa` ServiceAccount the ability to read node information across the entire cluster. It's essential to be judicious with cluster-wide permissions, as they grant broad access.
Best Practices
Applying the principle of least privilege is paramount. Always scope permissions as narrowly as possible. For applications running in specific namespaces, use Role and RoleBinding. Only use ClusterRole and ClusterRoleBinding when absolutely necessary for cluster-wide operations. Regularly review ServiceAccounts and their associated permissions to ensure they remain appropriate and to revoke any unnecessary access. Consider using tools that can help manage and audit RBAC configurations to maintain a strong security posture.
By correctly configuring ServiceAccounts and RBAC, you significantly enhance the security of your Kubernetes deployments, ensuring that your applications have precisely the access they require and no more.