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 jane
kubectl 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
kubeconfig
kubectl config set-credentials jane --client-key=jane.key --client-certificate=jane.crt --embed-certs=true
User "jane" set.
kubeconfig
kubectl 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:masters
example: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
poweruser
rm 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:
poweruser
kubectl 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