Enterprise User Federation¶
AKKO is designed to plug directly into your existing corporate identity infrastructure. You do not have to maintain a parallel set of credentials for your data team — AKKO brokers authentication through Keycloak and maps your corporate groups to platform roles.
This page is the single source of truth for customers bringing their own users. For step-by-step configuration of specific IdPs (Azure AD, Okta, Google, LDAP), see External Identity Provider Integration.
Overview — Three Authentication Modes¶
AKKO supports three deployment modes controlled by
global.auth.mode in your Helm values file:
| Mode | Who owns users? | When to use |
|---|---|---|
demo (default) |
Bundled directory service with seed users (alice, bob, carol, eve, dave) |
First-time evaluation, demos, internal POC |
enterprise-ldap |
Your corporate AD / OpenLDAP / FreeIPA | On-premises enterprises with a directory service |
enterprise-oidc |
External OIDC IdP (Azure AD / Entra ID, Okta, Auth0, external Keycloak) | Cloud-native SSO, federation across tenants |
All three modes result in a consistent experience inside AKKO: users log in once, receive a JWT with platform roles, and every service (Trino, Superset, Airflow, Dashboards, JupyterHub, MLflow, ADEN, ...) honours the same RBAC matrix.
Authentication Flow¶
sequenceDiagram
autonumber
actor User as Corporate user
participant IdP as Your IdP (AD / Azure / Okta)
participant KC as Keycloak (AKKO)
participant OP as oauth2-proxy
participant CP as Cockpit / UI
participant TR as Trino + OPA
User->>CP: 1. GET https://cockpit.<your-domain>
CP->>OP: 2. Unauthenticated request
OP->>KC: 3. Redirect to OIDC authorize endpoint
KC->>IdP: 4. Delegate to corporate IdP (brokering or federation)
IdP-->>User: 5. Prompt (password / MFA / SSO cookie)
User-->>IdP: 6. Credentials
IdP-->>KC: 7. ID token + groups claim
KC-->>OP: 8. AKKO JWT (sub, email, roles, attributes)
OP-->>CP: 9. Set session cookie, forward X-Auth-* headers
CP-->>User: 10. Render cockpit
User->>TR: 11. SQL query via Trino JDBC (Bearer token)
TR->>OPA: 12. OPA decision (role, column mask, row filter)
OPA-->>TR: 13. Allow / deny / mask
TR-->>User: 14. Result set (PII masked per role)
Every service protected by oauth2-proxy or OIDC (Superset, Airflow,
Dashboards, Trino, MLflow, JupyterHub, object storage, OpenMetadata) follows the
same flow. ABAC attributes (data-scope, column-mask, row-filter,
ai-tier) propagate from the IdP claim into the Trino + OPA decision.
Mode 1 — demo (default)¶
When to use: first install, local evaluation, airgapped demos, internal POC, training environments.
What you get:
- Bundled directory service pod with 5 seed users:
alice(admin),bob(engineer),carol(analyst),eve(user),dave(viewer) - 2 service accounts (
svc-aden,svc-superset) - Keycloak is federated to directory service automatically by the
akko-lldap-federationinit job - Passwords are generated at install time, stored in
Kubernetes Secret
akko-demo-users, and surfaced bybash helm/scripts/show-dev-credentials.sh
Helm values (the default — no change required):
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
alice cannot log in |
akko-lldap-federation job did not complete |
kubectl logs -n akko job/akko-lldap-federation; re-run helm upgrade |
| Password rejected | Secret rotated, Keycloak still has old hash | bash helm/scripts/rotate-secrets.sh --reset-demo-users |
| Keycloak admin lockout | Bootstrap admin password lost | Re-create secret akko-keycloak-admin, rolling restart Keycloak |
| User sees empty sidebar | No roles attached in directory service group | Add user to akko-admin / akko-engineer / ... directory service group, run federation job |
| Case-sensitive login fails | caseInsensitive: true not active in realm |
Check global.auth.caseInsensitive and Keycloak realm attribute |
Never keep demo mode in production
The seed users have well-known names. Before any production cutover,
set mode: enterprise-ldap or mode: enterprise-oidc, disable
akko-lldap, and run the production checklist.
Mode 2 — enterprise-ldap¶
When to use: on-premises organisations with Active Directory, OpenLDAP, FreeIPA, or another LDAP v3-compatible directory.
What AKKO does for you:
- Keycloak User Federation is configured via the
configure-federationinit job (Keycloak Admin REST API, idempotent). - A group-to-role mapper is created from
global.auth.ldap.roleMapping. - The bundled directory service is disabled.
- The initial admin (
initialAdmin.username) is kept as a break-glass local account.
Helm values:
global:
auth:
mode: "enterprise-ldap"
initialAdmin:
enabled: true
username: "admin-akko"
email: "admin-akko@corp.example.com"
# password: provided via Secret akko-admin-bootstrap (key=password)
ldap:
connectionUrl: "ldaps://ad.corp.example.com:636"
bindDn: "cn=svc-akko,ou=service,dc=corp,dc=com"
bindCredentialSecret: "akko-ldap-bind" # Secret key: password
usersDn: "ou=employees,dc=corp,dc=com"
groupsDn: "ou=groups,dc=corp,dc=com"
usernameLDAPAttribute: "sAMAccountName" # "uid" for OpenLDAP/FreeIPA
vendor: "ad" # "other" for OpenLDAP/FreeIPA
syncPeriodSeconds: 300
roleMapping:
akko-admin: ["IT-Admins", "Platform-Admins"]
akko-engineer: ["Data-Engineers", "DevOps"]
akko-analyst: ["Business-Analysts", "BI-Team"]
akko-steward: ["Data-Stewards"]
akko-user: ["Compliance", "Finance"]
akko-viewer: ["Management", "Executives"]
akko-lldap:
enabled: false
Create the bind secret before installing:
kubectl create namespace akko
kubectl create secret generic akko-ldap-bind \
--from-literal=password='<LDAP_BIND_PASSWORD>' \
-n akko
Deploy:
helm upgrade --install akko helm/akko/ -n akko --create-namespace \
--wait --wait-for-jobs --timeout 20m \
-f helm/examples/values-domain.yaml \
-f helm/examples/values-enterprise.yaml \
-f values-ldap-overrides.yaml \
--set-file akko-keycloak.realm.data=helm/examples/realm-domain.json
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Connection refused" in federation job | Firewall / wrong port | Verify pod-to-LDAP reachability: kubectl exec -it deploy/akko-keycloak -- nc -vz ad.corp.example.com 636 |
| Users sync but have no roles | Group-to-role mapper absent | Check job logs akko-keycloak-federation; re-run helm upgrade |
| TLS handshake failure | Keycloak doesn't trust AD CA | Add CA to akko-keycloak.extraVolumes and JAVA_OPTS_APPEND=-Djavax.net.ssl.trustStore=... |
| Many duplicate users in Keycloak | READ_ONLY not enforced |
Set editMode: READ_ONLY in federation config; delete duplicates |
| Sync period too slow | Default 24h | Reduce syncPeriodSeconds (300 recommended for dev, 3600 in prod) |
Mode 3 — enterprise-oidc¶
When to use: you already have an OIDC-compliant IdP (Azure AD / Entra ID, Okta, Auth0, Google Workspace, external Keycloak) and you want AKKO to broker against it rather than federate a directory.
What AKKO does for you:
- Keycloak Identity Provider is configured automatically by the
akko-keycloak-oidc-brokerinit job. groupsclaim from the IdP is mapped to AKKO realm roles.- ABAC attributes (
data-scope,column-mask,row-filter,ai-tier) are imported verbatim from the IdP token. - The bundled directory service is disabled.
Helm values:
global:
auth:
mode: "enterprise-oidc"
initialAdmin:
enabled: true
username: "admin-akko"
email: "admin-akko@corp.example.com"
oidc:
provider: "azure-ad" # azure-ad | okta | google | keycloak
displayName: "Sign in with Corporate SSO"
discoveryUrl: "https://login.microsoftonline.com/<TENANT_ID>/v2.0/.well-known/openid-configuration"
clientId: "<APPLICATION_CLIENT_ID>"
clientSecretRef:
name: "akko-oidc-client"
key: "secret"
scopes: "openid profile email groups"
syncMode: "FORCE"
trustEmail: true
groupsClaim: "groups"
roleMapping:
akko-admin: ["<OBJ_ID_OR_NAME_IT_ADMINS>"]
akko-engineer: ["<OBJ_ID_OR_NAME_DATA_ENG>"]
akko-analyst: ["<OBJ_ID_OR_NAME_ANALYSTS>"]
akko-steward: ["<OBJ_ID_OR_NAME_STEWARDS>"]
akko-user: ["<OBJ_ID_OR_NAME_USERS>"]
akko-viewer: ["<OBJ_ID_OR_NAME_EXECS>"]
# ABAC claims passed through from the IdP into the AKKO token
attributeMapping:
data-scope: "data_scope"
column-mask: "column_mask"
row-filter: "row_filter"
ai-tier: "ai_tier"
project-groups: "projects"
akko-lldap:
enabled: false
Create the OIDC client secret:
kubectl create secret generic akko-oidc-client \
--from-literal=secret='<IDP_CLIENT_SECRET>' \
-n akko
Deploy:
helm upgrade --install akko helm/akko/ -n akko --create-namespace \
--wait --wait-for-jobs --timeout 20m \
-f helm/examples/values-domain.yaml \
-f helm/examples/values-enterprise.yaml \
-f values-oidc-overrides.yaml \
--set-file akko-keycloak.realm.data=helm/examples/realm-domain.json
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Invalid redirect URI" on IdP | Redirect URI in IdP does not match exactly | Check IdP config, must be https://keycloak.<your-domain>/realms/akko/broker/<alias>/endpoint |
| User logs in but has zero roles | groupsClaim not emitted by IdP |
Azure: add a groups claim in Token configuration; Okta: scope groups; Auth0: add rule to include groups |
invalid_client on token exchange |
Client secret rotated, Kubernetes Secret stale | Re-create akko-oidc-client, restart Keycloak + akko-keycloak-oidc-broker job |
| Split-horizon DNS: internal pods can't resolve discoveryUrl | CoreDNS upstream mis-config | Add hostAliases to Keycloak or fix upstream resolver |
| Users created with wrong email | IdP does not emit email_verified |
Set trustEmail: true or configure IdP to verify email |
Bring Your Own Users — Manual User & Role Assignment¶
If your corporate IdP is not available (or for break-glass accounts), you can manage users directly in Keycloak.
1. Create users in Keycloak Admin UI¶
- Open
https://keycloak.<your-domain>/admin - Sign in with the initial admin (
admin-akko) - Select the akko realm > Users > Add user
- Fill in username, email, first name, last name
- Set
Email verified = On - Save, then go to Credentials and set a temporary password
2. Assign realm roles¶
In the user's Role mapping tab > Assign role, assign one or more of the AKKO platform realm roles:
akko-adminakko-engineerakko-analystakko-stewardakko-userakko-viewer
3. Set ABAC user attributes¶
AKKO enforces attribute-based access control (ABAC) on top of RBAC.
Set these user attributes under Users > \
| Attribute key | Example value | Effect |
|---|---|---|
data-scope |
finance,risk |
Restricts Trino queries to schemas tagged with these domains |
column-mask |
email,phone,ssn |
Forces these columns to be masked even for privileged roles |
row-filter |
region = 'EU' |
Prepends a Trino row filter to every query |
ai-tier |
standard (or premium, restricted) |
Controls LiteLLM model access (GPT-4 vs. local Ollama) |
These attributes are emitted in the JWT as protocol mapper claims and consumed by OPA policies in Trino and by the AKKO ABAC middleware in JupyterHub + Superset + ADEN.
4. Project groups¶
Project-level isolation is modelled via Keycloak groups prefixed with
projet-:
- Go to Groups > Create group >
projet-risk - Add members
- OPA rego rules read the
groupsclaim and restricticeberg.projet_risk.*to members - S3 buckets
projet-risk/*get the same restriction via the object storage OIDC policy mapper
See Governance Architecture for the full group model and OPA rule file layout.
Role Mapping — Corporate Role → AKKO Role¶
Use this table as the starting point for your roleMapping block. Adapt
group names to whatever your IdP uses.
| Your corporate role | AKKO role | Permissions |
|---|---|---|
| CTO, VP Data, Platform Owner, SRE Lead | akko-admin |
Full access to all services + admin consoles, unmasked PII, RBAC + ABAC management, OPA policy edits |
| Data Engineer, Platform Engineer, DevOps | akko-engineer |
CREATE / INSERT / SELECT on Iceberg, pipeline management (Airflow, dbt), Spark jobs, no PII masking, MLflow, LiteLLM (1000 req/day) |
| Senior Data Analyst, Data Scientist | akko-analyst |
SELECT on all schemas, full PII on authorised scopes, dashboard creation (Superset), notebooks (JupyterHub), ADEN NL queries |
| Data Steward, Data Governance Lead | akko-steward |
Catalog ownership (OpenMetadata), data classification, glossary, lineage edits, limited SELECT + embedding LLM access |
| Business User, Compliance, Finance | akko-user |
SELECT on published schemas, PII columns masked (email, phone, SSN, DOB), read-only dashboards, natural-language queries |
| Executive, Auditor, External consultant | akko-viewer |
Read-only published dashboards, row-filtered queries, PII masked, no direct SQL, no write anywhere |
Rule of thumb: start restrictive, expand via ABAC attributes
(data-scope, row-filter) rather than promoting the role.
Checklist — Enterprise Deployment¶
Go through this checklist before cutting over to production. Each item is mandatory for an enterprise deployment.
- [ ] 1. TLS certificate. Either cert-manager (
global.tls.issuer) or bring-your-own TLS secret referenced byglobal.tls.secretName. Self-signed certs are forbidden in production. - [ ] 2. Authentication mode.
global.auth.modeisenterprise-ldaporenterprise-oidc.akko-lldap.enabledisfalse. Verified by rendering the chart and grep-ing forlldap. - [ ] 3. Role mapping defined. Every group your users belong to is
mapped to exactly one AKKO role in
global.auth.ldap.roleMappingorglobal.auth.oidc.roleMapping. No*wildcards. - [ ] 4. ABAC attributes synced. User attributes
(
data-scope,column-mask,row-filter,ai-tier) are emitted as JWT claims. Tested viacurl ... /userinfo | jq .. - [ ] 5. Audit logs shipped to corporate SIEM. logs layer is configured to
forward to your SIEM (Splunk, Elastic, Datadog) via the logs layer
ruler.remote_writeor a dedicated log shipper. Keycloak events, OPA decision logs, and Trino query logs are included. - [ ] 6. Backup and DR configured.
akko-postgresql,akko-postgresql-data, Keycloak realm export, S3 bucket replication, Polaris metadata — all covered by a daily Velero / pgBackRest / object storage mirror job. - [ ] 7. Demo users disabled. No
alice,bob,carol,dave,eveaccounts remain. Verified withkubectl exec deploy/akko-keycloak -- /opt/keycloak/bin/kcadm.sh get users -r akko --fields username. - [ ] 8. Break-glass admin documented.
initialAdmin.usernamepassword stored in your corporate secret vault (HashiCorp Vault, AWS Secrets Manager, etc.), rotation procedure documented. - [ ] 9. Network policies enforced.
global.networkPolicies.enabled=true. No pod can egress to the internet except explicitly allowed (LiteLLM upstream, MLflow artefact store). - [ ] 10. Keycloak hardened.
KC_HOSTNAME_STRICT=true,KC_HTTP_ENABLED=false, brute-force detection enabled in realm, MFA required forakko-admin.
Once all ten boxes are ticked, run
bash helm/scripts/lint-no-hardcoding.sh (CI also runs this) and
bash tests/run-all.sh to validate the full stack end-to-end.
Further Reading¶
- External Identity Provider Integration -- step-by-step IdP-specific configuration
- RBAC Administration -- role definitions and access matrix
- Governance Architecture -- how RBAC + ABAC + OPA fit together
- Compliance -- SOC 2 / ISO 27001 / GDPR mapping
- Configuration -- full Helm values reference