Skip to content

Authorization

Authorization Mechanisms (Modes)

Refer here for more details.

In summary;

Mode Description
AlwaysAllow Allows all requests without any authorization checks.
AlwaysDeny Blocks all requests.
Node Authorization A special-purpose authorization mode that authorizes API requests made by kubelets.
ABAC It defines an access control paradigm whereby access rights are granted to users through the use of policies that combine attributes together.
RBAC It is a method of regulating (control) access to resources in a Kubernetes cluster based on the roles of individual users or service accounts.
Webhook A mode that allows you to manage authorization externally. For example, Open Policy Agent (OPA).

By default, the mode is set to AlwaysAllow in the kube-apiserver. You can change the mode by setting the --authorization-mode flag in the kube-apiserver. You can also specify multiple modes by separating them with a comma. When you specify multiple nodes, the kube-apiserver will try to authorize the request with the first mode in the list. If the request is denied, it will try the next mode in the list.

Bash
--authorization-mode=RBAC,ABAC,Webhook

Node Authorization

Info

The node authorizer only handles node requests.

Reference

The node authorizer allows a kubelet to perform API operations. All these operations are handled by node authorizer. So, we know that kubelet is part of a system nodes group and have a prefix system:node. The kubelet will be granted these privileges after the node authorizer has authorized the kubelet so that it can perform the following operations.

Read operations;

  • services
  • endpoints
  • nodes
  • pods
  • secrets, configmaps, persistent volume claims and persistent volumes related to pods bound to the kubelet's node

Write operations;

  • node status
  • pod status
  • events

Attribute-based Access Control (ABAC)

Reference

ABAC is a method of restricting access to resources based on the attributes of the user. It is a static file that defines the access control policy. The policy file is a set of rules that specify what kind of access is granted to which users.

Step 1: Create a Policy File

For example, the following policy file

  • allows Alice to create pods and get pods in the default namespace.
  • allows Bob to get pods in the prod namespace, but not create pods.
  • allows group dev to access all resources in all namespaces.
policy.jsonl
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": { "user": "alice", "namespace": "default", "resource": "pods", "readonly": false}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "prod", "resource": "pods", "readonly": true}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "dev", "namespace": "*", "resource": "*"}}
  • you can specify multiple rules in the policy file.

Step 2: Enable ABAC mode

Once you have the policy file, you will need to enable ABAC in the kube-apiserver by setting the --authorization-mode flag to ABAC and the --authorization-policy-file flag to the path of the policy file. But this method is not recommended, as everytime you need to update the policy file, you need to restart the kube-apiserver.

/etc/kubernetes/manifests/kube-apiserver.yaml
--authorization-mode=ABAC
--authorization-policy-file=policy.jsonl
  • Remember to mount the policy file through a volume.

Step 3: Create a new user and test

You can create a service account and use service account token to create a new user.

Bash
# create a new service account
kubectl create serviceaccount alice

Create service account token.

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

Retrieve the service account token and store the token securely in a file as it is used to authenticate the user.

Bash
kubectl get secret alice-token -o jsonpath='{.data.token}' | base64 --decode > token.txt

Setup new user credentials with the token.

Bash
export ALICE_TOKEN=$(cat token.txt)
kubectl config set-credetials alice --token=$ALICE_TOKEN

Setup new context with the new user.

Bash
kubectl config set-context alice-context --user=alice --cluster=kubernetes --namespace=default

Verify the permissions of the user.

Bash
kubectl get pods -n default # should work
kubectl get secrets -n default # should not work

Role-based Access Control (RBAC)

Info

RBAC mainly used to authorize users or service accounts to namespace resources.

Reference

RBAC is a method of regulating (control) access to resources based on the roles of individual users or service accounts. So we will create and define a role with a set of permissions and then bind the role to a user or service account.

Before we dive into RBAC, we need to understand what resources are under namespace and cluster scope (non-namespaced resources).

Bash
# list all resources under namespace
kubectl api-resources --namespaced=true

