Document the topics, the consumer account and the credentials store

The README described the cluster as it was before events existed: no declared
topics, no consumer, and no way for another namespace to reach a password
Strimzi keeps here.

The events themselves are specified by their producer, not here — this repo
owns the cluster, not the contract.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Stéphane Tailland
2026-08-31 08:36:48 +02:00
parent 9e0f908f19
commit 979c9da6c0
+60 -4
View File
@@ -41,16 +41,70 @@ kafka-kafka-bootstrap.kafka.svc.cluster.local:9093
| `kafka-admin` | `kafka-admin` | Super user — unrestricted access |
| `kafka-client` | `kafka-client` | Application user — Read/Write all topics and groups |
| `classic-models-api` | `classic-models-api` | Producer for `classic-models.*` — **Write and Describe only**, no Read |
| `classic-models-agent-approvisionnement` | same name | Consumer of `classic-models.catalog` and group prefix `approvisionnement-` — **Read and Describe only**, no Write |
`classic-models-api` publishes domain events and consumes nothing, so it is
write-only and prefix-scoped. A producer that can also read every topic is a
producer that exfiltrates every other domain's events if it is ever
compromised.
Each application account is scoped to what it actually does. The producer
publishes domain events and consumes nothing, so it is write-only: one that
could also read every topic exfiltrates every other domain's events if it is
ever compromised. The consumer is the mirror — it cannot see sales or payments,
and it cannot write, so a compromised workflow can raise no event that another
agent would then act on.
Duplicate one of these per application. `kafka-client` is the wide-open
template, useful for a smoke test and for nothing that runs unattended.
Strimzi stores credentials in Kubernetes secrets. Each secret contains two keys:
- `password` — the SCRAM password
- `sasl.jaas.config` — the ready-to-use JAAS config string
### Topics
Declared in `kafka-topics.yaml`, never auto-created — an application account has
no `Create` ACL, so a producer would simply be denied, and an auto-created topic
takes broker defaults nobody chose.
| Topic | Partitions | Replicas | Retention |
|---|---|---|---|
| `classic-models.catalog` | 3 | 1 | 7 days |
| `classic-models.sales` | 3 | 1 | 7 days |
| `classic-models.payments` | 3 | 1 | 7 days |
Partition count is the ceiling on consumer parallelism and **cannot be lowered
later**, so it is set for the traffic expected rather than the traffic today.
The events these carry are specified by their producer, in
`classic-models-api/docs/DOMAIN_EVENTS.md`. This repo owns the cluster, not the
contract.
### Getting credentials into another namespace
A Secret cannot be mounted across namespaces, and Strimzi writes a KafkaUser's
password into **this** one. `credentials-access.yaml` therefore declares a
`ClusterSecretStore` named `kafka-credentials` (External Secrets, `kubernetes`
provider) backed by a ServiceAccount that can read Secrets here and nowhere
else. An application namespace then pulls its own password and the cluster CA
with an `ExternalSecret`:
```yaml
secretStoreRef:
kind: ClusterSecretStore
name: kafka-credentials
data:
- secretKey: password
remoteRef: {key: <kafkauser-name>, property: password}
- secretKey: ca.crt
remoteRef: {key: kafka-cluster-ca-cert, property: ca.crt}
```
The password stays generated and rotatable by Strimzi; the copy follows. The
alternative — copying it by hand — drifts the first time the user is
regenerated.
**The trade, stated:** any namespace allowed to create an `ExternalSecret`
against this store can pull **any** Kafka account's credentials. Acceptable with
one operator; on a shared cluster, narrow the Role with `resourceNames` and run
one store per application.
### TLS
Strimzi generates and manages its own internal CA. The cluster CA certificate is stored in:
@@ -125,6 +179,8 @@ The target performs the following steps:
3. Waits for the Strimzi CRDs to be fully established
4. Applies `kafka.yaml` (KafkaNodePool + Kafka CRs) and waits for `Ready`
5. Applies `kafka-users.yaml` (KafkaUser CRs) and waits for `Ready`
6. Applies `kafka-topics.yaml` (the declared topics) and `credentials-access.yaml`
(the cross-namespace credentials store)
Expected duration: **4–6 minutes** on a single-node k3s cluster.