Checking API Access
January 2024
This blog post describes using the command line tool to check API access in Kubernetes. It especially focuses on the difference between the kubectl and --user options of the kubectl command line tool.--as
Role-based access control
Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within your organization.
It is advised to go through the Kubernetes RBAC documentation before reading ahead.
Checking API Access
The command can be used to determine whether a user has permissions to execute a certain action.kubectl auth can-i
Default Admin User
In the first example, we will work with the default admin user.
kubectl config get-contexts minikube
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* minikube minikube minikube default
minikube installation.kubectl config view -o jsonpath='{.contexts[?(@.name=="minikube")].context.user}'
minikube
| A user in Kubernetes is nothing but a key and certificate pair issued by the Kubernetes cluster and presented to the Kubernetes API. |
kubectl config view -o jsonpath='{.users[?(@.name=="minikube")].user.client-certificate}'
/Users/adityasamant/.minikube/profiles/minikube/client.crt
openssl x509 -in /Users/adityasamant/.minikube/profiles/minikube/client.crt -text -noout | grep Subject | grep -v "Public Key Info"
Subject: O=system:masters, CN=minikube-user
As can be seen above, the minikube admin user is part of the group.system:masters
|
system:masters is a group which is hardcoded into the Kubernetes API server source code as having unrestricted rights to the Kubernetes API server. Any user who is a member of this group has full cluster-admin rights to the cluster. Even if every cluster role and role is deleted from the cluster, users who are members of this group retain full access to the cluster. |
Use the command to verify a few scenarios.kubectl auth can-i
kubectl auth can-i create pods
yes
kubectl auth can-i create deployments
yes
kubectl auth can-i delete secrets
yes
Normal User
Configure a normal user and verify how the commands can be used to check the access.
To do this we need to issue a certificate for the user.kubectl auth can-i
openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -out jane.csr -subj "/CN=jane"
This will generate a private key named and a certificate signing request named jane.key.jane.csr
cat jane.csr | base64 | tr -d "\n"
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: csr-name (1)
spec:
request: base64 encoded csr (2)
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF
| 1 | Provide the name as |
| 2 | Provide the base64 encoded value of the CSR |
kubectl get csr jane
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
jane 55s kubernetes.io/kube-apiserver-client minikube-user 24h Pending
kubectl certificate approve jane
kubectl get csr jane
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
jane 2m17s kubernetes.io/kube-apiserver-client minikube-user 24h Approved,Issued
Granting permissions via RBAC
clusterrole granting permissions to only create podskubectl create clusterrole createpods --verb=create --resource=pods
clusterrole.rbac.authorization.k8s.io/createpods created
clusterrolebinding to bind the clusterrole with user janekubectl create clusterrolebinding createpods --clusterrole=createpods --user=jane
clusterrolebinding.rbac.authorization.k8s.io/createpods created
Difference between 'as' and 'user' options of kubectl
kubectl has a number of global that can be passed as an argument to any kubectl command. The list can be found with the following command:options
kubectl options
Two of the options are and --user. It is important to understand the difference between them.--as
--user='':
The name of the kubeconfig user to use
--as='':
Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
|
The The |
Let’s put the theory into action with the help of the user we created.
Using --as to Check Access
kubectl auth can-i create pods --as=jane
yes
kubectl auth can-i create deployments --as=jane
no
kubectl auth can-i delete secrets --as=jane
no
Due to the fact that we explicitly assigned the to clusterrole createpods, we see that user jane has access to create pods, but no access to create deployments or delete secrets.
Great, this is as expected.jane
Using --user to Check Access
Try the same commands, but this time using the --user option
kubectl auth can-i create pods --user=jane
error: auth info "jane" does not exist
The command leads to an error. This is because we have not configured the user in the jane file.kubeconfig
Fix that by adding the user to the jane file.kubeconfig
Adding the user to kubeconfig
kubectl get csr jane -o jsonpath='{.status.certificate}'| base64 -d > jane.crt
kubeconfigkubectl config set-credentials jane --client-key=jane.key --client-certificate=jane.crt --embed-certs=true
User "jane" set.
kubeconfigkubectl config set-context jane --cluster=minikube --user=jane
Context "jane" created.
Let’s try the command once again to verify the permissions on user jane:kubectl auth can-i
kubectl auth can-i create pods --user=jane
yes
kubectl auth can-i create deployments --user=jane
no
kubectl auth can-i delete secrets --user=jane
no
Now everything works as expected.
The --as option does not check the actual presence of the user in the . It only checks the explicitly configured roles and bindings that are bound to a user and returns a response based on that.
|
kubectl auth can-i create pods --as=nobody
no
Custom Admin User
Configure a new admin user and verify the behaviour of the commands.kubectl auth can-i
This time we will check the permissions that a user inherits via the group it is attached to.
Issue a certificate for the new admin user.
openssl genrsa -out poweruser.key 2048
openssl req -new -key poweruser.key -out poweruser.csr -subj "/CN=poweruser/O=system:masters" (1)
| 1 | CN is the name of the user and O is the group that this user will belong to. |
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: csr-name (1)
spec:
request: base64 encoded csr (2)
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF
| 1 | Provide the name as |
| 2 | Provide the base64 encoded value of the CSR |
|
The above command throws an error as the |
Granting permissions via RBAC through groups
In order to create a new admin user we will create a custom admin group that replicates the behaviour of the group. Let’s call it system:mastersexample:masters
To do this, create a new as below:clusterrolebinding
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: example-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: example:masters
EOF
Add the new admin user to the groupexample:masters
poweruserrm poweruser.key poweruser.csr
openssl genrsa -out poweruser.key 2048
openssl req -new -key poweruser.key -out poweruser.csr -subj "/CN=poweruser/O=example:masters"
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: csr-name (1)
spec:
request: base64 encoded csr (2)
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF
| 1 | Provide the name as |
| 2 | Provide the base64 encoded value of the CSR |
kubectl certificate approve poweruser
certificatesigningrequest.certificates.k8s.io/poweruser approved
kubectl get csr poweruser -o jsonpath='{.status.certificate}'| base64 -d > poweruser.crt
openssl x509 -in poweruser.crt -text -noout | grep Subject | grep -v "Public Key Info"
Subject: O=example:masters, CN=poweruser (1)
| 1 | The user is associated with the group |
Add the new admin user to kubeconfig
kubectl config set-credentials poweruser --client-key=poweruser.key --client-certificate=poweruser.crt --embed-certs=true
User "poweruser" set.
kubectl config set-context poweruser --cluster=minikube --user=poweruser
Context "poweruser" created.
Try the command to verify the permissions on the new admin user:kubectl auth can-i
kubectl auth can-i create pods --user=poweruser
yes
kubectl auth can-i create deployments --user=poweruser
yes
kubectl auth can-i delete secrets --user=poweruser
yes
Try the same commands but with using the --as option.
kubectl auth can-i create pods --as=poweruser
no
kubectl auth can-i create deployments --as=poweruser
no
kubectl auth can-i delete secrets --as=poweruser
no
Strange. The output expected was for all 3 commands as yes is an admin user with full access to the cluster.poweruser
We can prove this as follows:
poweruserkubectl config use-context poweruser
kubectl run nginx --image=nginx
pod/nginx created
kubectl create deployment nginx-deploy --image=nginx
deployment.apps/nginx-deploy created
kubectl create secret generic test-secret --from-literal=secret=1234
secret/test-secret created
kubectl delete secrets test-secret
secret "test-secret" deleted
|
My first thought was that this is a defect in Kubernetes. The reality is that the behaviour is as-expected. The API server has no knowledge of group membership apart from what is encoded directly in the credential or provided by a token webhook. To overcome this you need to pass the group you want to impersonate with the |
The 'as-group' option of kubectl
Try the same commands but this time append the option as well.--as-group
kubectl auth can-i create pods --as=poweruser --as-group=example:masters
yes
kubectl auth can-i create deployments --as=poweruser --as-group=example:masters
yes
kubectl auth can-i delete secrets --as=poweruser --as-group=example:masters
yes
Now the results are as expected.
Summary
The command behaves differently for the kubectl auth can-i and --user options.--as
The option checks for the actual presence of the user in the --user file and has the ability[.nobr] to check permissions derived from the group of the user.kubeconfig
The option can be used to check permissions for any user irrespective of its presence in the --as file. It checks permissions which are directly bound to the user through RBAC, and does not check permissions that are derived from the user’s group. The API server has no knowledge of group membership apart from whatever is encoded directly in the credential or provided by a token webhook.kubeconfig
The option should be used to check for permissions that are derived from the user’s group.--as-group