# this will help you to get the verb
kubectl api-resources --namespaced=true --sort-by name -o wide
Name API Version Kind
bindings v1 Binding
configmaps v1 ConfigMap
endpoints v1 Endpoints
events v1 Event
limitranges v1 LimitRange
persistentvolumeclaims v1 PersistentVolumeClaim
pods v1 Pod
podtemplates v1 PodTemplate
replicationcontrollers v1 ReplicationController
resourcequotas v1 ResourceQuota
secrets v1 Secret
serviceaccounts v1 ServiceAccount
services v1 Service
controllerrevisions apps/v1 ControllerRevision
daemonsets apps/v1 DaemonSet
deployments apps/v1 Deployment
replicasets apps/v1 ReplicaSet
statefulsets apps/v1 StatefulSet
localsubjectaccessreviews authorization.k8s.io/v1 LocalSubjectAccessReview
horizontalpodautoscalers autoscaling/v2 HorizontalPodAutoscaler
cronjobs batch/v1 CronJob
jobs batch/v1 Job
leases coordination.k8s.io/v1 Lease
endpointslices discovery.k8s.io/v1 EndpointSlice
events events.k8s.io/v1 Event
ingresses networking.k8s.io/v1 Ingress
networkpolicies networking.k8s.io/v1 NetworkPolicy
poddisruptionbudgets policy/v1 PodDisruptionBudget
contourconfigurations projectcontour.io/v1alpha1 ContourConfiguration
contourdeployments projectcontour.io/v1alpha1 ContourDeployment
extensionservices projectcontour.io/v1alpha1 ExtensionService
httpproxies projectcontour.io/v1 HTTPProxy
tlscertificatedelegations projectcontour.io/v1 TLSCertificateDelegation
rolebindings rbac.authorization.k8s.io/v1 RoleBinding
roles rbac.authorization.k8s.io/v1 Role
csistoragecapacities storage.k8s.io/v1 CSIStorageCapacity

Now, from the above table, we can see that roles and rolebindings are under namespace scope, meaning that they are created within a namespace. If you do not specify a namespace, they will be created in the default namespace and control access to resources within that namespace.

Step 1: Create a Role

You can use the following command to get the verb for the resource.

Bash
kubectl api-resources --namespaced=true --sort-by name -o wide
role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["create", "delete"]
  - apiGroups: [""]
    resources: ["secrets"] # use * to allow all resources
    verbs: ["get"] # use * to allow all verbs
    resourceNames: ["secret-name", "my-secret"] # optional
  • apiGroups - The API group of the resource. If you are not sure, you can see the above table (API Version).
  • resourceNames - The names of the resources that the rule applies to. If you do not specify, the rule applies to all resources of the specified type.
    • In this example, the user can only read the secrets with the name secret-name and my-secret.
    • secret-name and my-secret are the names of the secrets (metadata name).
Bash
# You cannot create a role with different rules, as they will mix it up
kubectl create role developer --verb=get,watch,list --resource=pods
kubectl create role developer --verb=create,delete --resource=deployments.apps # need to append .apps due to apiGroups
kubectl create role developer --verb=get --resource=secrets --resource-name=secret-name --resource-name=my-secret

kubectl get roles

Step 2: Create a RoleBinding

Link the role to a user, group or service account.

rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
subjects: # users, groups, or service accounts
  - kind: User
    name: user1 # user name
    apiGroup: rbac.authorization.k8s.io
  - kind: Group
    name: backend-developers # group name
    apiGroup: rbac.authorization.k8s.io
  - kind: ServiceAccount
    name: my-service-account # service account name
    namespace: default # namespace of the service account
  - kind: Group
    name: system:serviceaccounts:default # all service accounts in the default namespace
    apiGroup: rbac.authorization.k8s.io
  - kind: Group
    name: system:serviceaccounts # all service accounts in any namespace
    apiGroup: rbac.authorization.k8s.io
  - kind: Group
    name: system:authenticated # all authenticated users
    apiGroup: rbac.authorization.k8s.io
  - kind: Group
    name: system:unauthenticated # all unauthenticated users
    apiGroup: rbac.authorization.k8s.io
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role # Role or ClusterRole
  name: developer # role name
  • You can also reference a ClusterRole instead of a role to grant the permissions defined in that ClusterRole to resources inside the RoleBinding's namespace. This kind of reference lets you define a set of common roles across your cluster, then reuse them within multiple namespaces.
Bash
kubectl create rolebinding developer-binding --role=developer --user=user1
kubectl create rolebinding developer-binding --role=developer --group=backend-developers

kubectl create rolebinding developer-binding --role=developer --serviceaccount=<namespace>:<service-account-name>
kubectl create rolebinding developer-binding --role=developer --serviceaccount=default:my-service-account

kubectl get rolebinding

Step 3: Verify the access (Optional)

You can check if the user have access to a resource by using the following command.

Bash
kubectl auth can-i delete nodes

kubectl auth can-i get pods --as <name-of-the-user>
kubectl auth can-i get pods --as developer

# check if the user can create deployments in the prod namespace
kubectl auth can-i create deployments --as developer --namespace prod

# Check if the group 'developers' can delete nodes
kubectl auth can-i delete nodes --as-group=developers

# Check if the service account 'my-service-account' in the 'default' namespace can get pods
kubectl auth can-i get pods --as=system:serviceaccount:default:my-service-account

# Check if the service account 'my-service-account' in the 'default' namespace can create deployments in the 'prod' namespace
kubectl auth can-i create deployments --as=system:serviceaccount:default:my-service-account --namespace=prod