-
-
Notifications
You must be signed in to change notification settings - Fork 14
015 - entity isolation filter #80
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
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| <!-- This template is provided as an example with sections you may wish to comment on with respect to your proposal. Add or remove sections as required to best articulate the proposal. --> | ||
|
|
||
| # Entity Isolation Filter | ||
|
|
||
|
|
||
| Proposes the introduction of a "Entity Isolation Filter" to Kroxylicious's core filters. | ||
|
|
||
| This filter gives a connected client an isolated view of some or all of its entities (e.g. topics), segregating them entities of other clients that happen to use the same name. | ||
| Isolation can be applied selectively to some entity types and not others. For example, it's possible to have isolation for consumer groups, but not for topics. | ||
|
|
||
| ## Current situation | ||
|
|
||
| The project has a preview multi-tenancy filter, which is a similar idea to this one except that it applies unconditionally to all resource types. | ||
|
|
||
| ## Motivation | ||
|
|
||
| We encountered a use-case where the desire was to share topics but maintain isolated spaces for groups and transactional-ids. | ||
|
|
||
| ## Proposal | ||
|
|
||
| It is proposed to add a new filter, the Entity Isolation filter, to set of core filters shipped as part of Kroxylicious. | ||
|
|
||
| The filter will be capable of isolating the kafka entities of from one client from those of another client, even if they have to choose the same name. | ||
|
|
||
| The filter will achieve isolation using name transformation and result filtering | ||
|
|
||
| - Entity names known to the client will be transformed in some way to avoid collision with entities belonging to other clients. | ||
| - The client will have no knowledge of the entity's transformed name. | ||
| - When the client uses Kafka APIs that list entities, the result set will be filtered so that the client receives only entities that belong to them. | ||
|
|
||
| ## Configurable isolation | ||
|
|
||
| The filter will expose configuration that allows the administrator to decide which entity types are isolated and which are not. | ||
| For instance, it will be possible to configure the filter so that Kafka group-ids and transactional-ids are isolated, but | ||
| topic are not. | ||
|
|
||
| ## Pluggable Mapper | ||
|
|
||
| The filter will be delegate the job of transforming and filtering entity names to a `EntityNameMapper`. The mapper will be pluggable API | ||
| allowing alternative mapping strategies to be employed. | ||
|
|
||
| For the first release there will be a single implementation of the mapper, PrincipalEntityNameMapper, that works by prefixing the entity name with the name of a unique principal from the authenticated subject and a configurable separator | ||
| To use this mapper, the proxy must be configured with a `SubjectBuilder` so that the filter is aware of the channel's authenticated subject (from TLS or SASL). | ||
|
|
||
| On the request path, the isolated entity name will be prefixed with the principal name like so. | ||
|
|
||
| ``` | ||
| orders -> alice_orders | ||
| ``` | ||
|
|
||
| On the response path, for Kafka messages that list entities, the entities will be first filtered: | ||
|
|
||
| ``` | ||
| alice_orders -> alice_orders | ||
| bob_orders // filtered out | ||
| charlie_orders // filtered out | ||
| ``` | ||
|
|
||
| then the prefixing removed: | ||
|
|
||
| ``` | ||
| alice_orders -> orders | ||
| ``` | ||
|
|
||
| ## Security | ||
|
|
||
| The role of the filter is to prevent the entities of one client being visible to another. In other words, prevent an information leak between clients. | ||
|
|
||
| There's the possibility that a new version of the Kafka protocol could expose an entity in a new way. | ||
| There could be a new API key or API version of an existing API key that exposes an entity that ought to be isolated. | ||
|
|
||
| If an old version of this filter (one that doesn't know about the new API key/versions) is used with Kafka a client/broker that supports it, an information leak is a possibility. | ||
|
|
||
| In order to prevent this, the filter will employ a `fail-closed` methodology. | ||
|
|
||
| This means it will: | ||
| - influence the `ApiVersions` negotiations so that client/broker selects only API key and API versions that are known to the filter. | ||
| - if the filter encounters a API key or API version that is unknown to it, it will close the connection with an error. | ||
|
|
||
| ## Restrictions in scope for the first version | ||
|
|
||
| In order to narrow the scope of the problem, the first version of the Entity Isolation Filter will be restricted | ||
| to the groupId and transactionId entity types. | ||
|
|
||
| Topic isolation has some additional challenges which we want to defer to a future release. These are described in the | ||
| following issue https://github.com/kroxylicious/kroxylicious/issues/3504. | ||
|
|
||
| ### APIs | ||
|
|
||
| #### Filter Configuration | ||
|
|
||
| ```yaml | ||
|
|
||
| type: io.kroxylicious.filter.entityisolation.EntityIsolation | ||
| config: | ||
| entityTypes: | ||
| - GROUP_ID | ||
| - TRANSACTIONAL_ID | ||
| mapper: PrincipalEntityNameMapperService | ||
| mapperConfig: | ||
| separator: "-" | ||
| principalType: io.kroxylicious.proxy.authentication.User | ||
| ``` | ||
|
|
||
| ## EntityNameMapper API | ||
|
|
||
| Synchronous API that lets the filter map from downstream names to upstream names and vice versa. | ||
| It also has the responsibility to filter the upstream view, removing resources that don't belong in the view. | ||
|
|
||
| Asynchronous interface that lets the filter map from downstream names to upstream names and vice-versa. It also | ||
| has the responsibility to filter the upstream view, removing resources that don't belong in the view. | ||
|
|
||
| ```java | ||
| interface EntityNameMapper { | ||
| String map(MapperContext mapperContext, | ||
| EntityType entityType, | ||
| String downstreamEntityName) | ||
| throws EntityMapperException; | ||
|
|
||
| /** | ||
| * Maps an upstream kafka entity name to a downstream name. | ||
| * | ||
| * @param mapperContext mapper context. | ||
| * @param entityType entity type. | ||
| * @param upstreamEntityName upstream entity name. | ||
| * @return downstream entity name | ||
| * @throws EntityMapperException the mapped entity name violates one or more system constraints. | ||
| */ | ||
| String unmap(MapperContext mapperContext, | ||
| EntityType entityType, | ||
| String upstreamEntityName) | ||
| throws EntityMapperException; | ||
|
|
||
| /** | ||
| * Tests whether the given upstreams entity name belongs to this context. | ||
| * | ||
| * @param mapperContext mapper context. | ||
| * @param entityType entity type. | ||
| * @param upstreamEntityName upstream entity name. | ||
| * @return true if the mapped entity name belongs to this context, false otherwise. | ||
| */ | ||
| boolean isOwnedByContext(MapperContext mapperContext, | ||
| EntityType entityType, | ||
| String upstreamEntityName); | ||
| } | ||
| ``` | ||
|
|
||
| ```java | ||
| record MapperContext(Subject authenticatedSubject, @Nullable ClientTlsContext clientTlsContext, @Nullable ClientSaslContext clientSaslContext) { | ||
| public MapperContext { | ||
| Objects.requireNonNull(authenticatedSubject); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
| ## Affected/not affected projects | ||
|
|
||
| This proposal introduces a new filter. It does not affect any existing projects with the Kroxylicious organisation. | ||
|
|
||
| ## Compatibility | ||
|
|
||
| This proposal introduces a new filter. There are no changes to existing APIs. | ||
|
|
||
| ## Rejected alternatives | ||
|
|
||
| ### Build on the Multi Tenancy Filter | ||
|
|
||
| The project has an existing 'proof-of-concept' Multi Tenancy Filter that dates back to the project's inception. | ||
| It isolates topic names, group ids and transactional ids by prefixing with entities with the virtual cluster name. | ||
| Its implementation is sufficient to cover basic produce/consume use-cases only but nothing more. | ||
| There are several areas where the filter will fail. | ||
|
|
||
| Whilst it would have been possible to base the entity isolation work on the multi tenancy filter, | ||
| it was felt by the developers that a fresh start would give stronger foundations. | ||
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.
Uh oh!
There was an error while loading. Please reload this page.