Skip to content

fix: Update audience scope mapper when included.custom.audience changes - #331

Merged
pdettori merged 2 commits into
rossoctl:mainfrom
akram:fix/audience-scope-mapper-update
May 7, 2026
Merged

fix: Update audience scope mapper when included.custom.audience changes#331
pdettori merged 2 commits into
rossoctl:mainfrom
akram:fix/audience-scope-mapper-update

Conversation

@akram

@akram akram commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #330

When an audience scope mapper already exists (HTTP 409 Conflict), ensureAudienceMapper now fetches the existing mapper and compares its included.custom.audience value. If it differs from the desired value, the mapper is updated via PUT.

Previously, 409 was treated as success without checking the audience value, causing stale mappers when clients transitioned from short-form IDs (namespace/workload) to SPIFFE URIs (spiffe://domain/ns/namespace/sa/workload) or vice versa.

Changes

  • Add ID field to protocolMapperRep (needed for PUT by mapper ID)
  • On 409 Conflict in ensureAudienceMapper, call new updateAudienceMapperIfNeeded to check and fix the audience
  • Add putAudienceMapper for updating an existing mapper via PUT
  • Add two tests: one verifying stale mappers get updated, one verifying correct mappers are left alone

Root Cause

The EnsureAudienceScope caller in clientregistration_controller.go correctly passes the resolved SPIFFE URI as AudienceClientID:

kc.EnsureAudienceScope(ctx, token, keycloak.AudienceParams{
    ClientName:       clientName,    // "namespace/workload"
    AudienceClientID: clientID,      // "spiffe://domain/ns/.../sa/workload"
})

But if the scope was initially created with the short-form audience (e.g., before SPIFFE was enabled), the mapper POST returns 409 and the stale audience was never corrected.

Test plan

  • TestEnsureAudienceScope_UpdatesStaleMapper — verifies stale short-form audience is updated to SPIFFE URI via GET + PUT
  • TestEnsureAudienceScope_SkipsUpdateWhenCorrect — verifies no PUT is issued when audience already matches
  • All existing TestEnsureAudienceScope* tests pass
  • Full keycloak package tests pass (go test ./internal/keycloak/ -v)
  • Tested on OpenShift cluster (ROSA) with RedBank demo: disabled SPIFFE → verified short-form audiences → re-enabled SPIFFE → operator updated mappers to SPIFFE URIs → token exchange tests pass in both modes

Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

@huang195

huang195 commented May 5, 2026

Copy link
Copy Markdown
Member

This seems like a corner case that we have not tested. If I understand it correctly, the scenario is that an agent was initially provisioned without SPIRE enabled, and later, it was restarted with SPIRE enabled. Because error 409 is treated as success, client registration doesn't proceed to update Keycloak with the updated audience scope mapper. Is this right?

I'm curious what is your use case that you needed to restart an agent from no-spire to with-spire. Can't you delete the agent and create a new one?

@akram

akram commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

That's correct @huang195 . My use case is just that I am running a sequence of tests and I first try token exchange in non-spiffe mode. And then, I enable spiffe and expect token exchange to work as well.

For regular kagentiusers; when they use the kagenti ui; that should correspond to checking unchecking the "Enable SPIFFE" checkbox in the UI. They should certainly hit the same issue.

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped fix for a real production issue (toggling SPIFFE on/off leaves stale audience mappers). The GET+compare+PUT logic on 409 Conflict is the right approach. Tests cover both the update and no-op paths. All CI green.

A few non-blocking suggestions inline.

Comment thread kagenti-operator/internal/keycloak/audience.go Outdated
Comment thread kagenti-operator/internal/keycloak/audience.go
Comment thread kagenti-operator/internal/keycloak/audience.go
@akram
akram force-pushed the fix/audience-scope-mapper-update branch from fc6774a to 95947c6 Compare May 7, 2026 17:01
@akram

akram commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

/retest

akram added 2 commits May 7, 2026 22:15
When an audience scope mapper already exists (409 Conflict), fetch the
existing mapper and compare its included.custom.audience value. If it
differs from the desired value (e.g. short-form "ns/wl" vs SPIFFE URI),
update it via PUT.

Previously, 409 was treated as success without checking the audience
value, causing stale mappers when clients transitioned from short-form
IDs to SPIFFE URIs.

Fixes rossoctl#330

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Akram <akram.benaissi@gmail.com>
- Drop omitempty from protocolMapperRep.ID to fail explicitly on empty ID
- Add nil guard for Config map to prevent potential panic
- Add slog.Debug log when no matching audience mapper is found

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Akram <akram.benaissi@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Audience scope mapper not updated when client ID changes (SPIFFE URI mismatch)

4 participants