Add the offline_access optional client scope to the `kubernetes` kubelogin client so the operator's kubectl can request long-lived OFFLINE refresh tokens (--oidc-extra-scope=offline_access) instead of being forced to re-auth on the realm's ONLINE session timeouts (ssoSessionIdleTimeout 30m / ssoSessionMaxLifespan 10h). Offline tokens honour offlineSessionIdleTimeout 30d with no hard max lifespan. - keycloak-realm-import.yaml: add optionalClientScopes: [offline_access] to the kubernetes client so a fresh realm import reproduces it. - k8s-oidc-rbac.yaml: document the kubeconfig exec-arg (--oidc-extra-scope=offline_access) + clear-cache/re-login steps. Realm session timeouts unchanged; scope is optional (opt-in) and client-only. Applied live via kcadm (reversible). Co-Authored-By: Claude Opus 4.8 <[email protected]>
69 lines
3.1 KiB
YAML
69 lines
3.1 KiB
YAML
---
|
|
# Kubernetes RBAC for Keycloak-federated (OIDC) users. The k3s API server is configured
|
|
# (infra/ansible roles/k3s_server) with:
|
|
# oidc-issuer-url=https://keycloak.home.keithjackson.dev/realms/homelab
|
|
# oidc-client-id=kubernetes oidc-username-claim=email oidc-username-prefix=oidc:
|
|
# oidc-groups-claim=groups oidc-groups-prefix=oidc:
|
|
# so a Keycloak group `platform-admins` appears to RBAC as the group `oidc:platform-admins`, and a
|
|
# user with email [email protected] as `oidc:[email protected]`. These bindings map the Keycloak group
|
|
# claim to cluster roles. Group-based (not user-based) so access follows Keycloak group membership
|
|
# with no per-user k8s change. Applied by platform-config (dependsOn platform).
|
|
#
|
|
# BREAK-GLASS: the cert-based admin in the bootstrap kubeconfig is unaffected by any of this and
|
|
# keeps full access even if Keycloak/OIDC is down — do not remove it.
|
|
#
|
|
# OPERATOR KUBECONFIG (kubelogin / int128 oidc-login) — the `keycloak-oidc` user exec block:
|
|
# users:
|
|
# - name: keycloak-oidc
|
|
# user:
|
|
# exec:
|
|
# apiVersion: client.authentication.k8s.io/v1beta1
|
|
# command: kubectl
|
|
# args:
|
|
# - oidc-login
|
|
# - get-token
|
|
# - --oidc-issuer-url=https://keycloak.home.keithjackson.dev/realms/homelab
|
|
# - --oidc-client-id=kubernetes
|
|
# - --oidc-extra-scope=offline_access # long-lived OFFLINE token — avoids frequent re-auth
|
|
# The `--oidc-extra-scope=offline_access` arg makes kubelogin request an OFFLINE refresh token instead
|
|
# of an ONLINE one, so the CLI is not forced to re-login on the realm's ONLINE session timeouts
|
|
# (ssoSessionIdleTimeout 30m / ssoSessionMaxLifespan 10h). Offline tokens honour offlineSessionIdleTimeout
|
|
# (30 days idle) with offlineSessionMaxLifespanEnabled=false (no hard cap). Backed by the `offline_access`
|
|
# OPTIONAL client scope on the `kubernetes` client (see keycloak-realm-import.yaml). After adding the arg,
|
|
# clear the cached ONLINE token once so the next login mints an offline one:
|
|
# kubectl oidc-login clean # (or: rm -f ~/.kube/cache/oidc-login/*)
|
|
# kubectl get nodes # re-login once to obtain the 30-day offline token
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: oidc-platform-admins
|
|
labels:
|
|
app.kubernetes.io/part-of: keycloak
|
|
homelab.keithjackson.dev/oidc-rbac: "true"
|
|
roleRef:
|
|
apiGroup: rbac.authorization.k8s.io
|
|
kind: ClusterRole
|
|
name: cluster-admin
|
|
subjects:
|
|
- apiGroup: rbac.authorization.k8s.io
|
|
kind: Group
|
|
name: "oidc:platform-admins"
|
|
---
|
|
# Read-only tier: the Keycloak `viewers` group gets the built-in `view` ClusterRole (read most
|
|
# resources cluster-wide, excluding Secrets and RBAC escalation paths).
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: oidc-viewers
|
|
labels:
|
|
app.kubernetes.io/part-of: keycloak
|
|
homelab.keithjackson.dev/oidc-rbac: "true"
|
|
roleRef:
|
|
apiGroup: rbac.authorization.k8s.io
|
|
kind: ClusterRole
|
|
name: view
|
|
subjects:
|
|
- apiGroup: rbac.authorization.k8s.io
|
|
kind: Group
|
|
name: "oidc:viewers"
|