Skip to content

Commit 5343bd7

Browse files
doc: Document OPA rego rules
1 parent ff41ee2 commit 5343bd7

6 files changed

Lines changed: 138 additions & 43 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
apiVersion: zookeeper.stackable.tech/v1alpha1
3+
kind: ZookeeperCluster
4+
metadata:
5+
name: simple-zk
6+
spec:
7+
image:
8+
productVersion: 3.9.5
9+
servers:
10+
roleGroups:
11+
default:
12+
replicas: 1
13+
---
14+
apiVersion: zookeeper.stackable.tech/v1alpha1
15+
kind: ZookeeperZnode
16+
metadata:
17+
name: simple-kafka-znode
18+
spec:
19+
clusterRef:
20+
name: simple-zk
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
apiVersion: opa.stackable.tech/v1alpha1
3+
kind: OpaCluster
4+
metadata:
5+
name: simple-opa
6+
spec:
7+
image:
8+
productVersion: 1.16.2
9+
servers:
10+
config:
11+
logging:
12+
containers:
13+
opa:
14+
loggers:
15+
decision:
16+
level: INFO
17+
roleGroups:
18+
default: {}
19+
---
20+
apiVersion: v1
21+
kind: ConfigMap
22+
metadata:
23+
name: kafka-rego-rules
24+
labels:
25+
opa.stackable.tech/bundle: "true"
26+
data:
27+
kafka.rego: |
28+
package kafka
29+
30+
is_internal_request if input.requestContext.listenerName == "INTERNAL"
31+
is_external_request if not is_internal_request
32+
33+
# FQDNs of the brokers as regular expressions
34+
brokers_fqdn := [
35+
`local`, # cluster domain
36+
`cluster`, # cluster domain
37+
`svc`,
38+
`default`, # namespace
39+
`simple-kafka-broker-default-headless`, # Pod subdomain
40+
`simple-kafka-broker-default-[0-9]+`, # Pod name
41+
]
42+
43+
domain_components = [concat("", [`DC=`, dc]) | some dc in brokers_fqdn]
44+
common_name = `CN=generated certificate for pod`
45+
subject_dn_fields = array.concat(domain_components, [common_name])
46+
brokers_subject_dn_pattern := concat("", ["^", concat(",", subject_dn_fields), "$"])
47+
48+
default allow := false
49+
50+
allow if {
51+
is_internal_request
52+
53+
regex.match(
54+
brokers_subject_dn_pattern,
55+
input.requestContext.principal.name,
56+
)
57+
}
58+
59+
allow if {
60+
is_external_request
61+
62+
# TODO Add your own rules
63+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
apiVersion: kafka.stackable.tech/v1alpha1
3+
kind: KafkaCluster
4+
metadata:
5+
name: simple-kafka
6+
spec:
7+
image:
8+
productVersion: 3.9.2
9+
clusterConfig:
10+
authorization:
11+
opa:
12+
configMapName: simple-opa
13+
package: kafka
14+
zookeeperConfigMapName: simple-kafka-znode
15+
brokers:
16+
roleGroups:
17+
default:
18+
replicas: 1
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
apiVersion: kafka.stackable.tech/v1alpha1
3+
kind: KafkaCluster
4+
metadata:
5+
name: simple-kafka
6+
spec:
7+
image:
8+
productVersion: 3.9.2
9+
clusterConfig:
10+
authorization:
11+
opa:
12+
configMapName: simple-opa
13+
package: kafka
14+
zookeeperConfigMapName: simple-kafka-znode
15+
brokers:
16+
configOverrides:
17+
broker.properties:
18+
opa.authorizer.cache.initial.capacity: "100"
19+
opa.authorizer.cache.maximum.size: "100"
20+
opa.authorizer.cache.expire.after.seconds: "10"
21+
roleGroups:
22+
default:
23+
replicas: 1

docs/modules/kafka/pages/usage-guide/security.adoc

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -177,53 +177,24 @@ The package is optional and defaults to the `metadata.name` field:
177177

178178
[source,yaml]
179179
----
180-
---
181-
apiVersion: kafka.stackable.tech/v1alpha1
182-
kind: KafkaCluster
183-
metadata:
184-
name: simple-kafka
185-
spec:
186-
image:
187-
productVersion: 3.9.2
188-
clusterConfig:
189-
authorization:
190-
opa:
191-
configMapName: simple-opa
192-
package: kafka
193-
zookeeperConfigMapName: simple-kafka-znode
194-
brokers:
195-
roleGroups:
196-
default:
197-
replicas: 1
180+
include::example$security/03a-authorization-kafkacluster.yaml[]
198181
----
199182

200183
You can change some opa cache properties by overriding:
201184

202185
[source,yaml]
203186
----
204-
---
205-
apiVersion: kafka.stackable.tech/v1alpha1
206-
kind: KafkaCluster
207-
metadata:
208-
name: simple-kafka
209-
spec:
210-
image:
211-
productVersion: 3.9.2
212-
clusterConfig:
213-
authorization:
214-
opa:
215-
configMapName: simple-opa
216-
package: kafka
217-
zookeeperConfigMapName: simple-kafka-znode
218-
brokers:
219-
configOverrides:
220-
broker.properties:
221-
opa.authorizer.cache.initial.capacity: "100"
222-
opa.authorizer.cache.maximum.size: "100"
223-
opa.authorizer.cache.expire.after.seconds: "10"
224-
roleGroups:
225-
default:
226-
replicas: 1
187+
include::example$security/03b-authorization-kafkacluster-custom-properties.yaml[]
227188
----
228189

229190
A full list of settings and their respective defaults can be found https://github.com/anderseknert/opa-kafka-plugin[here].
191+
192+
The OPA Rego rules can authorize both external and internal communication.
193+
For internal communication, the principal name is the subject DN of the broker's certificate.
194+
The subject DN contains the FQDN of the pod and a generic common name, e.g. `DC=local,DC=cluster,DC=svc,DC=default,DC=simple-kafka-broker-default-headless,DC=simple-kafka-broker-default-0,CN=generated certificate for pod`.
195+
An OpaCluster and the Rego rules that verify the subject DNs could look as follows:
196+
197+
[source,yaml]
198+
----
199+
include::example$security/02-authorization-opa.yaml[]
200+
----

tests/templates/kuttl/opa/20_opa.yaml.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ data:
99
kafka.rego: |
1010
package authz
1111

12-
# FQDNs of the brokers as regular expressions
12+
# FQDN of the brokers as regular expressions
1313
brokers_fqdn := [
1414
`local`,
1515
`cluster`,
@@ -22,7 +22,7 @@ data:
2222
domain_components = [concat("", [`DC=`, dc]) | some dc in brokers_fqdn]
2323
common_name = `CN=generated certificate for pod`
2424
subject_dn_fields = array.concat(domain_components, [common_name])
25-
brokers_subject_dn_pattern := concat(",", subject_dn_fields)
25+
brokers_subject_dn_pattern := concat("", ["^", concat(",", subject_dn_fields), "$"])
2626

2727
default allow := false
2828

0 commit comments

Comments
 (0)