Try   HackMD

Does the call to TokenReview need a specific role?

I thought it was possible to use a token without any role to perform the TokenReview call to the Kubernetes API server.

But no: for the TokenReview call, the service account associated to the token used to authenticate (i.e., the Ahtorization: Bearer token HTTP header) must have the role system:auth-delegator.

On the other side, the token within the TokenReview doesn't need to have any role attached.

First, let us create a token with no role attached:

token=$(kubectl create --raw /api/v1/namespaces/default/serviceaccounts/default/token -f- <<EOF | jq -r '.status.token'
{
  "apiVersion": "authentication.k8s.io/v1",
  "kind": "TokenRequest",
  "spec": {
    "audiences": ["https://kubernetes.default.svc.cluster.local"]
  }
}
EOF
)

Now, let us use the TokenReview API to check that same token:

curl -sS -X POST $(kubectl config view --minify --flatten -ojson | jq '.clusters[0].cluster.server' -r)/apis/authentication.k8s.io/v1/tokenreviews \
  --cacert <( kubectl config view --minify --flatten -ojson | jq '.clusters[0].cluster."certificate-authority-data"' -r | base64 -d) \
  -H "Authorization: Bearer $token" \
  -H "Content-Type: application/json" \
  -d@- <<EOF
 {
  "apiVersion": "authentication.k8s.io/v1",
  "kind": "TokenReview",
  "spec": {
    "token": "$token",
    "audiences": ["https://kubernetes.default.svc.cluster.local"]
  }
}
EOF

gives:

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "tokenreviews.authentication.k8s.io is forbidden: User \"system:serviceaccount:default:default\" cannot create resource \"tokenreviews\" in API group \"authentication.k8s.io\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "group": "authentication.k8s.io",
    "kind": "tokenreviews"
  },
  "code": 403
}

To fix that:

kubectl apply -f- <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tokenreview
  namespace: default
subjects:
- kind: ServiceAccount
  namespace: default
  name: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
EOF

And now it works.

Testing TokenRequest for PR

kubectl run foo -n cert-manager --image=alpine/k8s:1.22.15 --restart=Never --overrides='{"spec":{"serviceAccountName": "cert-manager"}}' -q --rm -it -- bash

# And then, inside the container:
kubectl create --raw /api/v1/namespaces/sandbox/serviceaccounts/vault-issuer/token -f- <<EOF | jq -r '.status.token'
{
  "apiVersion": "authentication.k8s.io/v1",
  "kind": "TokenRequest",
  "spec": {
    "audiences": ["https://kubernetes.default.svc.cluster.local"],
    "expirationSeconds": 600
  }
}
EOF