Keycloak as a sample IdP#

This guide describes how to deploy Keycloak and configure it as the identity provider (IdP) for OSMO. Keycloak acts as an authentication broker, allowing OSMO to authenticate users through various identity providers (LDAP, SAML, social logins) while providing centralized group and role management.

Note

Keycloak is one option for an IdP. OSMO can also connect directly to other providers such as Microsoft Entra ID, Google, or AWS IAM Identity Center without Keycloak. See Identity Provider (IdP) Setup for direct IdP configuration.

When to use Keycloak#

Use Keycloak when:

  • You want a self-hosted identity broker that can federate multiple upstream identity providers (LDAP, SAML, OIDC) behind a single OIDC interface for OSMO.

  • You need centralized user, group, and role management in a dedicated admin console.

  • You want to manage pool access by assigning Keycloak roles to groups rather than configuring each user individually.

If you already have a single IdP (e.g., Microsoft Entra ID) and do not need a broker, connecting OSMO directly to that IdP is simpler. See Identity Provider (IdP) Setup.

Part 1: Deploy Keycloak#

Step 1: Create a Keycloak database#

If you are using an external PostgreSQL instance, create a database for Keycloak. Omit export OSMO_PGPASSWORD=... and PGPASSWORD=$OSMO_PGPASSWORD if PostgreSQL was configured without a password.

$ export OSMO_DB_HOST=<your-db-host>
$ export OSMO_PGPASSWORD=<your-postgres-password>
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: osmo-db-ops
spec:
  containers:
    - name: osmo-db-ops
      image: alpine/psql:17.5
      command: ["/bin/sh", "-c"]
      args:
        - "PGPASSWORD=$OSMO_PGPASSWORD psql -U postgres -h $OSMO_DB_HOST -p 5432 -d postgres -c 'CREATE DATABASE keycloak;'"
  restartPolicy: Never
EOF

Check that the process Completed with kubectl get pod osmo-db-ops. Then delete the pod with:

$ kubectl delete pod osmo-db-ops

Step 2: Install Keycloak with Helm#

  1. Add the Bitnami Helm repository:

$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
  1. Create a keycloak-values.yaml file with the following configuration:

keycloak-values.yaml
global:
  security:
    allowInsecureImages: true

image:
  registry: docker.io
  repository: bitnamilegacy/keycloak
  tag: 26.1.1-debian-12-r0

# Hostname configuration
hostname: auth-<your-domain>
proxy: edge

# Production mode
production: true
tls:
  enabled: true
  autoGenerated: true

# Admin user credentials
auth:
  adminUser: admin
  adminPassword: your-secure-password  # Change this!

# Ingress configuration
ingress:
  enabled: true
  tls: true
  ingressClassName: <your-ingress-class>  # e.g., nginx, alb
  hostname: auth-<your-domain>
  annotations:
    # Add additional ingress-specific annotations here to match your ingress controller
    # Example for AWS ALB:
    # alb.ingress.kubernetes.io/target-type: ip
    # alb.ingress.kubernetes.io/group.name: osmo
    # alb.ingress.kubernetes.io/group.order: "0"
    # alb.ingress.kubernetes.io/scheme: internet-facing
    # alb.ingress.kubernetes.io/certificate-arn: <your-ssl-cert-arn>
    # alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    # alb.ingress.kubernetes.io/ssl-redirect: '443'

  path: /
  pathType: Prefix
  servicePort: 80

# Autoscaling configuration
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 3
  targetCPU: 80
  targetMemory: 80

# Resource allocation
resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "2"
    memory: "1Gi"

# Database configuration
# Option 1: External Database
postgresql:
  enabled: false
externalDatabase:
  host: "<your-db-host>"
  port: 5432
  user: "<your-db-user>"
  database: "keycloak"
  existingSecret: "keycloak-db-secret"
  existingSecretPasswordKey: "postgres-password"

# Option 2: Built-in PostgreSQL (for testing)
# postgresql:
#   enabled: true

# Additional environment variables
extraEnvVars:
  - name: KC_HOSTNAME_STRICT_HTTPS
    value: "true"
  - name: KC_PROXY
    value: "edge"
  1. Create the namespace for Keycloak:

