Skip to content

Single sign-on (SAML)

OrbitalReg is a SAML 2.0 Service Provider (SP). Any SAML 2.0 IdP works; this section provides tested, step-by-step guides for the four most common self-hosted / enterprise IdPs, plus the Azure Entra ID default:

  • authentik
  • Okta
  • Keycloak
  • AD FS
  • Azure Entra ID — the chart default; see the inline comments in charts/orbitalreg/values-trial-saml.yaml.

Each guide covers provider creation, attribute/property mappings, the POST binding requirement, request-signing verification certificates, a ready-to-paste Helm values snippet (also shipped as charts/orbitalreg/values-<idp>.yaml.example), and a troubleshooting table built from real rollout findings.

How the SP side works

  • Endpoints. The SP mounts at /saml/ on your rootURL: /saml/metadata (SP metadata XML) and /saml/acs (Assertion Consumer Service, POST only).
  • Metadata-driven. At startup the API fetches saml.idpMetadataURL and takes the IdP's SSO endpoints and signing certificate from it. If the fetch fails, the pod logs saml init failed and crashes — fix the URL/TLS/DNS first.
  • Signed AuthnRequests. OrbitalReg signs its login requests (SignRequest: true) with the SP keypair (chart-generated self-signed by default, or your own via saml.existingSecret / saml.certPEM+saml.keyPEM). Some IdPs (authentik) must be given the SP public certificate to verify these requests.
  • Identity = email. The NameID / email claim identifies the user. Sessions are HMAC-signed cookies (8 h TTL); groups are baked into the session at login, so mapping changes require a full re-login.

Claims and the IdP presets

The SP reads up to four claims from the assertion: email (identity), display name, groups (multi-valued, mapped to roles), and an optional role claim. Which attribute names it looks for is controlled by saml.idpPreset — each preset matches that IdP's default property mappings / attribute statements, so you don't have to clone another vendor's claim URIs into your IdP:

PresetEmailDisplay nameGroupsRole
entra (default)xmlsoap …/emailaddress URIxmlsoap …/name URIMS 2008/06 …/groups URIMS 2008/06 …/role URI
authentikxmlsoap …/emailaddress URIxmlsoap …/name URIxmlsoap …/claims/Group URI
oktaemailnamegroups
keycloakurn:oid:1.2.840.113549.1.9.1urn:oid:2.16.840.1.113730.3.1.241memberRole
adfsxmlsoap …/emailaddress URIxmlsoap …/name URIxmlsoap …/claims/Group URIMS 2008/06 …/role URI

The full URIs are listed on each IdP's guide page. If your IdP emits custom attribute names, override any single field with saml.claimEmail / claimName / claimGroups / claimRole (env: ORBITALREG_SAML_CLAIM_*) — a non-empty override beats the preset for that field only.

From groups to roles

Group (and role-claim) values from the assertion are compared against auth.adminGroups / auth.developerGroups / auth.readerGroups. No match → default reader, which sees nothing until a project binding exists (see Tenancy model). Two practical consequences:

  1. The strings must match exactly what your IdP emits — display names for authentik/Keycloak/Okta, object-ID GUIDs for Entra.
  2. The lists also accept a login email address. That is the universal fallback: put your own email into auth.adminGroups, redeploy, re-login — you are org_admin even while group mapping is still broken, and can debug in peace.

Verify with https://<domain>/auth/whoami — check the groups and roles arrays after a complete logout + login.

Troubleshooting essentials (all IdPs)

SymptomCauseFix
Pod crashes, saml init failed in logSP cannot fetch idpMetadataURL (TLS, DNS, wrong path)curl the URL from the pod network; use the IdP's copy-URL button
"response code null" after clicking loginIdP metadata contains internal SSO URLs (metadata was fetched via an internal address)Point idpMetadataURL at the IdP's public URL
HTTP 405 after IdP loginIdP sends the SAML response via Redirect (GET) binding — the ACS accepts only POSTSet the SP/ACS binding to POST on the IdP side
404 on /saml/acsACS URL has a trailing slash or wrong path — the SP compares exactlyACS URL exactly https://<domain>/saml/acs
405 when opening /saml/acs in a browserNormal — GET on a POST-only endpointNot an error
Login works but roles: readerGroup values don't match auth.*Groups, or groups claim missingCheck /auth/whoami; see the per-IdP guide's mapping section; email fallback above
groups empty in whoamiMapping not attached to the provider, wrong attribute name/preset, or stale sessionFix mapping/preset; log out fully and back in

Operational monitoring for a down IdP is covered by the OrbitalRegSAMLDown runbook.

Released under the Apache-2.0 License.