Resolve RBAC

Authentication answered who; it granted nothing. Before it answers, the apiserver checks RBAC: the group the token carried, prefixed to okta:app-k8s-admins, must appear as a ClusterRoleBinding subject.

Call sequence

human browser kubectl kubelogin plugin okta dev-12345678.okta.com kube-apiserver k3s-control:6443 step 1 GET /authorize sign in · MFA 302 → ?code POST /token id_token step 2 GET /api/v1/nodes GET discovery GET JWKS step 3 1 200 · nodes
  • a ClusterRoleBinding names okta:app-k8s-admins, so RBAC allows the request; no binding would be 403
  • the response is illustrative, like the cluster host
response 200 OK
{
  "kind": "NodeList",
  "apiVersion": "v1",
  "items": [
    {
      "metadata": {
        "name": "k3s-control"
      }
    }
  ]
}

The binding RBAC evaluates

resolved identity okta:lab-admin@authlab.app okta:app-k8s-admins

RBAC binding — ClusterRoleBinding

cat okta-cluster-admins.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: okta-cluster-admins
subjects:
  - kind: Group
    name: okta:app-k8s-admins    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

subjects[0].name ≡ "okta:" + token.groups[0] — the prefixed group the apiserver resolved in step 2

Without this binding the identity authenticates and can do nothing — authN and authZ are separate gates.

Same OIDC mechanics as the workload track, a different consumer: who validates the token is the variable.