$ kubectl create namespace keycloak
  1. If you are using an external database, create a secret for the database password:

$ kubectl create secret generic keycloak-db-secret \
  --namespace keycloak \
  --from-literal=postgres-password='<your-db-password>'
  1. Install Keycloak using Helm:

$ helm install keycloak bitnami/keycloak \
  --version 24.4.9 \
  --namespace keycloak \
  -f keycloak-values.yaml
  1. Verify the installation:

$ kubectl get pods -n keycloak
$ kubectl get ingress -n keycloak

Note

To access the Keycloak instance, configure DNS records to point to your load balancer. For example, create a record for auth-osmo.example.com pointing to the load balancer IP.

If you have DNS configured, access the Keycloak instance at https://auth-osmo.example.com. If DNS is not configured, use port forwarding:

$ kubectl port-forward service/keycloak 32080:80 -n keycloak

Step 3: Post-installation configuration#

  1. Access your Keycloak instance at https://auth-osmo.example.com

  2. Log in with the admin credentials specified in the values file

  3. Create a new realm for OSMO:

    1. Download the sample realm file: sample_osmo_realm.json

    2. Click on the dropdown menu on the top left which says master and select Create Realm

    3. Enter the downloaded realm file in the Resource file field and click Create

    4. You will be redirected to the osmo realm

  4. Click on the Clients tab and for each of the osmo-browser-flow and osmo-device clients, update the client settings:

    • Root URL: https://osmo.example.com

    • Home URL: https://osmo.example.com

    • Admin URL: https://osmo.example.com

    • Valid Redirect URIs: https://osmo.example.com/*

    • Web Origins: https://osmo.example.com

    Note

    Replace osmo.example.com with your actual OSMO domain name.

  5. On the osmo-browser-flow client details page, click on the Credentials tab and create and save a client secret. You will need this when configuring OSMO’s OAuth2 Proxy sidecar.

Part 2: Configure OSMO to use Keycloak#

With Keycloak deployed and the osmo realm configured, follow the standard OSMO deployment steps in Deploy Service, substituting the Keycloak-specific OIDC endpoints shown below for the generic IdP placeholders.

Keycloak endpoints#

All endpoints are under the osmo realm:

Purpose

URL

Token

https://auth-<your-domain>/realms/osmo/protocol/openid-connect/token

Authorize

https://auth-<your-domain>/realms/osmo/protocol/openid-connect/auth

JWKS

https://auth-<your-domain>/realms/osmo/protocol/openid-connect/certs

Issuer

https://auth-<your-domain>/realms/osmo

Device auth

https://auth-<your-domain>/realms/osmo/protocol/openid-connect/device

Logout

https://auth-<your-domain>/realms/osmo/protocol/openid-connect/logout

Create secrets#

Create the OAuth2 Proxy secret using the client secret from Step 3: Post-installation configuration:

$ kubectl create secret generic oauth2-proxy-secrets \
  --from-literal=client_secret=<keycloak-client-secret> \
  --from-literal=cookie_secret=$(openssl rand -base64 32) \
  --namespace osmo

OSMO Helm values for Keycloak#

When preparing the OSMO Helm values (see Step 3: Prepare values), use the Keycloak endpoints for the auth, oauth2Proxy, and jwt sections. For the full deployment procedure and all other Helm values, follow Deploy Service.

Below are the Keycloak-specific sections that differ from the generic IdP examples in the deployment guide. Replace <your-domain> with your actual domain (e.g., osmo.example.com).

Service auth configuration (in osmo_values.yaml):

services:
  service:
    auth:
      enabled: true
      device_endpoint: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/device
      device_client_id: osmo-device
      browser_endpoint: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/auth
      browser_client_id: osmo-browser-flow
      token_endpoint: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/token
      logout_endpoint: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/logout

OAuth2 Proxy sidecar (in osmo_values.yaml):

sidecars:
  oauth2Proxy:
    enabled: true
    provider: oidc
    oidcIssuerUrl: https://auth-<your-domain>/realms/osmo
    clientId: osmo-browser-flow
    cookieDomain: .<your-domain>
    scope: "openid email profile"
    useKubernetesSecrets: true
    secretName: oauth2-proxy-secrets
    clientSecretKey: client_secret
    cookieSecretKey: cookie_secret
    extraArgs:
    - --insecure-oidc-allow-unverified-email=true

