✨ Keycloak dependency removed.#562
Conversation
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
📝 WalkthroughWalkthroughThis PR replaces operator-managed Keycloak with Hub-centric OIDC and federation: it adds IdentityProvider/IdpClient/LdapProvider CRDs and CSV RBAC, removes Keycloak templates, updates Ansible to detect or accept federated IdPs and create CRs, injects OIDC env vars and APIKEY_SECRET into Hub/UI, and adds AUTH.md documentation. ChangesHub OIDC and Federated Auth Migration
Estimated code review effort: Possibly related issues:
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
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>
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (3)
AUTH.md (3)
242-242: ⚡ Quick winClarify behavior when multiple IdentityProvider CRs exist.
The statement "Multiple providers can be configured (Hub will use the first one found)" could cause confusion since Kubernetes list order is not guaranteed to be stable. Consider documenting:
- Whether this scenario is supported or discouraged
- How "first" is determined (alphabetical by name, creation timestamp, etc.)
- Whether Hub will error/warn if multiple CRs exist
This would help operators avoid unexpected behavior if they accidentally create multiple IdentityProvider resources.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@AUTH.md` at line 242, Update the AUTH.md section about multiple IdentityProvider CRs to explicitly state whether multiple IdentityProvider custom resources are supported or discouraged, describe exactly how the Hub selects one when multiple exist (e.g., selection by alphabetical metadata.name or by metadata.creationTimestamp or by unspecified/undefined ordering), and document whether Hub emits a warning or error if more than one IdentityProvider CR is present; if current behavior is to pick the "first" in an unpredictable list, mark multiple CRs as discouraged and recommend operators ensure a single IdentityProvider or use a clear deterministic selection mechanism.
12-14: ⚡ Quick winAdd language specifier to fenced code blocks.
The ASCII architecture diagrams should include a language identifier (use
textor leave empty) to satisfy markdown linters while preserving formatting.📝 Proposed fix
-``` +```text Browser → UI Route (/oidc proxy) → Hub OIDC → Hub API```diff -``` +```text Browser → UI Route (/oidc proxy) → Hub OIDC → [Federated IDP] → Hub API ↓ IdentityProvider CR</details> Also applies to: 17-21 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@AUTH.mdaround lines 12 - 14, Add a language specifier to the fenced code
blocks containing the ASCII architecture diagrams so markdown linters accept
them; specifically update the blocks containing "Browser → UI Route (/oidc
proxy) → Hub OIDC → Hub API" and the multi-line block that includes "[Federated
IDP]" and "IdentityProvider CR" to usetext (or an empty language) instead of plainso formatting is preserved and linting passes.</details> --- `296-301`: _💤 Low value_ **Consider adding Ingress troubleshooting examples.** The troubleshooting section uses OpenShift `route` commands. Since the document mentions "Route/Ingress" throughout, consider adding equivalent commands for Kubernetes Ingress environments: ```bash kubectl get ingress tackle -n konveyor-tackle -o jsonpath='{.spec.rules[0].host}' ``` This would help users on vanilla Kubernetes clusters. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@AUTH.md` around lines 296 - 301, Add an equivalent Kubernetes Ingress example alongside the OpenShift Route commands in AUTH.md: after the kubectl get route tackle ... line, add the ingress command kubectl get ingress tackle -n konveyor-tackle -o jsonpath='{.spec.rules[0].host}' (and similarly note the OIDC_ISSUER retrieval remains the same for the tackle-hub and tackle-ui deployments using the env name OIDC_ISSUER) so users on vanilla Kubernetes can extract the host exactly like the Route example. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.Inline comments:
In@bundle/manifests/konveyor-operator.clusterserviceversion.yaml:
- Around line 204-212: The operator ClusterRole/Role for "tackle-operator" is
missing permissions for the newly-owned CRDs (IdentityProvider, IdpClient,
LdapProvider); update the RBAC rule that grants access to the tackle.konveyor.io
API group (the "tackle-operator" Role/ClusterRole resource) to include the
resources identityproviders, idpclients, and ldapproviders with appropriate
verbs (get, list, watch, create, update, patch, delete as needed) so
reconciliation can create and manage these CRs.In
@helm/templates/crds/tackle.konveyor.io_identityproviders.yaml:
- Around line 41-119: The IdentityProvider CRD allows empty spec objects; update
the schema for the IdentityProvider.spec to mark required fields so invalid CRs
are rejected: add a required array listing "issuer", "clientId", "redirectURI"
(and optionally "name") under the spec object definition, ensure existing
properties (issuer, clientId, redirectURI, name) remain defined, and keep
x-kubernetes-map-type or object types intact; locate the IdentityProvider.spec
block (the spec properties section containing clientId, issuer, redirectURI,
name, tls, etc.) and add the required: [...] entry there to enforce validation.In
@helm/templates/crds/tackle.konveyor.io_idpclients.yaml:
- Around line 189-190: The IdpClient CRD schema currently allows resources
without a top-level spec; update the OpenAPI v3 schema for the IdpClient (the
IdpClient CRD object under the schema served: true) to declare spec as required
by adding a required: ["spec"] entry at the same level as type: object (and
ensure the existing spec properties remain under properties.spec). Locate the
IdpClient CRD schema block in
helm/templates/crds/tackle.konveyor.io_idpclients.yaml and insert the required
key so top-level spec is enforced by admission validation.In
@roles/tackle/defaults/main.yml:
- Around line 86-94: The removal of keycloak_database_image_fqin leaves
kai_database_image_fqin referencing a missing variable; update the defaults so
kai_database_image_fqin no longer depends on keycloak_database_image_fqin by
either adding an explicit default for kai_database_image_fqin or changing its
expression to use a safe fallback (e.g., a literal default or empty string)
instead of keycloak_database_image_fqin; locate and modify the
kai_database_image_fqin variable definition in defaults/main.yml and remove or
replace any occurrence of keycloak_database_image_fqin there.In
@roles/tackle/tasks/main.yml:
- Around line 640-647: The IdentityProvider CR task ("Create IdentityProvider CR
for federated authentication") runs before hub_oidc_issuer is available,
producing an invalid redirect URI; update the task's when clause to also require
hub_oidc_issuer to be defined and non-empty (e.g. add "hub_oidc_issuer is
defined" and "hub_oidc_issuer | length > 0") or move this task to a point after
the code that derives/sets hub_oidc_issuer so the customresource-idp.yml.j2
template can render the correct callback URI.- Around line 839-845: The "Create IdpClient CRs" task currently runs when
feature_auth_required is true even if app_base_url is empty, producing invalid
redirect URIs; update this by adding a readiness guard and/or a fail-fast
assert: require app_base_url to be set/non-empty (e.g.
app_base_url|default('')|trim != '') in the task's when clause and/or add a
preceding assert/fail task that checks app_base_url and aborts with a clear
message before the "Create IdpClient CRs" task (reference the task name "Create
IdpClient CRs", the template "customresource-idpclient.yml.j2", and the variable
app_base_url and feature_auth_required).In
@roles/tackle/templates/customresource-idp.yml.j2:
- Around line 21-22: The template currently hardcodes tls.insecure: true in
customresource-idp.yml.j2; change this to make TLS verification the default and
make disabling it opt-in by replacing the hardcoded value with a
templated/variable-driven default (e.g., use a variable like tls_insecure or
idp.tls.insecure with a default of false) and update any values/values.yaml or
role defaults to expose that variable so callers can opt in to insecure TLS when
needed; ensure references to tls.insecure in related rendering
logic/documentation are updated accordingly.In
@roles/tackle/templates/deployment-ui.yml.j2:
- Around line 101-106: The UI is currently always given OIDC env vars
(AUTH_REQUIRED, OIDC_ISSUER, OIDC_CLIENT_ID) causing a conflict when the
oauth-proxy sidecar is deployed for feature_auth_type == "oauth"; change the
template so those OIDC-related env entries are only emitted when
feature_auth_type is not "oauth" (or specifically when using OIDC auth), e.g.
wrap the AUTH_REQUIRED / OIDC_ISSUER / OIDC_CLIENT_ID entries behind a
conditional that checks feature_auth_type != "oauth" (or feature_auth_type ==
"oidc") so the oauth-proxy path and the UI OIDC path are not both advertised.
Nitpick comments:
In@AUTH.md:
- Line 242: Update the AUTH.md section about multiple IdentityProvider CRs to
explicitly state whether multiple IdentityProvider custom resources are
supported or discouraged, describe exactly how the Hub selects one when multiple
exist (e.g., selection by alphabetical metadata.name or by
metadata.creationTimestamp or by unspecified/undefined ordering), and document
whether Hub emits a warning or error if more than one IdentityProvider CR is
present; if current behavior is to pick the "first" in an unpredictable list,
mark multiple CRs as discouraged and recommend operators ensure a single
IdentityProvider or use a clear deterministic selection mechanism.- Around line 12-14: Add a language specifier to the fenced code blocks
containing the ASCII architecture diagrams so markdown linters accept them;
specifically update the blocks containing "Browser → UI Route (/oidc proxy) →
Hub OIDC → Hub API" and the multi-line block that includes "[Federated IDP]" and
"IdentityProvider CR" to usetext (or an empty language) instead of plain
so formatting is preserved and linting passes.- Around line 296-301: Add an equivalent Kubernetes Ingress example alongside
the OpenShift Route commands in AUTH.md: after the kubectl get route tackle ...
line, add the ingress command kubectl get ingress tackle -n konveyor-tackle -o
jsonpath='{.spec.rules[0].host}' (and similarly note the OIDC_ISSUER retrieval
remains the same for the tackle-hub and tackle-ui deployments using the env name
OIDC_ISSUER) so users on vanilla Kubernetes can extract the host exactly like
the Route example.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `7042fd35-dbc0-4461-8b1a-85953af7efd7` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 8e88d273279bdd2047c2bdfae8ba3e11a39ef631 and 56aef6857af50e953552ea9240b5522511243d70. </details> <details> <summary>📒 Files selected for processing (24)</summary> * `AUTH.md` * `bundle/manifests/konveyor-operator.clusterserviceversion.yaml` * `helm/templates/crds/tackle.konveyor.io_identityproviders.yaml` * `helm/templates/crds/tackle.konveyor.io_idpclients.yaml` * `helm/templates/crds/tackle.konveyor.io_ldapproviders.yaml` * `roles/tackle/defaults/main.yml` * `roles/tackle/tasks/main.yml` * `roles/tackle/templates/customresource-idp.yml.j2` * `roles/tackle/templates/customresource-idpclient.yml.j2` * `roles/tackle/templates/customresource-rhbk-keycloak.yml.j2` * `roles/tackle/templates/customresource-rhsso-keycloak.yml.j2` * `roles/tackle/templates/deployment-hub.yml.j2` * `roles/tackle/templates/deployment-keycloak-postgresql.yml.j2` * `roles/tackle/templates/deployment-keycloak-sso.yml.j2` * `roles/tackle/templates/deployment-ui.yml.j2` * `roles/tackle/templates/persistentvolumeclaim-keycloak-postgresql.yml.j2` * `roles/tackle/templates/secret-hub.yml.j2` * `roles/tackle/templates/secret-keycloak-db.yml.j2` * `roles/tackle/templates/secret-keycloak-postgresql.yml.j2` * `roles/tackle/templates/secret-keycloak-sso.yml.j2` * `roles/tackle/templates/service-keycloak-postgresql-migration.yml.j2` * `roles/tackle/templates/service-keycloak-postgresql.yml.j2` * `roles/tackle/templates/service-keycloak-rhbk.yml.j2` * `roles/tackle/templates/service-keycloak-sso.yml.j2` </details> <details> <summary>💤 Files with no reviewable changes (12)</summary> * roles/tackle/templates/deployment-keycloak-postgresql.yml.j2 * roles/tackle/templates/persistentvolumeclaim-keycloak-postgresql.yml.j2 * roles/tackle/templates/service-keycloak-postgresql-migration.yml.j2 * roles/tackle/templates/secret-keycloak-db.yml.j2 * roles/tackle/templates/secret-keycloak-postgresql.yml.j2 * roles/tackle/templates/secret-keycloak-sso.yml.j2 * roles/tackle/templates/service-keycloak-rhbk.yml.j2 * roles/tackle/templates/customresource-rhbk-keycloak.yml.j2 * roles/tackle/templates/service-keycloak-sso.yml.j2 * roles/tackle/templates/service-keycloak-postgresql.yml.j2 * roles/tackle/templates/deployment-keycloak-sso.yml.j2 * roles/tackle/templates/customresource-rhsso-keycloak.yml.j2 </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| # Deprecated Keycloak reference variables (for backwards compatibility only) | ||
| # Operator no longer deploys Keycloak - users must deploy and configure their own | ||
| # These variables exist only for explicit external Keycloak configuration | ||
|
|
||
| keycloak_sso_realm: "{{ app_name }}" | ||
| keycloak_sso_req_passwd_update: true | ||
| keycloak_sso_client_id: "{{ app_name }}-ui" | ||
| keycloak_api_audience: "konveyor-api" | ||
| keycloak_sso_tls_enabled: "{{ true if openshift_cluster | bool else false }}" | ||
| keycloak_sso_tls_secret_name: "{{ keycloak_sso_service_name }}-serving-cert" | ||
| keycloak_sso_port: "{{ '8443' if keycloak_sso_tls_enabled | bool else '8080' }}" | ||
| keycloak_sso_proto: "{{ 'https' if keycloak_sso_tls_enabled | bool else 'http' }}" | ||
| keycloak_sso_url: "{{ keycloak_sso_proto }}://{{ keycloak_sso_service_name }}.{{ app_namespace }}.svc:{{ keycloak_sso_port }}" | ||
| keycloak_sso_hostname: "" | ||
| keycloak_sso_hostname_backchannel_dynamic: false | ||
| keycloak_sso_url: "" # Set explicitly for external Keycloak | ||
| rhbk_url: "" # Set explicitly for external RHBK | ||
|
|
There was a problem hiding this comment.
Removing Keycloak DB defaults leaves a dangling reference used by Kai.
This change removes keycloak_database_image_fqin, but kai_database_image_fqin still depends on it later in the same file. That will break variable resolution when Kai paths are evaluated.
Suggested direction
+# Keep an explicit Kai DB image default independent of removed Keycloak vars.
+kai_database_image_fqin: "{{ lookup('env', 'RELATED_IMAGE_TACKLE_POSTGRES') }}"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@roles/tackle/defaults/main.yml` around lines 86 - 94, The removal of
keycloak_database_image_fqin leaves kai_database_image_fqin referencing a
missing variable; update the defaults so kai_database_image_fqin no longer
depends on keycloak_database_image_fqin by either adding an explicit default for
kai_database_image_fqin or changing its expression to use a safe fallback (e.g.,
a literal default or empty string) instead of keycloak_database_image_fqin;
locate and modify the kai_database_image_fqin variable definition in
defaults/main.yml and remove or replace any occurrence of
keycloak_database_image_fqin there.
There was a problem hiding this comment.
Is kai actually accessing the keycloak db?
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how kai_database is deployed and whether it references keycloak DB
rg -n "kai_database" roles/tackle/
echo "---"
# Check for any task that deploys kai-db
rg -n "kai.db\|kai-db\|kai_db" roles/tackle/tasks/
echo "---"
# Confirm keycloak_database_image_fqin usage across the repo
rg -n "keycloak_database_image_fqin" roles/Length of output: 2753
@jortel — No, Kai does not access the Keycloak database. Kai runs its own dedicated PostgreSQL instance (kai-db service), and kai_database_image_fqin was only reusing keycloak_database_image_fqin as a convenient way to pull the same Postgres image — not to share the database.
That said, the broken variable reference is still real: roles/tackle/defaults/main.yml line 288 still reads:
kai_database_image_fqin: "{{ keycloak_database_image_fqin }}"…and keycloak_database_image_fqin was removed by this PR. The fix is simply to give Kai its own direct image lookup:
kai_database_image_fqin: "{{ lookup('env', 'RELATED_IMAGE_TACKLE_POSTGRES') }}"| tls: | ||
| insecure: true |
There was a problem hiding this comment.
Do not hardcode tls.insecure: true for federated IDP.
This makes insecure TLS the default for all deployments. It should be opt-in and default to certificate verification enabled.
Suggested change
tls:
- insecure: true
+ insecure: {{ federated_idp_tls_insecure | default(false) | bool }}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@roles/tackle/templates/customresource-idp.yml.j2` around lines 21 - 22, The
template currently hardcodes tls.insecure: true in customresource-idp.yml.j2;
change this to make TLS verification the default and make disabling it opt-in by
replacing the hardcoded value with a templated/variable-driven default (e.g.,
use a variable like tls_insecure or idp.tls.insecure with a default of false)
and update any values/values.yaml or role defaults to expose that variable so
callers can opt in to insecure TLS when needed; ensure references to
tls.insecure in related rendering logic/documentation are updated accordingly.
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@AUTH.md`:
- Around line 28-32: Add a language identifier to the fenced code block
containing the ASCII diagram in AUTH.md so it satisfies markdownlint MD040;
locate the triple-backtick block that contains "Browser → UI Route (/oidc proxy)
→ Hub OIDC → [LDAP Server] → Hub API" and change the opening fence from ``` to
```text (i.e., add "text" as the language specifier) so the diagram is a
lint-compliant fenced code block.
- Line 325: The example in AUTH.md shows a contradictory custom client id value
("id: 100") vs the rule that custom clients must be >= 1000; update the sample
"id" field in the example to a value >= 1000 (e.g., 1000) so the example matches
the stated rule and ensures consistency for readers referencing the "id" field
in the auth client example.
In `@bundle/manifests/tackle.konveyor.io_identityproviders.yaml`:
- Around line 41-118: The CRD currently allows an empty spec; add schema-level
required constraints so core IdentityProvider fields cannot be omitted: update
the spec schema for the IdentityProvider resource to include a "required" array
containing "name", "issuer", and "clientId" (and include "redirectURI" if the
controller treats it as mandatory), and ensure those properties (name, issuer,
clientId, redirectURI) remain defined under spec with correct types; this will
enforce validation at creation/update rather than failing later in reconcile
(refer to the spec object and property names clientId, clientSecret, issuer,
name, redirectURI in the manifest).
In `@bundle/manifests/tackle.konveyor.io_idpclients.yaml`:
- Around line 104-110: The IdpClient CRD schema currently forbids custom client
IDs by enforcing "maximum: 999" on the id property and also leaves "spec"
optional; update the IdpClient schema so custom clients are allowed and spec is
required: remove (or adjust) the "maximum: 999" constraint on the id property in
the IdpClient schema (the "id" property block) so IDs >=1000 are permitted, and
add "spec" to the top-level required array of the IdpClient schema so the "spec"
object is mandatory.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2cd7a304-eac9-4944-90c3-eb1d7f59559a
📒 Files selected for processing (7)
AUTH.mdbundle/manifests/konveyor-operator.clusterserviceversion.yamlbundle/manifests/tackle.konveyor.io_identityproviders.yamlbundle/manifests/tackle.konveyor.io_idpclients.yamlbundle/manifests/tackle.konveyor.io_ldapproviders.yamlhelm/templates/rbac/role.yamlroles/tackle/templates/customresource-idpclient.yml.j2
✅ Files skipped from review due to trivial changes (1)
- bundle/manifests/tackle.konveyor.io_ldapproviders.yaml
| ``` | ||
| Browser → UI Route (/oidc proxy) → Hub OIDC → [LDAP Server] → Hub API | ||
| ↓ | ||
| LdapProvider CR | ||
| ``` |
There was a problem hiding this comment.
Add a language identifier to fenced block (markdownlint MD040).
The fenced block starting at Line 28 should specify a language (for this diagram, text is appropriate).
Suggested lint-compliant fence
-```
+```text
Browser → UI Route (/oidc proxy) → Hub OIDC → [LDAP Server] → Hub API
↓
LdapProvider CR</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 28-28: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@AUTH.md` around lines 28 - 32, Add a language identifier to the fenced code
block containing the ASCII diagram in AUTH.md so it satisfies markdownlint
MD040; locate the triple-backtick block that contains "Browser → UI Route (/oidc
proxy) → Hub OIDC → [LDAP Server] → Hub API" and change the opening fence from
``` to ```text (i.e., add "text" as the language specifier) so the diagram is a
lint-compliant fenced code block.
| name: my-custom-app | ||
| namespace: konveyor-tackle | ||
| spec: | ||
| id: 100 # Must be >= 1000 for custom clients (< 1000 reserved for seeded clients) |
There was a problem hiding this comment.
Fix contradictory custom client ID example.
Line 325 uses id: 100 but the same line says custom clients must be >= 1000. Update the sample value to match the stated rule.
Suggested doc fix
- id: 100 # Must be >= 1000 for custom clients (< 1000 reserved for seeded clients)
+ id: 1000 # Must be >= 1000 for custom clients (< 1000 reserved for seeded clients)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| id: 100 # Must be >= 1000 for custom clients (< 1000 reserved for seeded clients) | |
| id: 1000 # Must be >= 1000 for custom clients (< 1000 reserved for seeded clients) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@AUTH.md` at line 325, The example in AUTH.md shows a contradictory custom
client id value ("id: 100") vs the rule that custom clients must be >= 1000;
update the sample "id" field in the example to a value >= 1000 (e.g., 1000) so
the example matches the stated rule and ensures consistency for readers
referencing the "id" field in the auth client example.
| id: | ||
| description: |- | ||
| ID is the database ID for the seeded client. | ||
| Must be less than 1000 (reserved range for seeded clients). | ||
| maximum: 999 | ||
| minimum: 1 | ||
| type: integer |
There was a problem hiding this comment.
IdpClient schema currently blocks custom clients and permits missing spec.
Line 108 caps id at 999, which conflicts with the documented custom-client range (>= 1000), and Lines 189-190 do not require spec at the top level. Together, this creates a broken/weak API contract.
Suggested schema corrections
id:
description: |-
ID is the database ID for the seeded client.
Must be less than 1000 (reserved range for seeded clients).
- maximum: 999
minimum: 1
type: integer
@@
- type: object
+ required:
+ - spec
+ type: objectAlso applies to: 189-190
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bundle/manifests/tackle.konveyor.io_idpclients.yaml` around lines 104 - 110,
The IdpClient CRD schema currently forbids custom client IDs by enforcing
"maximum: 999" on the id property and also leaves "spec" optional; update the
IdpClient schema so custom clients are allowed and spec is required: remove (or
adjust) the "maximum: 999" constraint on the id property in the IdpClient schema
(the "id" property block) so IDs >=1000 are permitted, and add "spec" to the
top-level required array of the IdpClient schema so the "spec" object is
mandatory.
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
Signed-off-by: Jeff Ortel <jortel@redhat.com>
llm-proxy is now reached only through tackle2-hub's /services/llm-proxy reverse-proxy endpoint. The hub validates the bearer token, enforces the llm-proxy RBAC scope, and forwards user identity in the X-Hub-User / X-Hub-User-Attributes headers it injects in ServiceHandler.Forward. Operator changes: - Hub Deployment gains LLM_PROXY_URL env (only when kai_llm_proxy_enabled), pointing at the cluster-internal Service URL. Hub reads this at startup to register the llm-proxy route in its serviceRoutes map. - UI Deployment drops KAI_LLM_PROXY_URL; the new UI image's server-side proxy targets TACKLE_HUB_URL with pathRewrite /llm-proxy -> /services/llm-proxy. - llm-proxy ConfigMap drops the oauth2_token Keycloak JWKS auth block. llm-proxy itself does no token validation; the namespace NetworkPolicy is the only barrier against in-namespace callers bypassing the hub. Same trust posture as kai-solution-server today. - Renamed kai_llm_proxy_url -> kai_llm_proxy_internal_url to signal "only hub should call this directly". - test-llm-proxy.sh rewritten for the new auth flow: uses HTTP Basic Auth against hub's seeded admin user and hits the LLM through /hub/services/llm-proxy/* so the test path goes through the existing /hub UI proxy and does not depend on the new tackle2-ui image. Companion changes required in: - tackle2-hub: register llm-proxy in serviceRoutes + inject X-Hub-User identity headers in ServiceHandler.Forward. - tackle2-ui: server/src/proxies.js retargets /llm-proxy at TACKLE_HUB_URL with pathRewrite to /services/llm-proxy. (Browser use only; not needed for the e2e test in this PR.) Based on PR konveyor#562 (Keycloak dependency removal / hub OIDC provider).
llm-proxy is now reached only through tackle2-hub's /services/llm-proxy reverse-proxy endpoint. The hub validates the bearer token, enforces the llm-proxy RBAC scope, and forwards user identity in the X-Hub-User / X-Hub-User-Attributes headers it injects in ServiceHandler.Forward. Operator changes: - Hub Deployment gains LLM_PROXY_URL env (only when kai_llm_proxy_enabled), pointing at the cluster-internal Service URL. Hub reads this at startup to register the llm-proxy route in its serviceRoutes map. - UI Deployment drops KAI_LLM_PROXY_URL; the new UI image's server-side proxy targets TACKLE_HUB_URL with pathRewrite /llm-proxy -> /services/llm-proxy. - llm-proxy ConfigMap drops the oauth2_token Keycloak JWKS auth block. llm-proxy itself does no token validation; the namespace NetworkPolicy is the only barrier against in-namespace callers bypassing the hub. Same trust posture as kai-solution-server today. - Renamed kai_llm_proxy_url -> kai_llm_proxy_internal_url to signal "only hub should call this directly". - test-llm-proxy.sh rewritten for the new auth flow: uses HTTP Basic Auth against hub's seeded admin user and hits the LLM through /hub/services/llm-proxy/* so the test path goes through the existing /hub UI proxy and does not depend on the new tackle2-ui image. Companion changes required in: - tackle2-hub: register llm-proxy in serviceRoutes + inject X-Hub-User identity headers in ServiceHandler.Forward. - tackle2-ui: server/src/proxies.js retargets /llm-proxy at TACKLE_HUB_URL with pathRewrite to /services/llm-proxy. (Browser use only; not needed for the e2e test in this PR.) Based on PR konveyor#562 (Keycloak dependency removal / hub OIDC provider).
✨ Route llm-proxy through hub /services/llm-proxy
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
bundle/manifests/konveyor-operator.clusterserviceversion.yaml (2)
240-242:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate the CSV auth description.
The install description still says auth mode deploys Keycloak, but this PR moves auth to Hub OIDC with optional federation. OLM surfaces this text directly to users, so it should match the new behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@bundle/manifests/konveyor-operator.clusterserviceversion.yaml` around lines 240 - 242, The CSV's install description string that mentions "Authentication capabilities may be enabled via the `feature_auth_required` parameter..." and specifically calls out Keycloak must be updated to reflect the new behavior: replace the Keycloak-specific text with a description stating that auth is provided via Hub OIDC (with optional federation to external providers) when `feature_auth_required` is enabled; ensure the CSV entry that contains the bullet list and the sentence mentioning Keycloak is edited (the install/description field containing "Authentication capabilities..." and the bullet "* Keycloak, to manage authentication...") so OLM shows the new Hub OIDC/federation behavior instead of Keycloak.
282-296:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDrop write verbs for legacy Keycloak CRs.
This PR removes operator-managed Keycloak, so this rule should not still allow cluster-wide
create/update/patch/deleteon Keycloak resources. Keeping those verbs is broader than the new migration/detection flow needs.Suggested fix
- apiGroups: - keycloak.org - k8s.keycloak.org resources: - keycloaks - keycloakrealms - keycloakclients - keycloakusers verbs: - get - list - watch - - create - - update - - patch - - delete🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@bundle/manifests/konveyor-operator.clusterserviceversion.yaml` around lines 282 - 296, The ClusterServiceVersion RBAC rule for API groups "keycloak.org" and "k8s.keycloak.org" currently grants write verbs (create, update, patch, delete) for resources "keycloaks", "keycloakrealms", "keycloakclients", and "keycloakusers"; remove the write verbs so only read/detect verbs remain (e.g., keep get, list, watch) to match the new migration/detection-only behavior and avoid cluster-wide operator-managed Keycloak writes.helm/templates/crds/tackle.konveyor.io_idpclients.yaml (1)
104-109:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAllow custom
IdpClientIDs.The CRD caps
spec.idat999, butAUTH.mdnow documents user-createdIdpClientresources with IDs>= 1000. As written, admission will reject the custom-client path this PR introduces.Suggested fix
id: description: |- - ID is the database ID for the seeded client. - Must be less than 1000 (reserved range for seeded clients). - maximum: 999 + ID is the database ID for the client. + IDs 1-999 are reserved for operator-seeded clients. minimum: 1 type: integer🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@helm/templates/crds/tackle.konveyor.io_idpclients.yaml` around lines 104 - 109, The CRD currently enforces a maximum of 999 on the IdpClient "id" field which blocks user-created IdpClient resources with spec.id >= 1000; remove the hard cap (delete the "maximum: 999" entry) or raise it to an intentionally large upper bound so the "id" property under the IdpClient CRD (the "id" schema used for spec.id) no longer rejects custom-client IDs >=1000, then run a CRD validation check to ensure the schema still requires an integer >= 1.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/e2e/llm-proxy/test-llm-proxy.sh`:
- Around line 42-46: The script sets HUB_URL to "http://$INGRESS_HOST" which
breaks when ingress enforces SSL redirects for auth-enabled runs; update the
INGRESS handling (the block that sets INGRESS_HOST and HUB_URL) to set
HUB_URL="https://$INGRESS_HOST" when AUTH_MODE is not "none" (or when an
AUTH_MODE env var indicates auth is enabled), otherwise keep http; ensure this
uses the existing INGRESS_HOST variable and preserves the empty-string fallback
behavior.
---
Outside diff comments:
In `@bundle/manifests/konveyor-operator.clusterserviceversion.yaml`:
- Around line 240-242: The CSV's install description string that mentions
"Authentication capabilities may be enabled via the `feature_auth_required`
parameter..." and specifically calls out Keycloak must be updated to reflect the
new behavior: replace the Keycloak-specific text with a description stating that
auth is provided via Hub OIDC (with optional federation to external providers)
when `feature_auth_required` is enabled; ensure the CSV entry that contains the
bullet list and the sentence mentioning Keycloak is edited (the
install/description field containing "Authentication capabilities..." and the
bullet "* Keycloak, to manage authentication...") so OLM shows the new Hub
OIDC/federation behavior instead of Keycloak.
- Around line 282-296: The ClusterServiceVersion RBAC rule for API groups
"keycloak.org" and "k8s.keycloak.org" currently grants write verbs (create,
update, patch, delete) for resources "keycloaks", "keycloakrealms",
"keycloakclients", and "keycloakusers"; remove the write verbs so only
read/detect verbs remain (e.g., keep get, list, watch) to match the new
migration/detection-only behavior and avoid cluster-wide operator-managed
Keycloak writes.
In `@helm/templates/crds/tackle.konveyor.io_idpclients.yaml`:
- Around line 104-109: The CRD currently enforces a maximum of 999 on the
IdpClient "id" field which blocks user-created IdpClient resources with spec.id
>= 1000; remove the hard cap (delete the "maximum: 999" entry) or raise it to an
intentionally large upper bound so the "id" property under the IdpClient CRD
(the "id" schema used for spec.id) no longer rejects custom-client IDs >=1000,
then run a CRD validation check to ensure the schema still requires an integer
>= 1.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 565889ed-011f-4f7d-b629-715a4828886b
📒 Files selected for processing (20)
bundle/manifests/konveyor-operator.clusterserviceversion.yamlbundle/manifests/tackle.konveyor.io_identityproviders.yamlbundle/manifests/tackle.konveyor.io_idpclients.yamlbundle/manifests/tackle.konveyor.io_ldapproviders.yamlhelm/templates/crds/tackle.konveyor.io_identityproviders.yamlhelm/templates/crds/tackle.konveyor.io_idpclients.yamlhelm/templates/crds/tackle.konveyor.io_ldapproviders.yamlhelm/templates/deployment.yamlhelm/values.yamlroles/tackle/defaults/main.ymlroles/tackle/tasks/main.ymlroles/tackle/templates/deployment-hub.yml.j2roles/tackle/templates/deployment-ui.yml.j2roles/tackle/templates/ingress-ui.yml.j2roles/tackle/templates/kai/llm-proxy-configmap.yaml.j2roles/tackle/templates/route-ui.yml.j2roles/tackle/templates/secret-cookie-secret.yml.j2roles/tackle/templates/service-ui.yml.j2roles/tackle/templates/serviceaccount-ui.yml.j2test/e2e/llm-proxy/test-llm-proxy.sh
💤 Files with no reviewable changes (5)
- roles/tackle/templates/route-ui.yml.j2
- roles/tackle/templates/secret-cookie-secret.yml.j2
- helm/templates/deployment.yaml
- roles/tackle/templates/serviceaccount-ui.yml.j2
- helm/values.yaml
✅ Files skipped from review due to trivial changes (3)
- helm/templates/crds/tackle.konveyor.io_identityproviders.yaml
- helm/templates/crds/tackle.konveyor.io_ldapproviders.yaml
- bundle/manifests/tackle.konveyor.io_identityproviders.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
- bundle/manifests/tackle.konveyor.io_ldapproviders.yaml
- bundle/manifests/tackle.konveyor.io_idpclients.yaml
- roles/tackle/tasks/main.yml
| if kubectl get ingress tackle -n "$NAMESPACE" &>/dev/null; then | ||
| INGRESS_HOST=$(kubectl get ingress tackle -n "$NAMESPACE" -o jsonpath='{.spec.rules[0].host}' 2>/dev/null || echo "") | ||
| if [ -n "$INGRESS_HOST" ]; then | ||
| HUB_URL="http://$INGRESS_HOST" | ||
| fi |
There was a problem hiding this comment.
Use HTTPS for ingress-derived HUB_URL in auth-enabled runs.
Line 45 hardcodes http://, but ingress auth mode now enforces SSL redirect; that can make the Line 76 and Line 110 requests return redirects/non-JSON instead of API responses.
Suggested fix
HUB_URL=""
+CURL_TLS_ARGS=()
if kubectl get ingress tackle -n "$NAMESPACE" &>/dev/null; then
INGRESS_HOST=$(kubectl get ingress tackle -n "$NAMESPACE" -o jsonpath='{.spec.rules[0].host}' 2>/dev/null || echo "")
if [ -n "$INGRESS_HOST" ]; then
- HUB_URL="http://$INGRESS_HOST"
+ HUB_URL="https://$INGRESS_HOST"
+ CURL_TLS_ARGS=(-k)
fi
fi
@@
- PROXY_RESPONSE=$(curl -s -X POST "${HUB_URL}/hub/services/llm-proxy/v1/chat/completions" \
+ PROXY_RESPONSE=$(curl -s "${CURL_TLS_ARGS[@]}" -X POST "${HUB_URL}/hub/services/llm-proxy/v1/chat/completions" \
@@
-INVALID_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${HUB_URL}/hub/services/llm-proxy/v1/chat/completions" \
+INVALID_STATUS=$(curl -s "${CURL_TLS_ARGS[@]}" -o /dev/null -w "%{http_code}" -X POST "${HUB_URL}/hub/services/llm-proxy/v1/chat/completions" \🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/e2e/llm-proxy/test-llm-proxy.sh` around lines 42 - 46, The script sets
HUB_URL to "http://$INGRESS_HOST" which breaks when ingress enforces SSL
redirects for auth-enabled runs; update the INGRESS handling (the block that
sets INGRESS_HOST and HUB_URL) to set HUB_URL="https://$INGRESS_HOST" when
AUTH_MODE is not "none" (or when an AUTH_MODE env var indicates auth is
enabled), otherwise keep http; ensure this uses the existing INGRESS_HOST
variable and preserves the empty-string fallback behavior.
Another attempt at #562. --- ● # 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_url` → `kai_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: ```bash # 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: ```yaml 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: ```yaml 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: ```yaml 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 - [x] Code changes implemented according to plan - [x] New CRDs added and validated - [x] Keycloak detection logic working - [x] IdpClient CRs created automatically - [x] Upgrade path preserves existing Keycloak - [x] Fresh installation works without Keycloak - [x] LLM proxy routing through Hub works - [x] Bundle/CSV updated and validated - [x] Helm chart updated with new CRDs - [x] Documentation updated ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for OIDC and LDAP identity providers for authentication * Added API key authentication support for Hub * **Improvements** * Enhanced LLM proxy integration testing and debug logging * Updated authentication architecture to support multiple provider types <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Jeff Ortel <jortel@redhat.com> Signed-off-by: Fabian von Feilitzsch <fabian@fabianism.us> Co-authored-by: Fabian von Feilitzsch <fabian@fabianism.us>
Summary
Introduces a new OIDC-based authentication architecture where the Hub acts as the primary OpenID Connect provider, with optional federation to external identity
providers (Keycloak, RHSSO, RHBK, LDAP).
Key Changes
New Authentication Architecture
Hub as OIDC Provider: Hub now serves as a built-in OAuth 2.0 / OIDC server with endpoints at
/oidc/oidc/.well-known/openid-configuration/oidc/authorize/oidc/token/oidc/callbackFlexible Authentication Modes:
New Custom Resource Definitions
Added three new CRDs under
tackle.konveyor.io/v1alpha1:Documentation
Backward Compatibility
Security Features
APIKEY_SECRETMigration Impact
For existing deployments:
https://<ui-route-host>/oidc/callbackcloses #560
Summary by CodeRabbit
Documentation
New Features
Refactor
Tests