[improve][broker] Add authn/authz to Scalable Topics Admin API (PIP-460)#25618
Merged
merlimat merged 2 commits intoApr 29, 2026
Merged
Conversation
The initial Scalable Topics Admin API (apache#25565) did not enforce authentication or authorization on its REST endpoints — they only parsed the namespace name. This wires up the same authz model used by the rest of the Admin API. ScalableTopics (/admin/v2/scalable): - list/create/delete: validateNamespaceOperationAsync (GET_TOPICS / CREATE_TOPIC / DELETE_TOPIC) - getMetadata/getStats: validateTopicOperationAsync (GET_METADATA / GET_STATS) - create/deleteSubscription: validateTopicOperationAsync (SUBSCRIBE / UNSUBSCRIBE) with the subscription name - splitSegment/mergeSegments: validateSuperUserAccessAsync (super-user only; reserved for operator-driven scaling, can be relaxed later if auto-split workflows need it) Segments (/admin/v2/segments): - All three endpoints (createSegment, terminateSegment, deleteSegment) now require validateSuperUserAccessAsync before the existing validateTopicOwnershipAsync routing. These endpoints are cross-broker coordination primitives invoked by the controller broker (which runs with super-user broker credentials) — they are not user-facing. - Class-level Javadoc documents the super-user-only design boundary. - Added 401/403 to @ApiResponses on each endpoint. Adds ScalableTopicsAuthZTest covering nobody / tenant-admin / super-user roles against all 12 endpoints (12 tests, all passing).
merlimat
reviewed
Apr 29, 2026
…n in helpers Address review feedback on apache#25618: extract two private helpers in ScalableTopics so the duplicated service-availability check and controller-leader redirect are no longer repeated inline at each call site. - withScalableTopicService(op): runs op against the local ScalableTopicService, surfacing 503 if the service is not available on this broker. Used by getStats (read-only, no redirect). - onControllerLeader(tn, op): combines withScalableTopicService with redirectToControllerLeaderIfNeeded so endpoints requiring the elected controller leader (createSubscription, deleteSubscription, splitSegment, mergeSegments) express the operation as a single chained step. No behavior change. Existing ScalableTopicsAuthZTest (12) and the scalable suites (ConsumerSession, DagWatchSession, ScalableTopicController, ScalableTopicService, SegmentLayout, SubscriptionCoordinator — 92 total) still pass.
merlimat
approved these changes
Apr 29, 2026
poorbarcode
pushed a commit
to poorbarcode/pulsar
that referenced
this pull request
May 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #25598
PIP: 460
Follow-up to #25565, which introduced the Scalable Topics (Topics v5) Admin API without enforcing authentication or authorization on its REST endpoints.
Motivation
The initial Scalable Topics Admin API merged in #25565 only called
validateNamespaceName(...)(a name-format parser) on its REST endpoints. None of the 9 endpoints under/admin/v2/scalable/...performed any authn/authz check, and the 3 endpoints under/admin/v2/segments/...only didvalidateTopicOwnershipAsync(...)(a routing/ownership check, not an authorization check). The OpenAPI annotations on theScalableTopicsendpoints already advertise401 / 403responses, so the public contract was written but not enforced.PIP-460 §Security Considerations states: "The new admin API endpoints for segment operations (split, merge, metadata read) will require the same permissions as equivalent topic-level admin operations." This PR wires that up, mirroring the patterns used elsewhere in the Admin API (
PersistentTopics/PersistentTopicsBase).Modifications
pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java— added an authz call as the first step of the async chain on each of the 9 endpoints. Operation mapping follows the conventions used by the partitioned-topic admin API:GET /{tenant}/{ns}(list)validateNamespaceOperationAsync(GET_TOPICS)PUT /{tenant}/{ns}/{topic}(create)validateNamespaceOperationAsync(CREATE_TOPIC)GET /{tenant}/{ns}/{topic}(metadata)validateTopicOperationAsync(GET_METADATA)DELETE /{tenant}/{ns}/{topic}(delete)validateNamespaceOperationAsync(DELETE_TOPIC)GET .../statsvalidateTopicOperationAsync(GET_STATS)PUT .../subscriptions/{sub}validateTopicOperationAsync(SUBSCRIBE, subscription)DELETE .../subscriptions/{sub}validateTopicOperationAsync(UNSUBSCRIBE, subscription)POST .../split/{segmentId}validateSuperUserAccessAsync()POST .../merge/{id1}/{id2}validateSuperUserAccessAsync()splitSegmentandmergeSegmentsare super-user only for now. Auto-split / auto-merge and any tenant-admin-initiated workflows can revisit this without breaking compatibility (relaxing access is non-breaking; tightening is breaking).pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java— all three endpoints (createSegment,terminateSegment,deleteSegment) now callvalidateSuperUserAccessAsync()before the existingvalidateTopicOwnershipAsync(...)routing check. These endpoints are cross-broker coordination primitives invoked by the controller broker during split/merge — not user-facing. The controller broker uses its broker-internal credentials, which are super-user, so internal coordination continues to work; tenant admins (and other principals) cannot bypass the super-user requirement onsplitSegment/mergeSegmentsby calling the segment-level endpoints directly. Class-level Javadoc documents this security boundary, and401/403are added to@ApiResponseson each endpoint.pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/ScalableTopicsAuthZTest.java— new TestNG class modeled afterTopicAuthZTest. 12 tests cover all 12 endpoints (9 inScalableTopics, 3 inSegments) against three roles: anonymous (NOBODY_TOKEN), tenant admin, and super-user. The test asserts the authz contract only — non-NotAuthorizedfailures from the underlying service are tolerated, since the happy paths are already covered byScalableTopicServiceTest/ScalableTopicControllerTest.When
authenticationorauthorizationis disabled, the existingvalidateXxxAsynchelpers complete immediately withnull, so behavior is unchanged for clusters that do not enable auth.Verifying this change
This change added tests and can be verified as follows:
ScalableTopicsAuthZTest(12 tests): all pass. Covers nobody / tenant-admin / super-user roles against all 12 endpoints.ConsumerSessionTest,DagWatchSessionTest,ScalableTopicControllerTest,ScalableTopicServiceTest,SegmentLayoutTest,SubscriptionCoordinatorTest— 92/92 pass, no regressions../gradlew :pulsar-broker:checkstyleMain :pulsar-broker:checkstyleTestclean.Does this pull request potentially affect one of the following parts:
The REST endpoints under
/admin/v2/scalable/*and/admin/v2/segments/*now enforce authentication/authorization. Clusters that previously relied on these endpoints being unauthenticated will see401/403for non-super-user (and, for the segment-level endpoints, non-super-user-only) callers when authentication and authorization are enabled. This brings the endpoints in line with the rest of the Admin API and matches the contract already advertised by the existing@ApiResponsesannotations.