Skip to content

Kubernetes kubeconfig and RBAC

Use this guide for a control plane you operate and for managed services that accept the equivalent OIDC fields. Complete Kubernetes and OIDC first.

Set these placeholders before adapting any example:

REALMROOT_ISSUER=https://id.example.com/api/auth
KUBERNETES_CLIENT_ID=APPLICATION_CLIENT_ID
ORGANIZATION_ID=REALMROOT_ORGANIZATION_ID
KUBERNETES_SERVER=https://kubernetes.example.com:6443

For the legacy flag-based configuration, add these arguments to every kube-apiserver instance:

--oidc-issuer-url=https://id.example.com/api/auth
--oidc-client-id=APPLICATION_CLIENT_ID
--oidc-username-claim=email
--oidc-username-prefix=-
--oidc-groups-claim=groups
--oidc-groups-prefix=
--oidc-required-claim=urn:realmroot:params:oauth:org=REALMROOT_ORGANIZATION_ID
--oidc-signing-algs=RS256

An empty groups prefix preserves Team names exactly. If your distribution cannot represent an empty argument, omit the groups-prefix flag only after confirming that the distribution does not add a default prefix.

Changing kube-apiserver arguments normally restarts the control plane. Keep an existing administrator kubeconfig until the OIDC path is verified.

Kubernetes 1.34+ structured authentication

Section titled “Kubernetes 1.34+ structured authentication”

Kubernetes 1.34 makes AuthenticationConfiguration stable. Save this file on every control-plane node and start kube-apiserver with --authentication-config=/etc/kubernetes/realmroot-authentication.yaml:

apiVersion: apiserver.config.k8s.io/v1
kind: AuthenticationConfiguration
jwt:
- issuer:
url: https://id.example.com/api/auth
audiences:
- APPLICATION_CLIENT_ID
audienceMatchPolicy: MatchAny
claimValidationRules:
- expression: "claims['urn:realmroot:params:oauth:org'] == 'REALMROOT_ORGANIZATION_ID'"
message: token is not issued for this Realmroot Organization
- expression: "claims.?email_verified.orValue(true) == true"
message: email must be verified when the claim is present
claimMappings:
username:
claim: email
prefix: ""
groups:
claim: groups
prefix: ""
uid:
claim: sub
userValidationRules:
- expression: "!user.username.startsWith('system:')"
message: username must not use the Kubernetes system prefix
- expression: "user.groups.all(group, !group.startsWith('system:'))"
message: groups must not use the Kubernetes system prefix

Do not configure --authentication-config and --oidc-* flags at the same time. Kubernetes treats that combination as a fatal configuration error.

Realmroot CLI does not currently implement the Kubernetes ExecCredential protocol. This guide uses the independent int128/kubelogin plugin:

Terminal window
brew install kubelogin
# or
kubectl krew install oidc-login

Choose one fixed loopback callback, for example http://127.0.0.1:8000. Add that exact URI to the Realmroot Application and use it consistently below.

Test the OIDC flow before editing kubeconfig:

Terminal window
kubectl oidc-login setup \
--oidc-issuer-url=https://id.example.com/api/auth \
--oidc-client-id=APPLICATION_CLIENT_ID \
--oidc-redirect-url=http://127.0.0.1:8000 \
--oidc-extra-scope=email \
--oidc-extra-scope=profile \
--oidc-extra-scope=groups \
--oidc-extra-scope=offline_access \
--oidc-pkce-method=S256

Confirm the displayed claims contain the expected Organization ID and Team names. Do not paste the token into an issue or log.

Fetch the cluster CA through your existing administrator access and encode the PEM certificate, not an administrator client certificate:

Terminal window
base64 < cluster-ca.pem | tr -d '\n'

Create a kubeconfig from this template:

apiVersion: v1
kind: Config
clusters:
- name: CLUSTER_NAME
cluster:
server: https://kubernetes.example.com:6443
certificate-authority-data: BASE64_CLUSTER_CA
users:
- name: realmroot
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: kubectl
interactiveMode: IfAvailable
provideClusterInfo: false
args:
- oidc-login
- get-token
- --oidc-issuer-url=https://id.example.com/api/auth
- --oidc-client-id=APPLICATION_CLIENT_ID
- --oidc-redirect-url=http://127.0.0.1:8000
- --oidc-extra-scope=email
- --oidc-extra-scope=profile
- --oidc-extra-scope=groups
- --oidc-extra-scope=offline_access
- --oidc-pkce-method=S256
- --token-cache-storage=keyring
contexts:
- name: CLUSTER_NAME
context:
cluster: CLUSTER_NAME
user: realmroot
current-context: CLUSTER_NAME

This file contains no user Token, Refresh Token, client secret, or administrator credential and can be distributed to authorized Organization members. Each user authenticates in their own browser. The keyring cache remains local.

Authentication alone grants no access. This namespace-scoped example lets the developers Team inspect workloads without reading Secrets:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: workload-reader
namespace: example
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developers-workload-reader
namespace: example
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: workload-reader
apiGroup: rbac.authorization.k8s.io

Avoid binding broad Teams to cluster-admin. If emergency bootstrap requires it, create a narrowly controlled binding and replace it with least-privilege roles after verification.

Terminal window
kubectl auth whoami
kubectl auth can-i list pods -n example
kubectl auth can-i list secrets -n example

The first command should show the user’s email and Realmroot Team names. The example policy should answer yes for Pods and no for Secrets.

To force the next command to authenticate again, clear kubelogin’s cached token using its cache command or remove the entry from the configured keyring. To revoke access, remove the user from the Team or Organization, then wait for the current ten-minute ID token to expire. Remove the OIDC configuration only after confirming another administrator path remains available.

See the Kubernetes documentation for authentication and RBAC.