-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow subscribers to access subscription admin-api #2981
Conversation
@rdhabalia Could this solved with the per-subscription auth mechanism which is already available? |
@merlimat I didn't see a placeholder which keeps map of authorized roles for a given subscription so, broker can authorize admin-api request. also, I am not exactly aware about per-sub auth, can you please point me the PR or change. |
Oh.. no, that will not help because in our useacase, recently many of the existing subscribers are reaching out to system-admin to execute subscription admin-api (eg: skip-all, skip, reset-cursor) due to multiple reasons (eg: backlog quota exceeded, reseting cursor with retention enable, etc..). So, in that case it's hard to handle multiple requests from subscribers so, it's better to let subscriber handle those admin-api. #899 restricts subscription-name creation with the role-name prefix but it will not address authorization of existing subscription name which doesn't have role-name prefix. |
My only concern is to end up with 2 ways to do (almost) the same thing, which might be confusing to users. |
Isn't it possible to give permissions to these subscriptions individually (with the existing solution and without changing subscription names) ? |
Umm.. #899 doesn't store authorized subscriber role-names. it authorizes request based on the sub-name (eg. |
@merlimat I think #899 can be only useful to avoid conflicting name because for authorization it enforces role name prefix and it has to be part of sub-name and that is something not feasible. |
@rdhabalia I see. Then this change would be a superset of #899 (in the sense that it would allow to achieve that goal as well), am I right? Would it then make sense to deprecate the sub prefix mode feature and just rely on "per-subscription" authorization? cc/ @nkurihar |
Yes, next I wanted to integrate this policy with consumer authorization so, at that time we can deprecate sub-prefix-mode and utilize per-sub authorization mechanism. I will try to address it in next PR. |
* the subscription name defined by the client | ||
* @return | ||
*/ | ||
CompletableFuture<Set<String>> getAuthorizedRolesOnSubscription(TopicName topicName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why getting a list of roles here instead of behaving like the rest of the methods?
I actually think that this should be handled by canConsumeAsync()
. Since we might not be able to fetch that info from the Authorization plugin implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, broker stores authorization metadata by calling AuthorizationServiceProvider::grantPermission(). and right now, broker is having default ZK-AuthorizationProvider which stores metadata into same global-ZK under policies so, if we want to retrieve then we can see it in policies.
However, if one implements different provider which stores this metadata somewhere else then broker will not have the way to get authorization metadata and user will not be able to see stored authorization-roles.
So, I added API by considering that we can utilize this API later to fetch auth metadata from Authorization provider. As this interface can be implemented by user, ideally we should not try to break so, I tried to keep it generic enough (though I am breaking the interface by adding new API but it seems it might be fine right now).
Does it make sense? or we still want to change api to isAuthorizedOnSubscription(..)
instead getAuthorizedRolesOnSubscription(..)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say to not add a new method, but rather handle that internally in the canConsume()
. That method is already taking the subscription name (along with the client credentials) and should be able to make the assessment.
There might be cases in which the permission might be already encrypted into the credentials, or that the check needs to be performed against external system.
If authorization is stored in default zk-store, then doing pulsar-admin namespaces policies
will already print the authorized roles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say to not add a new method, but rather handle that internally in the canConsume().
hmm.. yes, we can do that. let me fix it.
If authorization is stored in default zk-store, then doing pulsar-admin namespaces policies will already print the authorized roles
But what if authorization is not using default zk-store. in that case, we may have to add get() method in auth-provider. but that we can do later as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say to not add a new method, but rather handle that internally in the canConsume().
@merlimat this will not work because we want to explicitly give access to certain role that can use subscription-based admin-api (eg: reset-cursor, skip) for a given subscription. If the role is not configured/present into authorization list then admin-api request should fail.
whereas canConsume()
can not fail if subscription-authorization
list is not configured. If we enforce subscription-authorization
in canConsume
method then all existing consumer will start failing because we don't set this permission explicitly.
I can make change in canConsume()
where if sub-authorization
is configured then validate role else ignore the check. but we can't use canConsume()
for admin-api validation (once we have this check then we deprecate sub-prefix-auth
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see admin api permissions as different from "consume" permissions.
If a use has consume access to some topic (on all the subscriptions) than it can "mess up" some other consumer by attaching to the wrong subscription and stealing someone else's messages.
It's exactly the same as opening the admin API to all the users who have consume access on the topic.
To solve that, you can :
- Grant per-subscription authorization to each user on its subscription
- Remove the per-namespace consume authorization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a use has consume access to some topic (on all the subscriptions) than it can "mess up" some other consumer by attaching to the wrong subscription and stealing someone else's messages.
which is already incorrect. right? we should have a way to prevent this and with this PR it can be possible. But by default we can't enforce Per-Sub for consumers as it can create issue for existing topics. But may be pulsar can have a flag to enforce it in the system.
I don't see admin api permissions as different from "consume" permissions.
Actually then we don't need this PR at all. No need of introducing "Per-Subscription" authorization if "Namespace-auth(consume)" is anyway present so, "Namespace-auth" will always win and all subscribers can access each other's cursor state.
So, I thought admin-api right now doesn't have any authorization present, we can make it right atleast for admin-api by enforcing "Per-Subscription" validation.
But Let me know if you still think admin-api should not enforce "Per-subscription" then I will make your suggested change and all api will use one canConsume()-api
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which is already incorrect. right? we should have a way to prevent this and with this PR it can be possible.
I think having per-subscription ACLs should be enough, right?
But by default we can't enforce Per-Sub for consumers as it can create issue for existing topics. But may be pulsar can have a flag to enforce it in the system.
Even for existing topic, we can just add the per-subscription ACLs, no?
Actually then we don't need this PR at all. No need of introducing "Per-Subscription" authorization if "Namespace-auth(consume)" is anyway present so, "Namespace-auth" will always win and all subscribers can access each other's cursor state.
But you just need to grant one permission, either at the namespace level or at the subscription level if you want to have a user to be restricted.
I think this change is good. Otherwise having 2 different ways to enforce authorization for consume vs admin makes things very confusing.
Let's stick with 3 levels of authorization (namespace, topic, subscription). Whoever has "consume" access on any of these, will be able to consume and perform admin related operations on that topic/subscription.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoever has "consume" access on any of these, will be able to consume and perform admin related operations on that topic/subscription.
Alright. I will make the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@merlimat made the change.
I almost agree with deprecating the sub prefix mode and introducing per-subscription auth mode. Let me confirm:
If we grant |
right now, it's not supporting wild-card char such as
|
OK, thanks. |
@@ -109,6 +112,16 @@ public void initialize(ServiceConfiguration conf, ConfigurationCacheService conf | |||
log.debug("Policies node couldn't be found for topic : {}", topicName); | |||
} | |||
} else { | |||
// check if role is authorize to access subscription. (skip validatation if authorization list is empty) | |||
Set<String> roles = policies.get().auth_policies.subscription_auth_roles.get(subscription); | |||
if (roles != null && !roles.isEmpty() && !roles.contains(role)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if the role is superuser, access will be denied unless it is included in subscription_auth_roles, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if the role is superuser, access will be denied
No, checkout PersistentTopicsBase:: validateAdminAccessForSubscriber(), broker allows super-user/tenant to access any topic api and only validate on subscription if user is not super-user/tenant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since ServerCnx
etc calls AuthorizationService#canConsumeAsync()
directly, superuser seems to fail to subscribe.
$ grep '^superUserRoles=' conf/standalone.conf
superUserRoles=superuser
$ ./bin/pulsar-admin namespaces policies auth/standalone/test
{
"auth_policies" : {
"namespace_auth" : {
"ns-user" : [ "produce", "consume" ]
},
"destination_auth" : { },
"subscription_auth_roles" : {
"sub1" : [ "massakam" ]
}
},
...
}
$ ./bin/pulsar-client consume -s sub1 -n 10 persistent://auth/standalone/test/t1
17:35:48.140 [pulsar-io-49-3] INFO org.apache.pulsar.broker.service.ServerCnx - New connection from /127.0.0.1:43666
17:35:48.162 [pulsar-io-49-3] INFO org.apache.pulsar.broker.service.ServerCnx - [/127.0.0.1:43666] Client successfully authenticated with basic role superuser and originalPrincipal null
17:35:48.182 [pulsar-io-49-3] WARN org.apache.pulsar.broker.authorization.PulsarAuthorizationProvider - [superuser] is not authorized to subscribe on persistent://auth/standalone/test/t1-sub1
17:35:48.184 [pulsar-io-49-3] WARN org.apache.pulsar.broker.service.ServerCnx - [/127.0.0.1:43666] Client is not authorized to subscribe with role superuser
pulsar/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java
Lines 542 to 548 in 0da4e4a
if (service.isAuthorizationEnabled()) { | |
authorizationFuture = service.getAuthorizationService().canConsumeAsync(topicName, | |
originalPrincipal != null ? originalPrincipal : authRole, authenticationData, | |
subscription); | |
} else { | |
authorizationFuture = CompletableFuture.completedFuture(true); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@massakam good catch. fixed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rdhabalia Now the super user can subscribe, but consumers which are allowed access at the level of namespace, topic, or subscription fail to subscribe yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@massakam yes, that's correct. that's what we want here right?
- first broker validates subscription-permission (if it's configured) over namespace-auth so, only authorized principal can access the subscription. and that will also cover "pre-fix" sub usecase where only authorized sub can consume on specific subscription.
@merlimat can you also review this PR one more time.
if (roles != null && !roles.isEmpty() && !roles.contains(role)) { | ||
log.warn("[{}] is not authorized to subscribe on {}-{}", role, topicName, subscription); | ||
PulsarServerException ex = new PulsarServerException( | ||
String.format("%s is not authorized to access subscription %s on topic", role, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more %s
is required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
…6122) ### Motivation In #2981, we have added support to grant subscriber-permission to manage subscription based apis. However, grant-subscription-permission api requires super-user access and it creates too much dependency on system-admin when many tenants want to grant subscription permission. So, allow each tenant to manage subscription permission in order to reduce administrative efforts for super user.
…pache#6122) ### Motivation In apache#2981, we have added support to grant subscriber-permission to manage subscription based apis. However, grant-subscription-permission api requires super-user access and it creates too much dependency on system-admin when many tenants want to grant subscription permission. So, allow each tenant to manage subscription permission in order to reduce administrative efforts for super user. (cherry picked from commit 254e54b)
…6122) ### Motivation In #2981, we have added support to grant subscriber-permission to manage subscription based apis. However, grant-subscription-permission api requires super-user access and it creates too much dependency on system-admin when many tenants want to grant subscription permission. So, allow each tenant to manage subscription permission in order to reduce administrative efforts for super user. (cherry picked from commit 254e54b)
…pache#6122) ### Motivation In apache#2981, we have added support to grant subscriber-permission to manage subscription based apis. However, grant-subscription-permission api requires super-user access and it creates too much dependency on system-admin when many tenants want to grant subscription permission. So, allow each tenant to manage subscription permission in order to reduce administrative efforts for super user. (cherry picked from commit 254e54b)
…pache#6122) ### Motivation In apache#2981, we have added support to grant subscriber-permission to manage subscription based apis. However, grant-subscription-permission api requires super-user access and it creates too much dependency on system-admin when many tenants want to grant subscription permission. So, allow each tenant to manage subscription permission in order to reduce administrative efforts for super user.
Motivation
Addressing #2964
Result
Subscribers will be able to access subscribe admin-api.