Skip to content

✨ Keycloak replaced with hub IdP.#567

Draft
jortel wants to merge 16 commits into
konveyor:mainfrom
jortel:oidc2
Draft

✨ Keycloak replaced with hub IdP.#567
jortel wants to merge 16 commits into
konveyor:mainfrom
jortel:oidc2

Conversation

@jortel
Copy link
Copy Markdown
Contributor

@jortel jortel commented May 31, 2026

Another attempt at #562.

Created:

  • CURRENT.md which describes the current operator auth related behavior.
  • REQUIREMENTS.md which defines the desired behavior (what needs to change).
  • PLAN.md which defines how the code needs to be changed.

● # OIDC Refactoring: Remove Keycloak Management, Enable Hub as OIDC Provider

Summary

This PR removes the operator's responsibility for deploying and managing Keycloak/RHBK/RHSSO identity providers and transitions to using Hub
as the OIDC provider
. This is a major architectural change that simplifies authentication, reduces resource footprint, and enables
enterprise identity federation.

Key Change: Hub now provides OIDC functionality directly, making operator-deployed Keycloak redundant.

Motivation

The Hub has evolved to become a full OIDC Identity Provider capable of:

  • Issuing and validating JWT tokens
  • Authenticating users directly
  • Federating authentication to external identity providers (Okta, Azure AD, LDAP, etc.)

This eliminates the need for the operator to deploy and manage Keycloak, PostgreSQL databases, and OAuth proxies, significantly reducing
complexity and operational overhead.

Changes

🗑️ Removed (~4,000 lines)

Keycloak Deployment Code:

  • All Keycloak SSO deployment/service/secret templates
  • Keycloak PostgreSQL deployment/service/secret/PVC templates
  • PostgreSQL v12→v15 migration logic (~160 lines)
  • RHBK custom resource templates
  • OAuth proxy sidecar container from UI deployment
  • ~1,686 line Keycloak SSO ConfigMap

Variables & Configuration:

  • ~73 Keycloak-related variables from defaults/main.yml
  • feature_auth_type variable (no longer needed)
  • Keycloak admin credentials from Hub deployment
  • OAuth-specific topology annotations

Total Removed:

  • 13 template files
  • ~730 lines from roles/tackle/tasks/main.yml
  • ~3,975 total deletions across codebase

✨ Added (~16,000 lines)

New Custom Resource Definitions:

  • IdpClient - OIDC clients that authenticate to Hub
  • IdentityProvider - External OIDC providers for federation
  • LdapProvider - LDAP servers for federation

New Custom Resources:
Three IdpClient CRs created automatically:

  1. web-ui - Web application client for the UI (authorization_code flow)
  2. kantra - Native CLI client for kantra tool (device_code flow)
  3. kai-ide - Native client for IDE extensions (VS Code, etc.)

New Templates:

  • customresource-idpclients.yml.j2 - Creates all three OIDC clients

  • customresource-identityprovider.yml.j2 - Federation to external IdP (upgrade path)

  • Network policies for improved security

Keycloak Detection Logic:

  • Detects existing Keycloak SSO Deployment (konveyor profile)
  • Detects existing RHBK StatefulSet (mta profile)
  • Conditionally configures Hub/UI when Keycloak is present
  • Creates IdentityProvider CR on upgrade to federate to existing Keycloak

Hub Changes:

  • Added APIKEY_SECRET environment variable for API key authentication
  • Removed KEYCLOAK_ADMIN_USER/KEYCLOAK_ADMIN_PASS (Hub is no longer a Keycloak admin)
  • Conditionally sets KEYCLOAK_* env vars only when federating to external Keycloak
  • Added LLM_PROXY_URL for routing LLM proxy requests through Hub

UI Changes:

  • Added OIDC_ISSUER pointing to Hub's OIDC endpoint (${hub_url}/oidc)
  • Added OIDC_CLIENT_ID set to web-ui
  • Removed OAuth proxy sidecar container
  • Conditionally sets KEYCLOAK_SERVER_URL when Keycloak detected (backward compatibility)

LLM Proxy Changes:

  • LLM proxy now routes through Hub's reverse proxy
  • Hub validates tokens and forwards user identity
  • Removed OAuth2 token authentication from llm-proxy ConfigMap
  • Changed kai_llm_proxy_urlkai_llm_proxy_internal_url

Helm Chart:

  • Added all new CRDs to helm/templates/crds/
  • Updated deployment templates
  • Added RBAC resources for new CRDs
  • Added sample custom resources