Note

The --insecure-oidc-allow-unverified-email=true flag is required when using Keycloak because Keycloak does not set the email_verified claim to true by default. Without this flag, OAuth2 Proxy will reject logins from users whose email is not marked as verified.

Envoy JWT providers (in osmo_values.yaml):

sidecars:
  envoy:
    jwt:
      user_header: x-osmo-user
      providers:
      - issuer: https://auth-<your-domain>/realms/osmo
        audience: osmo-device
        jwks_uri: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/certs
        user_claim: preferred_username
        cluster: idp
      - issuer: https://auth-<your-domain>/realms/osmo
        audience: osmo-browser-flow
        jwks_uri: https://auth-<your-domain>/realms/osmo/protocol/openid-connect/certs
        user_claim: preferred_username
        cluster: idp
      - issuer: osmo
        audience: osmo
        jwks_uri: http://localhost:8000/api/auth/keys
        user_claim: unique_name
        cluster: service

Note

With Keycloak, two IdP JWT providers are configured — one for the osmo-device client (CLI) and one for the osmo-browser-flow client (Web UI) — because each client has its own audience. The third provider is for OSMO-issued JWTs (access tokens).

Apply the same Keycloak endpoints to the router and UI values files. For the complete deployment procedure including all other configuration steps, see Deploy Service.

Part 3: Keycloak Group and Role Management#

OSMO uses Keycloak’s role-based access control to manage permissions for pool access and other resources. The configuration follows a hierarchical structure:

  1. Roles: Represent specific permissions within OSMO (e.g., osmo-group1 grants permission to submit workflows to group1-* pools)

  2. Groups: Collections of users that share the same access requirements. When a role is assigned to a group, all members inherit the associated permissions

  3. Users: Individual accounts that belong to one or more groups and inherit the roles assigned to those groups

This hierarchical approach simplifies access management by allowing administrators to grant permissions to entire teams at once rather than configuring each user individually.

Configuration Workflow#

The typical workflow for setting up access control is:

  1. Create roles in Keycloak clients (osmo-browser-flow and osmo-device)

  2. Create groups in Keycloak

  3. Assign roles to groups

  4. Add users to groups (manually or via identity provider mappings)

  5. Create matching pools

  6. Verify access

Creating Roles in Keycloak#

Roles must be created in both Keycloak clients that OSMO uses:

  1. Access the Keycloak admin console and select the OSMO realm

  2. Navigate to the “Clients” tab and select the osmo-browser-flow client

  3. Click on the “Roles” tab, then click “Create Role”

  4. Enter a name for the role following the format osmo-<pool-group-name>

    For example: osmo-group1

  5. Click “Save”

  6. Repeat steps 2-5 for the osmo-device client

Note

The role name is format-sensitive. You must use the exact format osmo-<pool-group-name> for pool access roles.

Creating Groups in Keycloak#

Groups organize users and assign roles to multiple users at once:

  1. In the Keycloak admin console, select the OSMO realm

  2. Navigate to the “Groups” tab and click “Create Group”

  3. Enter a name for the group following the format OSMO <pool-group-name>

    For example: OSMO group1

  4. Click “Save”

Assigning Roles to Groups#

After creating the group, assign the appropriate roles:

  1. Click into the group you just created

  2. Select the “Role Mapping” tab

  3. Click “Assign Role”

  4. Click on the filter dropdown and select “Filter by clients”

  5. Search for osmo-<pool-group-name> (e.g., osmo-group1)

  6. Select both roles (one from osmo-browser-flow and one from osmo-device client)

  7. Click “Assign”

Note

The osmo-browser-flow client is used for the Web UI and the osmo-device client is used for the CLI. You must assign roles from both clients for full functionality.

Managing Users in Keycloak#

Adding Users Manually#

To create users directly in the Keycloak admin console:

  1. Go to the “Users” tab

  2. Click “Add User”

  3. Fill in the user details, add the user to the User or Admin group depending on the role you want to assign, and save

  4. Click on the user’s ID to access their settings. In the “Credentials” tab, enter a password with the temporary password setting enabled

  5. When the temporary password setting is enabled, the user will be forced to change their password upon first login

