|
| 1 | +<!-- 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. --> |
| 2 | + |
| 3 | +# Authorizer Filter |
| 4 | + |
| 5 | +The Authorizer filter gives the ability to add authorisation checks into a Kafka system which will be enforced by the proxy. |
| 6 | + |
| 7 | +## Current situation |
| 8 | + |
| 9 | +It is possible for a filter to implement its own business rules, enforcing authorization is some custom manner. |
| 10 | + |
| 11 | +## Motivation |
| 12 | + |
| 13 | +We are identifying use-cases where making authorization decisions at the proxy is desireable. Examples include where one wishes to restrict a virtual cluster to a sub-set of the resources (say topics) of the cluster. |
| 14 | + |
| 15 | +## Proposal |
| 16 | + |
| 17 | +The Authorizer filter gives the ability to layer authorisation checks into a Kafka system which with those authorization checks being enforced by the filter. These authorization checks are in addition to anythat may be imposed by the Kafka Cluster itself. This means that for an action to be allowed both the proxy’s authorizer and the Kafka broker’s authorizer will need to reach an ALLOW decision. |
| 18 | + |
| 19 | +The Authorizer filter allows for authorization checks to be made in the following form: |
| 20 | + |
| 21 | +Principal P is [Allowed/Denied] Operation O On Resource R. |
| 22 | + |
| 23 | +where: |
| 24 | + |
| 25 | +* Principal is the authenticated user. |
| 26 | +* Operation is an action such as, but not limited to, Read, Write, Create, Delete. |
| 27 | +* Resource identifies one or more resources, such as, but not limited to Topic, Group, Cluster, TransactionalId. |
| 28 | + |
| 29 | +Unlike Apache Kafka authorizer system, the `from host` predicate is omitted. This is done to adhere to modern security principle that there are no privileged network locations. |
| 30 | + |
| 31 | +### Request authorization |
| 32 | + |
| 33 | +The Authorizer filter will intercept all request messages that perform an action on a resource, and all response messages that list resources. |
| 34 | + |
| 35 | +On receipt of a request message from the downstream, the filter will make an asynchronous call to the authorizer for the resource(s) involved in the request. If the authorization result for all resources is allowed, the filter will forward the request to the broker. If the authorization result is denied for any resource in the request, the filter will produce a short circuit error response denying the request using the appropriate authorization failed error code. The authorizer filter must not forward requests that fail authorization. |
| 36 | + |
| 37 | +### Response resource filtering |
| 38 | + |
| 39 | +On receipt of a response message from the upstream, the Authorizing filter will filter the resources so that the downstream receives only resources that they are authorized to see. |
| 40 | + |
| 41 | +The Authorizer filter will have a pluggable API that allows different Authorizer implementations to be plugged in. This proposal will deliver a simple implementation of the API that allows authorization rules to be expressed in a separate file. Future work may |
| 42 | +deliver alternative implementations that, say, delegate authorization decisions to externals systems (such as OPA), or implement other |
| 43 | +authorizations schemes (such as RBAC). |
| 44 | + |
| 45 | +### Operation/Resource Matrix |
| 46 | + |
| 47 | +For the initial version, the system will be capable of making authorization decisions for topic operations and cluster connections only. |
| 48 | +Future versions may support authorization decisions for other Kafka resources types (e.g. consumer group and transactional id). |
| 49 | +The Authorizer will be designed to be open for extension so that it may be used to make authorization decisions about other entities (beyond those defined by Apache Kafka). |
| 50 | + |
| 51 | +The table below sets out the authorization checks and filters will be implemented. |
| 52 | + |
| 53 | +| Operation | Resource Type | Kafka Message | |
| 54 | +|-----------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 55 | +| READ | Topic | Fetch, ShareFetch, ShareGroupFetch, ShareAcknowledge, AlterShareGroupOffsets, DeleteShareGroupOffsets, OffsetCommit, TxnOffsetCommit, OffsetDelete | |
| 56 | +| WRITE | Topic | Produce, InitProducerId, AddPartitionsToTxn | |
| 57 | +| CREATE | Topic | CreateTopics | |
| 58 | +| DELETE | Topic | DeleteTopics | |
| 59 | +| ALTER | Topic | AlterConfigs, IncrementalAlterConfigs, CreatePartitions | |
| 60 | +| DESCRIBE | Topic | ListOffset, OffsetFetch, OffsetFetchForLeaderEpoch DescribeProducers, ConsumerGroupHeartbeat, ConsumerGroupDescribe, ShareGroupHeartbeat, ShareGroupDescribe, MetaData, DescribeTopicPartitions, ConsumerGroupDescribe | |
| 61 | +| CONNECT | Cluster | SaslAuthenticate | |
| 62 | + |
| 63 | +In general, the filter will make access decisions in the same manner as Kafka itself. This means it will apply the same authorizer checks that Kafka enforces itself and generate error responses in the same way. It will |
| 64 | +From the client's perspective, it will be impossible for it to distinguish between the proxy and kafka cluster itself. |
| 65 | +It will also use the same implied operation semantics as implemented by Kafka itself, such as where `ALTER` implies `DESCRIBE`, as described by |
| 66 | +`org.apache.kafka.common.acl.AclOperation`. |
| 67 | + |
| 68 | +There is one deviation. The filter will implement a `CONNECT` authorization check on the `CLUSTER` early, as the connection is made, once the principal is known. This allows the Authorizer filter to be used to gate access to virtual clusters. |
| 69 | +* In the case of SASL, this will be performed on receipt of the Sasl Authentication Response. If the authorization check fails, the authentication will fail with an authorization failure and the connection closed. |
| 70 | +* In case of TLS client-auth, this will be performed on receipt of the first request message. If the authorization check fails, a short circuit response will be sent containing an authorization failure and the connection closed. This feature won’t be part of the initial scope. |
| 71 | + |
| 72 | +The filter will support messages that express topic identity using topic ids (i.e. those building on [KIP-516](https://cwiki.apache.org/confluence/display/KAFKA/KIP-516%3A+Topic+Identifiers)). It will resolve the topic id into a topic name before making the authorization check. |
| 73 | + |
| 74 | +### File based Authorizer implementation |
| 75 | + |
| 76 | +The initial scope will include an Authorizer implementation that is backed by authorization rules expressed in a separate file. This file will associate principals with ACL rules capable of expressing an allow-list of resources. |
| 77 | +The initial version will be restricted to expressing allow lists of topics, but future version will extend this to allow for rules to be express about other resource types. |
| 78 | + |
| 79 | +### APIs |
| 80 | + |
| 81 | +#### Authorizer Filter |
| 82 | + |
| 83 | +Filter Configuration: |
| 84 | + |
| 85 | +```yaml |
| 86 | +type: AuthorizerFilter |
| 87 | +config: |
| 88 | + authorizer: FileBasedAllowListAuthorizer |
| 89 | + authorizerConfig: |
| 90 | + rulesFile: /path/to/allow-list.yaml |
| 91 | +``` |
| 92 | +
|
| 93 | +Java APIs: |
| 94 | +
|
| 95 | +```java |
| 96 | +// Inspired by org.apache.kafka.server.authorizer.Authorizer, except is asynchronous in nature. |
| 97 | +interface Authorizer { |
| 98 | + CompletionStage<List<AuthenticationResult>> authorize(AuthorizableRequestContext context, List<Action> actions); |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +```java |
| 103 | +// Inspired by org.apache.kafka.server.authorizer.AuthorizableRequestContext |
| 104 | +interface AuthorizableRequestContext { |
| 105 | + String principal(); |
| 106 | + // scope for methods such as requestType(), requestVersion() etc to be added in future. |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +```java |
| 111 | +// Inspired by org.apache.kafka.server.authorizer.Action |
| 112 | +record Action( |
| 113 | + AclOperation aclOperation, |
| 114 | + ResourcePattern resourcePattern) { |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | +```java |
| 119 | +// The following types are inspire by the Kafka classes of the same name and have the same role. However, interfaces are used |
| 120 | +// rather than enums to allow for extensibility (using pattern suggested by https://www.baeldung.com/java-extending-enums) |
| 121 | +interface AclOperation { |
| 122 | + String operationName(); |
| 123 | +} |
| 124 | + |
| 125 | +enum CoreAclOperation implements AclOperation { |
| 126 | + CREATE("Create"), |
| 127 | + DELETE("Delete"), |
| 128 | + READ("Read")/* ,... */ |
| 129 | +} |
| 130 | + |
| 131 | +interface ResourceType { |
| 132 | + String resourceType(); |
| 133 | +} |
| 134 | + |
| 135 | + |
| 136 | +enum CoreResourceType implements ResourceType { |
| 137 | + TOPIC("Topic"), |
| 138 | + CLUSTER("Cluster"); |
| 139 | +} |
| 140 | + |
| 141 | +interface PatternType { |
| 142 | + boolean matches(String resourceName); |
| 143 | +} |
| 144 | + |
| 145 | + |
| 146 | +enum CorePatternType { |
| 147 | + LITERAL() { |
| 148 | + @Override |
| 149 | + boolean matches(String pattern, String resourceName) { |
| 150 | + return pattern.equals(resourceName); |
| 151 | + } |
| 152 | + }, |
| 153 | + MATCH() { /* ... */ }, |
| 154 | + PREFIXED { /* ... */ } |
| 155 | +} |
| 156 | + |
| 157 | +record ResourceNamePattern(PatternType patternType, String pattern) { |
| 158 | + boolean matches(String resourceName) { |
| 159 | + return patternType.matches(pattern, resourceName); |
| 160 | + } |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +#### Rules File |
| 165 | + |
| 166 | +The rules file expresses a mapping between principals (user type only with exact match) and an allow-list of resources. |
| 167 | + |
| 168 | +For the initial scope, only resource rules of type TOPIC are supported. In order to allow for future extension, the user’s configuration set the version property to 1. This will allow future versions of the filter to introduce support for other resource types without changing the meaning of existing configurations. |
| 169 | + |
| 170 | +For the `CLUSTER` `CONNECT` authorization check, this will be implemented implicitly. The check will return `ALLOW` if there is at least one resource rule for the principal. If there are no resource rules for the principal, the authorizer will return `DENY`. |
| 171 | + |
| 172 | +```yaml |
| 173 | +version: 1 # Mandatory must be 1. Version 1 is defined as supporting resourceType TOPIC only. |
| 174 | +definitions: |
| 175 | +- principals: [User:bob, User:grace] # Only User: prefixed principals will be supported. |
| 176 | + resourceRules: |
| 177 | + - resourceType: TOPIC # Only the topic resourceType is permitted |
| 178 | + operations: [READ] |
| 179 | + patternType: LITERAL |
| 180 | + resourceName: foo |
| 181 | + - type: TOPIC |
| 182 | + operations: [ALL] |
| 183 | + patternType: PREFIXED |
| 184 | + resourceName: bar |
| 185 | + - type: TOPIC |
| 186 | + operations: [ALL] |
| 187 | + patternType: MATCH |
| 188 | + resourceName: baz* |
| 189 | +``` |
| 190 | +
|
| 191 | +## Affected/not affected projects |
| 192 | +
|
| 193 | +The kroxylicious repo. |
| 194 | +
|
| 195 | +## Compatibility |
| 196 | +
|
| 197 | +No issues - this proposal introduces a new filter./ |
| 198 | +
|
| 199 | +## Rejected alternatives |
| 200 | +
|
| 201 | +### Reuse of the Kafka ACL interfaces/enumerations |
| 202 | +
|
| 203 | +The Kafka Client library includes interfaces and enumeration such as `org.apache.kafka.server.authorizer.Action` |
| 204 | +and `org.apache.kafka.common.acl.AclOperation`. It would be technically possible to base the Authorizer's interfaces |
| 205 | +on these types. This would have the advantage that it would help ensure that the ACL model of the Proxy followed |
| 206 | +that of Kafka, but it would have also meant restricting the Authorizer to making access control decisions for the same |
| 207 | +entities as Kafka does. We want to leave open the possibilty to make access decisions about other resource types, beyond |
| 208 | +those considered by Kafka today (such as record-level ACLs). |
| 209 | + |
0 commit comments