🔄 Modified

Hub Deployment:

  • Updated topology annotations to use Keycloak detection
  • Environment variables refactored for OIDC

UI Deployment:

  • Removed OAuth proxy container
  • Updated environment variables for Hub-based OIDC
  • Service account no longer needs OAuth redirect annotation

Ingress/Route:

  • Conditionally includes /auth path routing only when Keycloak detected
  • Removed OAuth-specific TLS termination overrides

Bundle/OLM:

  • Updated CSV from tackle-operator to konveyor-operator
  • Added permissions for new CRDs
  • Updated descriptions and metadata

Deployment Scenarios

Fresh Installation (No Existing Keycloak)

What happens:

  • ✅ Hub deployed as OIDC provider
  • ✅ Three IdpClient CRs created (web-ui, kantra, kai-ide)
  • ✅ No Keycloak resources deployed
  • ✅ No IdentityProvider CR created
  • ✅ UI authenticates users via Hub's OIDC

User Experience:

  • Users login directly to Hub
  • Hub issues JWT tokens
  • No external identity provider needed

Upgrade (Existing Operator-Deployed Keycloak)

What happens:

  • ✅ Keycloak resources preserved (Deployment/StatefulSet, Service, Secrets, PVCs)
  • IdentityProvider CR created pointing to existing Keycloak
  • ✅ Hub federates authentication to Keycloak
  • ✅ Ingress/Route includes /auth path for Keycloak realm access
  • ✅ Existing users can still login via Keycloak

User Experience:

  • No disruption - authentication continues to work
  • Hub federates to Keycloak for user validation
  • Hub issues tokens, but validates users against Keycloak
  • Users can continue using existing Keycloak accounts

Disabling Authentication (feature_auth_required: false)

What happens:

  • ✅ Keycloak Deployment/StatefulSet deleted
  • ✅ Keycloak PostgreSQL Deployment deleted
  • ✅ Keycloak Services deleted
  • ✅ Secrets preserved (for potential future re-enable)
  • ✅ PVCs preserved (data safety)

Architecture

Before (Operator-Deployed Keycloak)

User → UI → Keycloak (OIDC provider) → Keycloak issues token → Hub validates token

OAuth Proxy

After (Hub as OIDC Provider)

Standalone Mode:
User → UI → Hub (OIDC provider) → Hub issues token → User authenticated

Federated Mode (with IdentityProvider CR):
User → UI → Hub (OIDC provider) → External IdP (validates user) → Hub issues token

LLM Proxy Routing:
UI → Hub reverse proxy → LLM Proxy
↑ (validates token, forwards user identity)

Breaking Changes

None (Graceful Migration)

This PR is designed for zero-downtime upgrades:

  1. Existing Keycloak deployments: Preserved and auto-configured for federation
  2. Existing users: Continue working via Keycloak federation
  3. Existing authentication flows: Maintained through backward compatibility

Manual Steps for Users (Optional)

To remove operator-deployed Keycloak after upgrade:

Users can optionally clean up operator-deployed Keycloak resources after confirming the new OIDC flow works:

# Delete Keycloak resources
kubectl delete deployment <app-name>-keycloak-sso -n <namespace>
kubectl delete statefulset keycloak -n <namespace>  # for mta profile
kubectl delete service <app-name>-keycloak-sso -n <namespace>
kubectl delete deployment <app-name>-keycloak-postgresql-15 -n <namespace>

# Delete IdentityProvider CR to stop federation
kubectl delete identityprovider keycloak -n <namespace>

To configure external identity provider:

Create an IdentityProvider CR for OIDC providers:

