Skip to content

fix(security-operator): address AuthorizationModel StoreRef at the org's generated cluster#477

Open
ifdotpy wants to merge 2 commits intoplatform-mesh:mainfrom
ifdotpy:fix/openkcm-store-ref
Open

fix(security-operator): address AuthorizationModel StoreRef at the org's generated cluster#477
ifdotpy wants to merge 2 commits intoplatform-mesh:mainfrom
ifdotpy:fix/openkcm-store-ref

Conversation

@ifdotpy
Copy link
Copy Markdown

@ifdotpy ifdotpy commented Apr 15, 2026

Summary

  • Every provider APIExport binding generates an AuthorizationModel whose StoreRef.Cluster must identify the KCP workspace that hosts the org's OpenFGA Store. The Process path was addressing it by Organization.OriginClusterId; the Finalize path in the same file already uses Organization.GeneratedClusterId to identify the org. Align Process with Finalize so provider auth modules actually merge into the org store on write.
  • Add a regression test asserting StoreRef.Cluster == Organization.GeneratedClusterId for any namespaced provider resource.

Why

StoreRef is a KCP workspace reference (see internal/subroutine/authorization_model.go -> getRelatedAuthorizationModels matching on the store's logical cluster key from multicluster-runtime context). Organization.OriginClusterId is the shard-side identifier used in OpenFGA tuple object strings - stable for tuples, wrong for workspace lookups. Organization.GeneratedClusterId is the org's logical cluster identity and matches what the Finalize path already uses to disambiguate bindings. The two cluster IDs are distinct by design (see account-operator account_info_types.go); Process was picking the wrong one.

Why this isn't a provider-specific bug

Every APIBinding (regardless of provider) flows through this subroutine. Any org-scoped provider APIExport currently produces an AuthorizationModel whose StoreRef points at the wrong logical cluster for the org store, so its module is never merged into that store - the resource becomes unreachable to account-scope users because OpenFGA returns NoOpinion -> default deny at the gateway. The symptom is more visible for providers whose resources are consumed from account scope through the shared store; the root cause is generic.

Other OriginClusterId sites intentionally stay as they are

Usage in apiexportpolicy.go and account-operator/pkg/subroutines/fga.go composes FGA tuple user/object strings (e.g. core_platform-mesh_io_account:<OriginClusterId>/<name>). Those are the stable identifiers inside OpenFGA's model graph; changing them would invalidate the existing tuple graph. Left unchanged on purpose.

Testing

  • go test ./internal/subroutine -run TestAuthorizationModelGeneration_Process_UsesGeneratedClusterForStoreRef -count=1
  • Full subroutine suite: go test ./internal/subroutine -count=1

Risk

  • AccountInfos with empty Organization.GeneratedClusterId would produce a model with an empty StoreRef.Cluster. The account-operator's FGA subroutine already guards on a non-empty value before propagating (account-operator/pkg/subroutines/fga.go:95), so in a healthy cluster this field is populated by the time an APIBinding is processed. Worth sanity-checking on older clusters before rollout.

@ifdotpy ifdotpy requested review from a team as code owners April 15, 2026 13:13
The StoreRef-cluster fix is generic to every provider; the test should
read that way. Swap OpenKCM-specific identifiers (operations.openkcm.io /
servicekeys / openkcm-provider workspace) for the stand-in example.io /
widgets / providers:example so the intent is 'any provider APIBinding
generates an AuthorizationModel addressed at the org GeneratedClusterId',
not 'OpenKCM happens to break on cc-d2'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ifdotpy ifdotpy changed the title fix: use generated org cluster for provider auth models fix(security-operator): address AuthorizationModel StoreRef at the org's generated cluster Apr 15, 2026
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.

1 participant