TL;DR

Having get permissions to a Kubernetes object does not imply you have list permissions and vice versa.

This was not immediately obvious to me.

I figured that if you can list all objects of a certain kind (like secrets) you can also get an individual object by name, but that’s not the case.

Here’s how it works using Kubernetes Secrets as an example object:

  • If you only have get permissions, you will have to know the exact name of the secret you are trying to read beforehand. You can run a command like kubectl get secret <secret-name> successfully, but running kubectl get secrets will not work.

  • If you only have list permissions for secrets, you can run kubectl get secrets and see a list of secrets. But running kubectl get secret <secret-name> will not work.

  • There’s a tricky part: if you run kubectl get secrets -o yaml you will see a list of secrets and all of their contents. Having list permissions doesn’t mean you only get to list the names of the secrets, you can append -o yaml to the command and see all the contents as well. Just because you don’t have get permissions doesn’t mean you can’t see the contents of the objects.

Example with Minikube

I’ll be demonstrating the conclusion from above using Minikube. I’ll be creating the following in K8s: a Secret, two Roles, two Service Accounts, and two RoleBindings to assign get and list RBAC permissions to each service account for testing.

Here is a very long manifest that creates the following objects:

  • A namespace called example
  • A basic authentication secret called credentials in the example namespace
  • Two service accounts. One called service-account-1 and another called service-account-2
  • Two Roles:
    • A role named get-secrets that allows users associated with this role to get a secret.
    • A role named list-secrets that allows users to list secrets.
  • Two RoleBindings:
    • A RoleBinding named get-secrets-binding that will associate the service account service-account-1 with the get-secrets role.
    • A RoleBinding named list-secrets-binding that will associate the service account service-account-2 with the list-secrets role.
YAML
---
apiVersion: v1
kind: Namespace
metadata:
  name: example
  labels:
    name: example

---
apiVersion: v1
kind: Secret
metadata:
  namespace: example
  name: credentials
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: securepassword

---
  apiVersion: v1
  kind: ServiceAccount
  metadata:
    name: service-account-1
    namespace: example

---
  apiVersion: v1
  kind: ServiceAccount
  metadata:
    name: service-account-2
    namespace: example

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: example
  name: get-secrets
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: example
  name: list-secrets
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: get-secrets-binding
  namespace: example
subjects:
  - kind: ServiceAccount
    name: service-account-1
    namespace: example
roleRef:
  kind: Role
  name: get-secrets
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: list-secrets-binding
  namespace: example
subjects:
  - kind: ServiceAccount
    name: service-account-2
    namespace: example
roleRef:
  kind: Role
  name: list-secrets
  apiGroup: rbac.authorization.k8s.io

This manifest can be saved to a YAML file and applied like so:

Console
$ kubectl apply -f manifest.yaml

namespace/example created
secret/credentials created
serviceaccount/service-account-1 created
serviceaccount/service-account-2 created
role.rbac.authorization.k8s.io/get-secrets created
role.rbac.authorization.k8s.io/list-secrets created
rolebinding.rbac.authorization.k8s.io/get-secrets-binding created
rolebinding.rbac.authorization.k8s.io/list-secrets-binding created

Testing It All Out

Now we can test the get and list RBAC verbs with our service accounts.

To summarize:

  • The service account service-account-1 has get permissions for secrets in the example namespace. This service account should not be able to list secrets but should be able to get an individual secret in the example namespace.
  • The service account service-account-2 has list permissions for secrets in the example namespace. This service account should not be able to get an individual secret but should be able to list all secrets in the example namespace.

We can use the following command formula to test the permissions set to both service accounts:

Shell
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<namespace>:<serviceaccountname> -n <namespace>

Testing get Permissions

First let’s try getting a secret under both service accounts. We expect service-account-1 to be able to get a secret, but not service-account-2:

Console
$ kubectl auth can-i get secrets -n example --as=system:serviceaccount:example:service-account-1

yes
Console
$ kubectl auth can-i get secrets -n example --as=system:serviceaccount:example:service-account-2

no

Works as expected!

Now let’s try getting the credentials secret specifically that we created earlier, just to double check. We should get the same results as above.

Console
$ kubectl auth can-i get secrets/credentials -n example --as=system:serviceaccount:example:service-account-1

yes
Console
$ kubectl auth can-i get secrets/credentials -n example --as=system:serviceaccount:example:service-account-2

no

Works as expected.

Testing list Permissions

Next let’s try listing secrets under both service accounts. This time we expect service-account-2 to be able to list secrets, but not service-account-1:

Console
$ kubectl auth can-i list secrets -n example --as=system:serviceaccount:example:service-account-1

no
Console
$ kubectl auth can-i list secrets -n example --as=system:serviceaccount:example:service-account-2

yes

Works as expected once again.

Revealing Secret Data With Only list Permissions

Next, let’s try listing secrets with -o yaml to show that just because you don’t have get permissions it doesn’t mean you can’t see contents of secrets.

service-account-2 has list permissions but not get. If we try to get a specific Secret, Kubernetes doesn’t allow it. This is expected:

Console
$ kubectl get secret credentials -n example --as=system:serviceaccount:example:service-account-2

Error from server (Forbidden): secrets "credentials" is forbidden: User "system:serviceaccount:example:service-account-2" cannot get resource "secrets" in API group "" in the namespace "example"

Listing secrets does work, as expected.

Console
$ kubectl get secrets -n example --as=system:serviceaccount:example:service-account-2

NAME          TYPE                       DATA   AGE
credentials   kubernetes.io/basic-auth   2      9m38s

And if we add -o yaml to the command, we get the full YAML output for the Secret, revealing a username and password, despite not having get permissions:

Console
$ kubectl get secrets -n example -o yaml --as=system:serviceaccount:example:service-account-2

apiVersion: v1
items:
- apiVersion: v1
  data:
    password: c2VjdXJlcGFzc3dvcmQ=
    username: YWRtaW4=
  kind: Secret
  metadata:
    creationTimestamp: "2026-07-20T08:12:24Z"
    name: credentials
    namespace: example
    resourceVersion: "418"
    uid: bcd4013c-9ed5-4cdc-9436-9ff8dc7d9982
  type: kubernetes.io/basic-auth
kind: List
metadata:
  resourceVersion: ""

The data of each Secret is revealed under the data key in base64 encoding, which can easily be decoded:

Console
$ echo "YWRtaW4=" | base64 --decode

admin

$ echo "c2VjdXJlcGFzc3dvcmQ=" | base64 --decode

securepassword

Further Reading