TestBootstrapKit_BlueprintCardsHaveRequiredFields was failing on main for
9 blueprints because their platform/<name>/chart/Chart.yaml version had
been bumped without a matching update to platform/<name>/blueprint.yaml
spec.version. The pre-existing failure forced 7 recent PRs to self-merge
with --admin, masking real CI failures.
Aligned spec.version to match Chart.yaml version on:
cert-manager 1.1.1 -> 1.1.2
flux 1.1.3 -> 1.1.4
crossplane 1.1.3 -> 1.1.4
sealed-secrets 1.1.1 -> 1.1.2
spire 1.1.4 -> 1.1.7
nats-jetstream 1.1.1 -> 1.1.2
openbao 1.2.0 -> 1.2.14
keycloak 1.3.1 -> 1.3.2
gitea 1.2.1 -> 1.2.3
Verified locally:
$ go test ./... -run TestBootstrapKit_BlueprintCardsHaveRequiredFields -count=1
--- PASS: TestBootstrapKit_BlueprintCardsHaveRequiredFields (0.01s)
... all 10 sub-tests pass (cilium + the 9 above)
The existing test (tests/e2e/bootstrap-kit/main_test.go:145) is itself
the drift guardrail: it fails CI whenever Chart.yaml is bumped without a
matching blueprint.yaml bump. No additional script needed.
Closes #817 once verified on main.
Co-authored-by: Hatice Yildiz <hatice.yildiz@openova.io>
|
||
|---|---|---|
| .. | ||
| chart | ||
| blueprint.yaml | ||
| README.md | ||
Keycloak
User identity for Catalyst Sovereigns. Per-Sovereign supporting service in the Catalyst control plane (see docs/PLATFORM-TECH-STACK.md §2.3). Also serves as the FAPI Authorization Server for the Fingate (Open Banking) Blueprint.
Status: Accepted | Updated: 2026-04-27
Catalyst topology (set at Sovereign provisioning time, see
docs/SECURITY.md§6):
per-organization(SME-style Sovereigns, e.g. omantel): one minimal Keycloak per Organization (single replica, embedded H2/sqlite, ~150 MB RAM, no HA). Blast radius limited to one Org.shared-sovereign(corporate self-host, e.g. bankdhofar): one HA Keycloak for the entire Sovereign with multiple realms (one per Organization), federating to the corporation's identity provider (Azure AD, Okta).
Overview
Keycloak provides:
- User identity for the Catalyst console, marketplace, admin, REST/GraphQL API, and per-Application SSO.
- OIDC / OAuth 2.0 / SAML federation to corporate IdPs.
- FAPI 2.0 compliant authorization for the Fingate Open Banking Blueprint:
- PSD2/FAPI 2.0 certification path
- eIDAS certificate validation
- Consent management
- Multi-tenant TPP support (PSD2 sense — Third Party Providers, not platform tenants)
Architecture
flowchart TB
subgraph Keycloak["Keycloak"]
Core[Core IAM]
FAPI[FAPI Module]
Consent[Consent Service]
end
subgraph Backend["Backend"]
CNPG[CNPG Postgres]
end
subgraph Integration["Integration"]
Envoy[Envoy/Cilium]
TPP[TPP Registry]
end
Envoy -->|"ext_authz"| FAPI
FAPI --> Consent
Core --> CNPG
FAPI --> TPP
FAPI 2.0 Compliance
| Feature | Status |
|---|---|
| PKCE | Required |
| Signed JWT requests | Required |
| mTLS client auth | Required |
| PAR (Pushed Authorization) | Required |
| JARM responses | Required |
Configuration
Keycloak Deployment
The deployment shape depends on Catalyst's keycloakTopology choice (see banner above):
Corporate (shared-sovereign) — one HA Keycloak per Sovereign in catalyst-keycloak namespace on the management cluster:
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
namespace: catalyst-keycloak
spec:
instances: 3 # HA, multiple replicas
db:
vendor: postgres
host: keycloak-postgres-rw.catalyst-keycloak.svc
port: 5432
database: keycloak
usernameSecret: # ESO-managed via OpenBao
name: keycloak-db-credentials
key: username
passwordSecret:
name: keycloak-db-credentials
key: password
http:
tlsSecret: keycloak-tls
hostname:
hostname: auth.<location-code>.<sovereign-domain>
SME (per-organization) — one minimal Keycloak per Organization in the Org's namespace on the management cluster:
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
namespace: <org> # per-Org namespace
spec:
instances: 1 # no HA at SME tier
db:
vendor: postgres # or H2/sqlite for the smallest tier
host: keycloak-postgres-rw.<org>.svc
port: 5432
database: keycloak
# ... credentials
hostname:
hostname: auth.<org>.<location-code>.<sovereign-domain>
FAPI Realm Configuration
{
"realm": "open-banking",
"enabled": true,
"sslRequired": "all",
"attributes": {
"fapi.compliance.mode": "strict",
"pkce.required": "S256",
"require.pushed.authorization.requests": "true"
},
"clientPolicies": {
"policies": [
{
"name": "fapi-advanced",
"enabled": true,
"conditions": [
{
"condition": "client-roles",
"configuration": {
"roles": ["fapi-client"]
}
}
],
"profiles": ["fapi-2-security-profile"]
}
]
}
}
eIDAS Certificate Validation
TPP certificates are validated against qualified trust service providers:
apiVersion: v1
kind: ConfigMap
metadata:
name: eidas-config
namespace: open-banking
data:
trust-anchors: |
# QTSPs for eIDAS validation
- name: qualified-tsp-1
certificate: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
TPP Client Registration
{
"clientId": "tpp-12345",
"clientAuthenticatorType": "client-jwt",
"redirectUris": ["https://tpp.example.com/callback"],
"attributes": {
"tpp.authorization.number": "PSDGB-FCA-123456",
"tpp.eidas.certificate": "...",
"tpp.roles": ["AISP", "PISP"]
},
"defaultClientScopes": [
"openid",
"accounts",
"payments"
]
}
Consent Flow
sequenceDiagram
participant TPP
participant Keycloak
participant User
participant ConsentService
TPP->>Keycloak: PAR request
Keycloak->>TPP: request_uri
TPP->>User: Redirect to Keycloak
User->>Keycloak: Authenticate
Keycloak->>ConsentService: Get consent page
ConsentService->>User: Show accounts/permissions
User->>Keycloak: Grant consent
Keycloak->>ConsentService: Store consent
Keycloak->>TPP: Authorization code
High Availability
HA shape depends on Catalyst's keycloakTopology:
shared-sovereign(corporate): 3 replicas behind a Service, CNPG PostgreSQL with WAL streaming to async standby, session replication via Infinispan.per-organization(SME): single replica, no session replication, restart-on-deploy is acceptable for SME-tier SLAs. Larger SMEs can opt into HA via tier upgrade — same Catalyst CR shape, just bumpedinstances.
Part of OpenOva