-
Notifications
You must be signed in to change notification settings - Fork 14.2k
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
KAFKA-18813: ConsumerGroupHeartbeat API and ConsumerGroupDescribe API must check topic describe #18989
base: trunk
Are you sure you want to change the base?
Conversation
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.
@dongnuo123 Thanks for the patch. I left some high level comments.
core/src/main/scala/kafka/coordinator/group/GroupCoordinatorAdapter.scala
Outdated
Show resolved
Hide resolved
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupMetadataManager.java
Outdated
Show resolved
Hide resolved
…onsumer-group-heartbeat-and-describe-feb20
...tor-common/src/main/java/org/apache/kafka/coordinator/common/runtime/CoordinatorRuntime.java
Outdated
Show resolved
Hide resolved
This reverts commit e80adf4.
…onsumer-group-heartbeat-and-describe-feb20
@dongnuo123 Thanks for the update. The patch looks pretty good to me. There are some test failures which are related. Could you please check them with @lianetm? |
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.
@dongnuo123 thanks for this patch.
@@ -2529,9 +2529,24 @@ class KafkaApis(val requestChannel: RequestChannel, | |||
requestHelper.sendMaybeThrottle(request, consumerGroupHeartbeatRequest.getErrorResponse(Errors.GROUP_AUTHORIZATION_FAILED.exception)) | |||
CompletableFuture.completedFuture[Unit](()) | |||
} else { | |||
if (consumerGroupHeartbeatRequest.data.subscribedTopicNames != null && |
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.
Does handleShareGroupHeartbeat
have similar issue?
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.
Yes but it will be treated separately. This is a critical blocker for 4.0 for the new consumer protocol whereas it is not for share group.
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.
Got it. open https://issues.apache.org/jira/browse/KAFKA-18851 to log 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.
I think that there is already one open but I cannot find it from my phone.
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.
There it is: https://issues.apache.org/jira/browse/KAFKA-18817
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.
thanks! will close KAFKA-18851 as duplicate
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.
just to complete the story, we need this for KS too, they also have their jira already https://issues.apache.org/jira/browse/KAFKA-18819
} | ||
} | ||
}) | ||
val authorizedTopics = authHelper.filterByAuthorized(request.context, DESCRIBE, TOPIC, |
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.
It seems handleDescribeGroupsRequest
does not require topic authorization. Does it mean users need to update the ACLs when migrating to use AsyncConsumer?
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.
That’s right. The thing is that we cannot apply it on there because the broker is not aware of the topic partitions. It just sees bytes by design.
We could consider parsing the bytes to check the partitions too but as it has been like this since the beginning of the classic protocol. We would need a KIP to discuss it for sure. Personally, I would not change it.
Regarding your second question, the Consumer is not impacted by this as both implementations require topic describe but in different ways. Only the admin client will require extra permissions if not given yet.
@dongnuo123 Could you add a sentence about it in the doc? We could mention this in the ops.html, consumer group section.
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupMetadataManager.java
Show resolved
Hide resolved
group-coordinator/src/main/java/org/apache/kafka/coordinator/group/GroupMetadataManager.java
Outdated
Show resolved
Hide resolved
@@ -645,6 +645,7 @@ class BrokerServer( | |||
.withGroupCoordinatorMetrics(new GroupCoordinatorMetrics(KafkaYammerMetrics.defaultRegistry, metrics)) | |||
.withGroupConfigManager(groupConfigManager) | |||
.withPersister(persister) | |||
.withAuthorizer(authorizer.toJava) |
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.
Did we consider splitting the processing of heartbeat request in the group coordinator so that topic authorization can continue to be in KafkaApis? Moving some of the authorization out of KafkaApis and into the group coordinator doesn't seem ideal. If we could instead ask the coordinator first for list of topics to filter out for regex and then invoke GroupCoordinatorService.consumerGroupHeartbeat() passing the filtered topics as well, we could avoid splitting out authorization between KafkaApis and group coordinator. And it would avoid knowledge of logIfDenied
etc. mentioned in https://github.com/apache/kafka/pull/18989/files#r1966700208 outside of KafkaApis.
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 we could instead ask the coordinator first for list of topics to filter out for regex
With the current implementation, the challenge with this is that the resolution and filtering of the regex are done in an async fashion. consumerGroupHeartbeat
will return before we finish resolving the list of topics to filter which is done in a separate thread in the coordinator.
But it does make sense that it's a bit strange carrying the authorizer to the coordinator. I think we can work on it as a followup improvement.
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.
Agree, do we have a jira for it @dongnuo123 ?
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.
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.
@rajinisivaram any concerns with this as follow-up? It will be handled to improve right after this and included in 4.1 as described in KAFKA-18857
I'm taking a closer look at the changes, but regarding the test failures, they show the consumer getting more than one TopicAuth after the ACLs are added (before this change it expected at most 1 more TopicAuth here). I wonder if that expectation is too strict now, that we send the error via HBs continuously on the interval, even if it fails with error (vs before we would only get the auth error from the Metadata path). The consumer should recover, but I don't think we can guarantee that it will only get 1 TopicAuth after the ACLs are added. |
if (authorizedTopics.size < consumerGroupHeartbeatRequest.data.subscribedTopicNames.size) { | ||
val responseData = new ConsumerGroupHeartbeatResponseData() | ||
.setErrorCode(Errors.TOPIC_AUTHORIZATION_FAILED.code) | ||
.setErrorMessage("The client is not authorized to describe the provided subscribed topics.") |
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.
in this case we had a request with a list of topics, and we're already sending a response with errorCode TOPIC_AUTH_FAILED, so I wonder if adding this message is bringing much value?
Also, it's not consistent with how other APIs handle the same situation. Ex. on the metadata path, we get a request with topic list and if auth fails the response will only include the error code, no custom message. This inconsistency is relevant because it will translate into the consumer btw (whatever topic auth message we get from metadata or HB will bubble up to the consumer.poll). We can always make it consistent on the client side of course, but seems to me that making it consistent here makes more sense given that the message seems redundant. Thoughts?
@dongnuo123 could you please sync trunk for #18770? |
new ConsumerGroupDescribeResponseData.DescribedGroup() | ||
.setGroupId(group.groupId) | ||
.setErrorCode(Errors.TOPIC_AUTHORIZATION_FAILED.code) | ||
.setErrorMessage("The group has described topic(s) that the client is not authorized to describe.") |
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.
Should this align #18989 (comment) ?
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.
this one I find it valuable, not the same case as my other comment. In this case we don't have topics in the request, so getting a topic_auth in response may not be clear enough, and this generic msg may be helpful.
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.
Got it, thanks.
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.
Thanks for the patch
I have some comments. PTAL
…onsumer-group-heartbeat-and-describe-feb20
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.
Thanks for the updates @dongnuo123 ! Some minor comments
...p-coordinator/src/test/java/org/apache/kafka/coordinator/group/GroupMetadataManagerTest.java
Show resolved
Hide resolved
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.
Thanks for the updates @dongnuo123, LGTM.
Just to recap, we have KAFKA-18857 as follow-up, and related jiras to address this same gap for share (KAFKA-18817) and streams (KAFKA-18819) groups (not 4.0 blockers)
I will wait for the build, and confirmation on this comment https://github.com/apache/kafka/pull/18989/files#r1969914513 in case @rajinisivaram or @chia7712 have any other comments.
Thanks!
.setMemberId(memberId2) | ||
.setMemberEpoch(10) | ||
.setRebalanceTimeoutMs(5000) | ||
.setSubscribedTopicRegex("foo*|bar*") |
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.
just for the record, this makes me notice that we require a HB with regex in this case (and makes sense, because IIRC we only refresh it if it changes or if there is a new topic metadata image, which is not the case here).
I remember there was already a jira/intention to consider time-based refresh, which I expect would help improve the experience in this case. I will find the jira (or file) and update here just for reference.
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.
overall LGTM!
try { | ||
consumeRecords(consumer, numRecords, startingOffset, topic) | ||
} catch { | ||
case _: TopicAuthorizationException => consumeRecordsIgnoreAuthorizationException(consumer, numRecords, startingOffset, topic) |
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.
Is this recursive call necessary? TestUtils.waitUntilTrue already contains a loop, so perhaps we can streamline the check as follows:
TestUtils.waitUntilTrue(() => {
try {
consumeRecords(consumer)
true
} catch {
case _: TopicAuthorizationException => false
}
}, "Consumer didn't manage to consume the records within timeout.")
@@ -2592,6 +2607,34 @@ class KafkaApis(val requestChannel: RequestChannel, | |||
response.groups.addAll(results) | |||
} | |||
|
|||
// Clients are not allowed to see topics that are not authorized for Describe. | |||
val topicsToCheck = response.groups.stream() |
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 small optimization - could we do this check only if authorizer
is defined?
This patch filters out the topic describe unauthorized topics from the ConsumerGroupHeartbeat and ConsumerGroupDescribe response.
In ConsumerGroupHeartbeat,
subscribedTopicNames
set, we directly check the authz inKafkaApis
and return a topic auth failure in the response if any of the topics is denied.In ConsumerGroupDescribe, we check the authz of the coordinator response. If any of the topic in the group is denied, we remove the described info and add a topic auth failure to the described group. (similar to the group auth failure)
Reviewers: David Jacot [email protected], Lianet Magrans [email protected], Rajini Sivaram [email protected], Chia-Ping Tsai [email protected], TaiJuWu [email protected], TengYao Chi [email protected]