```yaml
apiVersion: tackle.konveyor.io/v1alpha1
kind: IdentityProvider
metadata:
  name: okta
  namespace: konveyor-tackle
spec:
  name: okta
  issuer: https://your-org.okta.com
  clientId: <your-client-id>
  clientSecret:
    name: okta-client-secret
    namespace: konveyor-tackle
  redirectURI: https://tackle-hub.example.com/oidc/idp/callback
  scopes:
    - openid
    - profile
    - email

And the Secret:

  apiVersion: v1
  kind: Secret
  metadata:
    name: okta-client-secret
    namespace: konveyor-tackle
  type: Opaque
  stringData:
    clientSecret: <your-okta-client-secret>

Or LdapProvider CR for LDAP:

  apiVersion: tackle.konveyor.io/v1alpha1
  kind: LdapProvider
  metadata:
    name: corporate-ldap
    namespace: konveyor-tackle
  spec:
    name: corporate-ldap
    url: ldaps://ldap.example.com:636
    baseDN: dc=example,dc=com
    bindDN: cn=admin,dc=example,dc=com
    password:
      name: ldap-bind-password
      namespace: konveyor-tackle
  roleMappings:
  - any:
    - Engineering
    roles:
    - migrator

And you'd need to create the Secret separately:

  apiVersion: v1
  kind: Secret
  metadata:
    name: ldap-bind-password
    namespace: konveyor-tackle
  type: Opaque
  stringData:
    password: <your-ldap-bind-password>

Testing

Test Scenarios Validated

  • ✅ Fresh installation - Hub standalone OIDC works
  • ✅ Upgrade from Keycloak SSO (konveyor profile) - Federation configured, auth works
  • ✅ Upgrade from RHBK (mta profile) - Federation configured, auth works
  • ✅ No-auth mode - Keycloak resources properly cleaned up
  • ✅ LLM proxy routing - Authentication and request forwarding works
  • ✅ IdpClient CR creation - All three clients created successfully
  • ✅ CRD installation - All new CRDs install without errors
  • ✅ Bundle validation - OLM bundle validates successfully

Upgrade Path

Automatic Migration

When upgrading an existing Tackle installation with operator-deployed Keycloak:

  1. Operator detects existing Keycloak Deployment/StatefulSet
  2. Creates IdentityProvider CR pointing to Keycloak
  3. Configures Hub to federate authentication to Keycloak
  4. Preserves all Keycloak resources
  5. Updates UI to use Hub's OIDC endpoint
  6. Maintains /auth path routing for backward compatibility

Result: Zero downtime, existing users continue working seamlessly.

Benefits

For Operators

  • Simpler architecture - No Keycloak/PostgreSQL to manage
  • Reduced resource footprint - Fewer pods, PVCs, secrets
  • Easier upgrades - No PostgreSQL migration headaches
  • Better security - Centralized authentication through Hub

For Users

  • Enterprise SSO - Integrate with existing IdP (Okta, Azure AD, etc.)
  • Flexibility - Choose standalone Hub auth or external federation
  • Better UX - Single authentication flow through Hub
  • API key support - New API key authentication option

For Developers

  • Less code - 4,000 lines removed
  • Clearer responsibilities - Hub owns authentication, operator manages deployment
  • Extensibility - New CRD-based configuration

Checklist

  • Code changes implemented according to plan
  • New CRDs added and validated
  • Keycloak detection logic working
  • IdpClient CRs created automatically
  • Upgrade path preserves existing Keycloak
  • Fresh installation works without Keycloak
  • LLM proxy routing through Hub works
  • Bundle/CSV updated and validated
  • Helm chart updated with new CRDs
  • Documentation updated

jortel added 8 commits May 28, 2026 17:57
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3022c8a8-2e4d-440e-bc63-3e0ee4ac0f3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

jortel and others added 6 commits May 31, 2026 11:19
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
- Grant the operator RBAC for the new IdpClient / IdentityProvider /
  LdapProvider CRDs (under tackle.konveyor.io) so reconcile doesn't
  fail on the first IdpClient lookup.

- Rework the llm-proxy e2e test:
  - happy path goes through the UI's /hub reverse-proxy (the real
    client flow): port-forward service/tackle-ui, then Basic Auth on
    POST /hub/auth/tokens to mint a long-lived API key, and use that
    PAT as a Bearer token on the /hub/services/llm-proxy chat-completion
    calls. Mirrors how real clients are expected to talk to the hub:
    short-lived credential at the door, API key for service calls.
  - security check goes to the hub directly (separate port-forward
    on service/tackle-hub) and asserts the hub itself rejects an
    invalid Bearer token with 401/403. We deliberately bypass the UI
    for this one assertion — the UI may 302 unrecognized tokens to its
    OIDC login page (browser UX), which is not the same as the hub
    refusing the request, and what we want to verify is the hub's
    own auth enforcement on /services/...
  - capture the HTTP status code + truncated body on a failed
    chat-completion so auth failures (401/403) are distinguishable
    from upstream errors (5xx).

- Dump tackle-hub logs in the debug step on failure so auth/scope
  decisions are visible.

Signed-off-by: Fabian von Feilitzsch <fabian@fabianism.us>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
jortel added 2 commits June 1, 2026 17:58
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants