Skip to content

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-federation init job
  • Passwords are generated at install time, stored in Kubernetes Secret akko-demo-users, and surfaced by bash helm/scripts/show-dev-credentials.sh

Helm values (the default — no change required):

global:
  auth:
    mode: "demo"

akko-lldap:
  enabled: true

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-federation init 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-broker init job.
  • groups claim 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

  1. Open https://keycloak.<your-domain>/admin
  2. Sign in with the initial admin (admin-akko)
  3. Select the akko realm > Users > Add user
  4. Fill in username, email, first name, last name
  5. Set Email verified = On
  6. 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-admin
  • akko-engineer
  • akko-analyst
  • akko-steward
  • akko-user
  • akko-viewer

3. Set ABAC user attributes

AKKO enforces attribute-based access control (ABAC) on top of RBAC. Set these user attributes under Users > \ > Attributes:

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-:

  1. Go to Groups > Create group > projet-risk
  2. Add members
  3. OPA rego rules read the groups claim and restrict iceberg.projet_risk.* to members
  4. 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 by global.tls.secretName. Self-signed certs are forbidden in production.
  • [ ] 2. Authentication mode. global.auth.mode is enterprise-ldap or enterprise-oidc. akko-lldap.enabled is false. Verified by rendering the chart and grep-ing for lldap.
  • [ ] 3. Role mapping defined. Every group your users belong to is mapped to exactly one AKKO role in global.auth.ldap.roleMapping or global.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 via curl ... /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_write or 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, eve accounts remain. Verified with kubectl exec deploy/akko-keycloak -- /opt/keycloak/bin/kcadm.sh get users -r akko --fields username.
  • [ ] 8. Break-glass admin documented. initialAdmin.username password 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 for akko-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