Shuzheng
Shuzheng

Reputation: 14018

Why can't I execute `kubectl get pods --as=api-test -n default` using Service Account with access to Pod resources and GET verb?

I have the following api-test service account in the default namespace:

$ kubectl get serviceaccount api-test -n default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-03-05T17:15:40Z"
  name: api-test
  namespace: default
  resourceVersion: "27599"
  selfLink: /api/v1/namespaces/default/serviceaccounts/api-test
  uid: dd51ae9e-9729-4084-9e1e-b5421861b215
secrets:
- name: api-test-token-kz796

The api-test service account has role pod-reader through the following rolebinding:

$ kubectl get rolebinding api-test:pod-reader -n default -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"RoleBinding","metadata":{"annotations":{},"name":"api-test:pod-reader","namespace":"default"},"roleRef":{"apiGroup":"rbac.authorization.k8s.io","kind":"Role","name":"pod-reader"},"subjects":[{"kind":"ServiceAccount","name":"api-test"}]}
  creationTimestamp: "2020-03-17T11:03:36Z"
  name: api-test:pod-reader
  namespace: default
  resourceVersion: "374396"
  selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings/api-test:pod-reader
  uid: 5df0d84e-1d64-4750-9e3c-4026ec8193a4
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader
subjects:
- kind: ServiceAccount
  name: api-test

The pod-reader has access to pod resources and the get verb:

$ kubectl get role pod-reader -n default -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","metadata":{"annotations":{},"name":"pod-reader","namespace":"default"},"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["get","watch","list"]}]}
  creationTimestamp: "2020-03-17T10:47:39Z"
  name: pod-reader
  namespace: default
  resourceVersion: "373233"
  selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/roles/pod-reader
  uid: 19463c6a-3e68-4127-9c0a-ca1f7749af24
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - watch
  - list

However, the following kubectl get pods ... command fails in the default namespace, using user impersonation --as=api-test:

$ kubectl get pods --as=api-test -n default -v6
I0317 12:52:34.116634   63031 loader.go:359] Config loaded from file:  /Users/nlykkei/.kube/config
I0317 12:52:34.139588   63031 round_trippers.go:438] GET https://kubernetes.docker.internal:6443/api/v1/namespaces/default/pods?limit=500 403 Forbidden in 15 milliseconds
I0317 12:52:34.139857   63031 helpers.go:199] server response object: [{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "pods is forbidden: User \"api-test\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403
}]
F0317 12:52:34.139901   63031 helpers.go:114] Error from server (Forbidden): pods is forbidden: User "api-test" cannot list resource "pods" in API group "" in the namespace "default"

Checking the authorizations for api-test reveals that it has get access to /api/*:

$ kubectl auth can-i --list --as=api-test -n default
Resources                                       Non-Resource URLs   Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                  []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []               [create]
                                                [/api/*]            []               [get]
                                                [/api]              []               [get]
                                                [/apis/*]           []               [get]
                                                [/apis]             []               [get]
                                                [/healthz]          []               [get]
                                                [/healthz]          []               [get]
                                                [/openapi/*]        []               [get]
                                                [/openapi]          []               [get]
                                                [/version/]         []               [get]
                                                [/version/]         []               [get]
                                                [/version]          []               [get]
                                                [/version]          []               [get]

Why can't my api-test service account be used to retrieve information about pods in the default namespace?

Indeed, the URL output by kubectl matches the wildcard path /api/*:

https://kubernetes.docker.internal:6443/api/v1/namespaces/default/pods?limit=500

Any ideas?

Upvotes: 2

Views: 863

Answers (2)

Nicolas Lykke Iversen
Nicolas Lykke Iversen

Reputation: 4250

You should use --as=system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT) to authenticate to the API server.

In your example, that is --as=system:serviceaccount:default:api-test.

The details are available in the Kubernetes documentation:

Service accounts authenticate with the username system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT), and are assigned to the groups system:serviceaccounts and system:serviceaccounts:(NAMESPACE).

https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens

Upvotes: 4

Arghya Sadhu
Arghya Sadhu

Reputation: 44657

Command to create role and rolebinding

kubectl create role pod-reader --resource=pods --verb=get,list,watch --namespace=default 

kubectl create rolebinding pod-reader-role-binding --role=pod-reader --serviceaccount=default:api-test -n default

Command to check permission should be

kubectl auth can-i get pods -n default --as=system:serviceaccount:api-test:default

yes

Access the resource

kubectl get pods --as=system:serviceaccount:default:api-test -n default

Upvotes: 3

Related Questions