kubernetes
Security
Authorization

Authorization

Authorization Mechanisms (Modes)

Refer here (opens in a new tab) for more details.

In summary;

ModeDescription
AlwaysAllowAllows all requests without any authorization checks.
AlwaysDenyBlocks all requests.
Node AuthorizationA special-purpose authorization mode that authorizes API requests made by kubelets.
ABACIt defines an access control paradigm whereby access rights are granted to users through the use of policies that combine attributes together.
RBACIt is a method of regulating (control) access to resources in a Kubernetes cluster based on the roles of individual users or service accounts.
WebhookA 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.

--authorization-mode=RBAC,ABAC,Webhook

Node Authorization

ℹ️

The node authorizer only handles node requests.

Reference (opens in a new tab)

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 (opens in a new tab)

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.

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.json
{"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.

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.

Role-based Access Control (RBAC)

ℹ️

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

Reference (opens in a new tab)

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).

# 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
NameAPI VersionKind
bindingsv1Binding
configmapsv1ConfigMap
endpointsv1Endpoints
eventsv1Event
limitrangesv1LimitRange
persistentvolumeclaimsv1PersistentVolumeClaim
podsv1Pod
podtemplatesv1PodTemplate
replicationcontrollersv1ReplicationController
resourcequotasv1ResourceQuota
secretsv1Secret
serviceaccountsv1ServiceAccount
servicesv1Service
controllerrevisionsapps/v1ControllerRevision
daemonsetsapps/v1DaemonSet
deploymentsapps/v1Deployment
replicasetsapps/v1ReplicaSet
statefulsetsapps/v1StatefulSet
localsubjectaccessreviewsauthorization.k8s.io/v1LocalSubjectAccessReview
horizontalpodautoscalersautoscaling/v2HorizontalPodAutoscaler
cronjobsbatch/v1CronJob
jobsbatch/v1Job
leasescoordination.k8s.io/v1Lease
endpointslicesdiscovery.k8s.io/v1EndpointSlice
eventsevents.k8s.io/v1Event
ingressesnetworking.k8s.io/v1Ingress
networkpoliciesnetworking.k8s.io/v1NetworkPolicy
poddisruptionbudgetspolicy/v1PodDisruptionBudget
contourconfigurationsprojectcontour.io/v1alpha1ContourConfiguration
contourdeploymentsprojectcontour.io/v1alpha1ContourDeployment
extensionservicesprojectcontour.io/v1alpha1ExtensionService
httpproxiesprojectcontour.io/v1HTTPProxy
tlscertificatedelegationsprojectcontour.io/v1TLSCertificateDelegation
rolebindingsrbac.authorization.k8s.io/v1RoleBinding
rolesrbac.authorization.k8s.io/v1Role
csistoragecapacitiesstorage.k8s.io/v1CSIStorageCapacity

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.

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).
# 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.
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.

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