new
This commit is contained in:
@@ -14,6 +14,10 @@ stringData:
|
||||
{
|
||||
"clientId": "backstage",
|
||||
"name": "Backstage Developer Portal",
|
||||
"serviceAccountsEnabled": true,
|
||||
"serviceAccountRoles": {
|
||||
"realm-management": ["view-users", "query-users", "view-groups", "query-groups"]
|
||||
},
|
||||
"redirectUris": ["https://backstage.forteapps.net/api/auth/oidc/handler/frame"],
|
||||
"webOrigins": ["https://backstage.forteapps.net"],
|
||||
"defaultClientScopes": ["openid", "email", "profile"],
|
||||
|
||||
@@ -997,6 +997,7 @@ ignore:
|
||||
- **Important**: `dangerouslyAllowSignInWithoutUserInCatalog` must be nested inside the resolver object, not at the provider level
|
||||
|
||||
**Keycloak User/Group Sync**:
|
||||
- The `backstage` Keycloak client has `serviceAccountsEnabled: true` with `realm-management` roles (`view-users`, `query-users`, `view-groups`, `query-groups`) — assigned automatically by the registrar
|
||||
- The `keycloakOrg` catalog provider auto-imports users and groups from the `forte` realm
|
||||
- Requires the Keycloak dynamic plugin to be enabled (pre-installed but disabled by default in RHDH)
|
||||
- Syncs every 30 minutes with 15-second initial delay
|
||||
@@ -1082,9 +1083,10 @@ upstream:
|
||||
2. For each config Secret, parses `client.json` and computes a config hash
|
||||
3. Skips if hash matches annotation and credential Secret already exists
|
||||
4. Creates or updates the Keycloak client via Admin API
|
||||
5. Fetches the generated client secret
|
||||
6. Upserts credential Secret in target namespace + central `secrets` namespace
|
||||
7. Annotates config Secret with sync status, config hash, and timestamp
|
||||
5. If `serviceAccountsEnabled: true` and `serviceAccountRoles` defined, assigns service account roles (e.g., `realm-management` → `view-users`)
|
||||
6. Fetches the generated client secret
|
||||
7. Upserts credential Secret in target namespace + central `secrets` namespace
|
||||
8. Annotates config Secret with sync status, config hash, and timestamp
|
||||
|
||||
**Resources**:
|
||||
- `ServiceAccount`: `keycloak-client-registrar` (namespace: `keycloak`)
|
||||
|
||||
@@ -22,9 +22,9 @@ route:
|
||||
upstream:
|
||||
backstage:
|
||||
image:
|
||||
registry: quay.io
|
||||
repository: rhdh-community/rhdh
|
||||
tag: next
|
||||
registry: ghcr.io
|
||||
repository: vfarcic/idp-full-backstage
|
||||
tag: 0.0.3
|
||||
|
||||
podSecurityContext:
|
||||
runAsUser: 1001
|
||||
|
||||
@@ -371,7 +371,7 @@ extraDeploy:
|
||||
continue
|
||||
fi
|
||||
|
||||
# Build Keycloak client representation (strip our secret delivery config)
|
||||
# Build Keycloak client representation (strip our secret/role delivery config)
|
||||
KC_CLIENT=$(echo "$CLIENT_JSON" | jq '{
|
||||
clientId: .clientId,
|
||||
name: .name,
|
||||
@@ -379,6 +379,7 @@ extraDeploy:
|
||||
protocol: "openid-connect",
|
||||
clientAuthenticatorType: "client-secret",
|
||||
standardFlowEnabled: true,
|
||||
serviceAccountsEnabled: (.serviceAccountsEnabled // false),
|
||||
directAccessGrantsEnabled: false,
|
||||
publicClient: false,
|
||||
redirectUris: .redirectUris,
|
||||
@@ -426,6 +427,56 @@ extraDeploy:
|
||||
# Sync credentials to target namespace
|
||||
sync_credentials "$CLIENT_ID" "$CLIENT_UUID" "$CRED_NS" "$CRED_NAME" "$CRED_ID_KEY" "$CRED_SECRET_KEY"
|
||||
|
||||
# Assign service account roles if serviceAccountsEnabled
|
||||
SA_ENABLED=$(echo "$CLIENT_JSON" | jq -r '.serviceAccountsEnabled // false')
|
||||
SA_ROLES_JSON=$(echo "$CLIENT_JSON" | jq -c '.serviceAccountRoles // empty')
|
||||
if [ "$SA_ENABLED" = "true" ] && [ -n "$SA_ROLES_JSON" ]; then
|
||||
echo " Assigning service account roles for '${CLIENT_ID}'"
|
||||
# Get the service account user for this client
|
||||
SA_USER_ID=$(curl -sf -H "Authorization: Bearer ${TOKEN}" \
|
||||
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/service-account-user" \
|
||||
| jq -r '.id // empty')
|
||||
if [ -z "$SA_USER_ID" ]; then
|
||||
echo " WARNING: Could not get service account user for '${CLIENT_ID}'"
|
||||
else
|
||||
# Iterate over each target client and its roles
|
||||
echo "$SA_ROLES_JSON" | jq -r 'keys[]' | while read -r TARGET_CLIENT_ID; do
|
||||
# Get the target client's UUID
|
||||
TARGET_UUID=$(curl -sf -H "Authorization: Bearer ${TOKEN}" \
|
||||
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients?clientId=${TARGET_CLIENT_ID}" \
|
||||
| jq -r '.[0].id // empty')
|
||||
if [ -z "$TARGET_UUID" ]; then
|
||||
echo " WARNING: Target client '${TARGET_CLIENT_ID}' not found"
|
||||
continue
|
||||
fi
|
||||
# Get available roles from the target client
|
||||
AVAILABLE_ROLES=$(curl -sf -H "Authorization: Bearer ${TOKEN}" \
|
||||
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${TARGET_UUID}/roles")
|
||||
# Build the role payload from requested role names
|
||||
ROLE_PAYLOAD=$(echo "$SA_ROLES_JSON" | jq -c --arg tc "$TARGET_CLIENT_ID" --argjson avail "$AVAILABLE_ROLES" '
|
||||
.[$tc] as $wanted |
|
||||
[$avail[] | select(.name as $n | $wanted | index($n))]
|
||||
')
|
||||
ROLE_COUNT=$(echo "$ROLE_PAYLOAD" | jq 'length')
|
||||
if [ "$ROLE_COUNT" = "0" ]; then
|
||||
echo " WARNING: No matching roles found for '${TARGET_CLIENT_ID}'"
|
||||
continue
|
||||
fi
|
||||
# Assign the roles to the service account
|
||||
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST -d "$ROLE_PAYLOAD" \
|
||||
"${KEYCLOAK_URL}/admin/realms/${REALM}/users/${SA_USER_ID}/role-mappings/clients/${TARGET_UUID}")
|
||||
if [ "$HTTP_CODE" = "204" ] || [ "$HTTP_CODE" = "200" ]; then
|
||||
echo " Assigned ${ROLE_COUNT} roles from '${TARGET_CLIENT_ID}'"
|
||||
else
|
||||
echo " WARNING: Failed to assign roles from '${TARGET_CLIENT_ID}' (HTTP ${HTTP_CODE})"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Annotate config Secret with hash and sync status
|
||||
annotate_secret "keycloak" "$CONFIG_NAME" "keycloak.forteapps.net/config-hash" "$CONFIG_HASH"
|
||||
annotate_secret "keycloak" "$CONFIG_NAME" "keycloak.forteapps.net/sync-status" "synced"
|
||||
|
||||
Reference in New Issue
Block a user