Note

The Admin group is reserved for administrators with elevated permissions for configuring OSMO and managing users. The User group is reserved for users with basic permissions for submitting workflows and managing their own workflows.

Adding Users to Groups#

To add existing users to groups:

  1. Navigate to the “Users” tab in the Keycloak admin console

  2. Search for and select the user you want to add

  3. Click on the “Groups” tab

  4. Click “Join Group”

  5. Select the group you want to add the user to

  6. Click “Join”

Configuring Identity Provider Mappings#

Instead of manually adding users to groups, you can configure identity provider mappings to automatically add users to groups based on claims or metadata provided by an upstream identity provider (e.g., LDAP, SAML). For more information, see the Keycloak identity brokering documentation .

See also

Keycloak can be configured to federate login with upstream identity providers. For detailed instructions on configuring SSO with identity providers in Keycloak, refer to the official Keycloak documentation .

Verification and Testing#

Verifying User Access#

To verify that a user has the correct roles:

  1. Have the user log in to OSMO

  2. In the Keycloak admin console, go to “Users” and find the user

  3. Click on the user and select the “Groups” tab

  4. Verify the user is in the expected groups

  5. Select the “Role Mapping” tab and click “View all assigned roles”

  6. Confirm the user has the expected roles (both from osmo-browser-flow and osmo-device)

Testing Pool Access#

Test that the user can access the pool:

  1. Log in to OSMO as the user

  2. List available pools:

    $ osmo pool list
    
  3. Submit a test workflow to the pool:

    $ osmo workflow submit my-workflow.yaml --pool group1-h100-gpu
    
  4. If successful, the user has proper access

Troubleshooting#

Keycloak Deployment Issues#

  • Pods not starting: Check pod logs with kubectl logs -f <keycloak-pod> -n keycloak. Common issues include database connectivity and incorrect secrets.

  • Ingress not accessible: Verify DNS records point to the load balancer and the ingress is configured correctly with kubectl get ingress -n keycloak.

User Cannot Access Pool#

Symptoms: User receives “Permission denied” or cannot see the pool

Solutions:

  1. Verify Role Policy: Ensure the corresponding role has been created. Follow the steps in Troubleshooting.

  2. Verify Role Names: Pool access roles must start with osmo- prefix (see Role Naming for Pools). Pool names must match the role suffix. Example: Role osmo-team1 will make pools named team1* visible.

  3. Check Both Clients: Ensure roles are created in both osmo-browser-flow and osmo-device clients. Both roles must be assigned to the group.

  4. Verify Group Membership: In the Keycloak admin console, check if the user appears in the group. If using IdP mappings (see Configuring Identity Provider Mappings):

    • Verify the mapping configuration

    • Check IdP logs to ensure claims are being sent

    • Have the user log out and log back in again. Check Keycloak logs during login and verify that the IdP claim matches the mapper configuration.

Roles Not Appearing in JWT Token#

Symptoms: User can log in but has no permissions

Solutions:

  1. Check Client Scope: Verify that osmo-browser-flow and osmo-device clients have the correct client scopes configured.

  2. Review Token: Decode the JWT token to see what roles are included. Use a tool like jwt.io to inspect the token.

Best Practices#

Naming Conventions#

  • Roles: Use lowercase with hyphens: osmo-<team>-<purpose>

  • Groups: Use title case: OSMO <Team> <Purpose>

  • Pools: Match role suffix: <team>-<resource-type>

Examples:
  • Role: osmo-ml-team

  • Group: OSMO ML Team

  • Pools: ml-team-training, ml-team-inference

Group Organization#

  1. Use Hierarchy: Create parent groups for departments and child groups for teams

  2. Document Purpose: Add descriptions to groups explaining their purpose

  3. Regular Audits: Periodically review group memberships

Security Considerations#

  1. Principle of Least Privilege: Only grant necessary pool access

  2. Regular Reviews: Audit role assignments quarterly

  3. Offboarding: Remove users from groups when they leave teams

  4. Monitor Access: Review Keycloak audit logs for unusual activity

  5. Test Changes: Always test role/group changes with a test user first

See Also#