From 1a50f51115e908df6a0f66c3bd48f6ea7b65bea1 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Mon, 12 Jan 2026 23:13:30 -0300 Subject: [PATCH] planka: enable project owners via oidc --- services/keycloak/realm-settings-job.yaml | 63 ++++++++++++++++++++++- services/planka/deployment.yaml | 6 +++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/services/keycloak/realm-settings-job.yaml b/services/keycloak/realm-settings-job.yaml index af595c1..108f141 100644 --- a/services/keycloak/realm-settings-job.yaml +++ b/services/keycloak/realm-settings-job.yaml @@ -2,7 +2,7 @@ apiVersion: batch/v1 kind: Job metadata: - name: keycloak-realm-settings-14 + name: keycloak-realm-settings-15 namespace: sso spec: backoffLimit: 0 @@ -251,6 +251,67 @@ spec: if status not in (201, 204): raise SystemExit(f"Unexpected group create response for {group_name}: {status}") + # Ensure Planka client exposes groups in userinfo for role mapping. + status, clients = http_json( + "GET", + f"{base_url}/admin/realms/{realm}/clients?clientId=planka", + access_token, + ) + planka_client = None + if status == 200 and isinstance(clients, list): + for item in clients: + if isinstance(item, dict) and item.get("clientId") == "planka": + planka_client = item + break + + if planka_client: + client_id = planka_client.get("id") + mapper_payload = { + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": False, + "config": { + "full.path": "false", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String", + }, + } + status, mappers = http_json( + "GET", + f"{base_url}/admin/realms/{realm}/clients/{client_id}/protocol-mappers/models", + access_token, + ) + existing = None + if status == 200 and isinstance(mappers, list): + for item in mappers: + if isinstance(item, dict) and item.get("name") == mapper_payload["name"]: + existing = item + break + + if existing and existing.get("id"): + mapper_payload["id"] = existing["id"] + status, _ = http_json( + "PUT", + f"{base_url}/admin/realms/{realm}/clients/{client_id}/protocol-mappers/models/{existing['id']}", + access_token, + mapper_payload, + ) + if status not in (200, 204): + raise SystemExit(f"Unexpected protocol mapper update response: {status}") + else: + status, _ = http_json( + "POST", + f"{base_url}/admin/realms/{realm}/clients/{client_id}/protocol-mappers/models", + access_token, + mapper_payload, + ) + if status not in (201, 204): + raise SystemExit(f"Unexpected protocol mapper create response: {status}") + # Ensure MFA is on by default for newly-created users. status, required_actions = http_json( "GET", diff --git a/services/planka/deployment.yaml b/services/planka/deployment.yaml index 0a3d93d..36fe4fd 100644 --- a/services/planka/deployment.yaml +++ b/services/planka/deployment.yaml @@ -66,6 +66,12 @@ spec: value: https://tasks.bstein.dev - name: TRUST_PROXY value: "true" + - name: OIDC_IGNORE_ROLES + value: "false" + - name: OIDC_PROJECT_OWNER_ROLES + value: "*" + - name: OIDC_ROLES_ATTRIBUTE + value: groups envFrom: - secretRef: name: planka-db