From 34ff37edbfd20f6ab27e913c3a65eb2cd4ca517f Mon Sep 17 00:00:00 2001 From: Danijel Simeunovic Date: Thu, 23 Apr 2026 20:31:04 +0200 Subject: [PATCH] config --- .../backstage-keycloak-client-config.yaml | 43 +++++++++++++++++ docs/REFERENCE.md | 44 ++++++++++------- infra/base/backstage.yaml | 1 + infra/values/base/backstage-values.yaml | 48 ++++++++++++++++--- infra/values/upc-dev/backstage-values.yaml | 12 +++++ 5 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 cluster-resources/backstage-keycloak-client-config.yaml create mode 100644 infra/values/upc-dev/backstage-values.yaml diff --git a/cluster-resources/backstage-keycloak-client-config.yaml b/cluster-resources/backstage-keycloak-client-config.yaml new file mode 100644 index 0000000..7bfd34f --- /dev/null +++ b/cluster-resources/backstage-keycloak-client-config.yaml @@ -0,0 +1,43 @@ +# Self-service Keycloak client config for Backstage. +# Kyverno clones this to the keycloak namespace, where the +# keycloak-client-registrar CronJob processes it and creates +# the backstage-oidc-credentials Secret in the backstage namespace. +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-client-backstage + namespace: backstage + labels: + keycloak.forteapps.net/client-config: "true" +stringData: + client.json: | + { + "clientId": "backstage", + "name": "Backstage Developer Portal", + "redirectUris": ["https://backstage.forteapps.net/api/auth/oidc/handler/frame"], + "webOrigins": ["https://backstage.forteapps.net"], + "defaultClientScopes": ["openid", "email", "profile"], + "protocolMappers": [ + { + "name": "email_verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-hardcoded-claim-mapper", + "config": { + "claim.name": "email_verified", + "claim.value": "true", + "jsonType.label": "boolean", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ], + "secret": { + "namespace": "backstage", + "name": "backstage-oidc-credentials", + "keys": { + "clientId": "AUTH_OIDC_CLIENT_ID", + "clientSecret": "AUTH_OIDC_CLIENT_SECRET" + } + } + } diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index e722606..05e4c89 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -986,15 +986,18 @@ ignore: - Dynamic plugins: loads `dynamic-plugins.default.yaml` (all 27+ bundled plugins) - Catalog rules: Component, System, API, Resource, Location, Template, Group, User, Domain -**Dynamic Plugins**: -Add plugins at runtime via `global.dynamic.plugins` in values — no image rebuild: -```yaml -global: - dynamic: - plugins: - - package: "@scope/my-plugin@1.0.0" - integrity: "sha512-..." -``` +**Authentication** (Keycloak OIDC): +- Uses the self-service registrar pattern (see [Keycloak Client Registrar](#keycloak-client-registrar)) +- Config Secret: `cluster-resources/backstage-keycloak-client-config.yaml` +- Kyverno clones it → registrar creates `backstage-oidc-credentials` Secret in `backstage` namespace +- Credential keys: `AUTH_OIDC_CLIENT_ID`, `AUTH_OIDC_CLIENT_SECRET` (loaded via `extraEnvVarsSecrets`) +- Redirect URI: `https://backstage.forteapps.net/api/auth/oidc/handler/frame` +- Sign-in resolver: `emailMatchingUserEntityProfileEmail` + +**Catalog Discovery** (Gitea): +- Auto-discovers `catalog-info.yaml` from all repos in the `Forte` organization +- Scans every 30 minutes via the Gitea catalog provider plugin +- Gitea SCM integration configured for URL resolution (`git.forteapps.net`) **Catalog Registration**: Teams register services by adding a `catalog-info.yaml` to their repo root: @@ -1012,22 +1015,31 @@ spec: owner: team-name ``` -Then add the location to `backstage-values.yaml` under `upstream.backstage.appConfig.catalog.locations`. +Repos with this file are auto-discovered — no manual registration needed. -**Per-cluster Configuration**: -To set the ingress hostname, create a per-cluster overlay values file (e.g., `infra/values/upc-dev/backstage-values.yaml`) with: +**Dynamic Plugins**: +Add plugins at runtime via `global.dynamic.plugins` in values — no image rebuild: ```yaml global: - host: backstage.example.com + dynamic: + plugins: + - package: "@scope/my-plugin@1.0.0" + integrity: "sha512-..." +``` + +**Per-cluster Configuration** (`infra/values/upc-dev/backstage-values.yaml`): +```yaml +global: + host: backstage.forteapps.net upstream: backstage: appConfig: app: - baseUrl: https://backstage.example.com + baseUrl: https://backstage.forteapps.net backend: - baseUrl: https://backstage.example.com + baseUrl: https://backstage.forteapps.net ingress: - host: backstage.example.com + host: backstage.forteapps.net ``` ### Keycloak Client Registrar diff --git a/infra/base/backstage.yaml b/infra/base/backstage.yaml index 52de3f7..5130547 100644 --- a/infra/base/backstage.yaml +++ b/infra/base/backstage.yaml @@ -22,6 +22,7 @@ spec: releaseName: backstage valueFiles: - $values/infra/values/base/backstage-values.yaml + - $values/infra/values/upc-dev/backstage-values.yaml - repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git targetRevision: HEAD diff --git a/infra/values/base/backstage-values.yaml b/infra/values/base/backstage-values.yaml index 9edcb51..d425266 100644 --- a/infra/values/base/backstage-values.yaml +++ b/infra/values/base/backstage-values.yaml @@ -36,9 +36,12 @@ upstream: cpu: 1000m memory: 2560Mi + extraEnvVarsSecrets: + - backstage-oidc-credentials + appConfig: app: - title: "Forte Developer Portal" + title: "Forte Backstage" baseUrl: http://localhost:7007 backend: @@ -47,6 +50,27 @@ upstream: client: better-sqlite3 connection: ":memory:" + # -- Keycloak OIDC authentication + signInPage: oidc + auth: + environment: production + providers: + oidc: + production: + metadataUrl: https://id.forteapps.net/realms/forte/.well-known/openid-configuration + clientId: ${AUTH_OIDC_CLIENT_ID} + clientSecret: ${AUTH_OIDC_CLIENT_SECRET} + prompt: auto + signIn: + resolvers: + - resolver: emailMatchingUserEntityProfileEmail + + # -- Gitea SCM integration (for catalog URL resolution) + integrations: + gitea: + - host: git.forteapps.net + + # -- Software catalog catalog: rules: - allow: @@ -59,12 +83,22 @@ upstream: - Group - User - Domain - locations: [] - # Register components from Gitea repositories by adding: - # - type: url - # target: https://git.forteapps.net/Forte/my-repo/raw/branch/main/catalog-info.yaml - # rules: - # - allow: [Component, System, API] + providers: + # Auto-discover catalog-info.yaml from all Forte org repos + gitea: + forte: + organization: Forte + host: git.forteapps.net + catalogPath: catalog-info.yaml + schedule: + frequency: { minutes: 30 } + timeout: { minutes: 3 } + locations: + # Backstage's own org data (bootstrap teams, systems, domains) + # - type: url + # target: https://git.forteapps.net/Forte/backstage-catalog/raw/branch/main/org.yaml + # rules: + # - allow: [Group, User, System, Domain] ingress: enabled: true diff --git a/infra/values/upc-dev/backstage-values.yaml b/infra/values/upc-dev/backstage-values.yaml new file mode 100644 index 0000000..c0ffd25 --- /dev/null +++ b/infra/values/upc-dev/backstage-values.yaml @@ -0,0 +1,12 @@ +global: + host: backstage.forteapps.net + +upstream: + backstage: + appConfig: + app: + baseUrl: https://backstage.forteapps.net + backend: + baseUrl: https://backstage.forteapps.net + ingress: + host: backstage.forteapps.net