New to Kestra?
Use blueprints to kickstart your first workflows.
Detect Kafka topic config drift against a policy, alert Slack, remediate with TopicUpdate behind dry-run gates, and re-describe to verify.
Kafka topic configs drift. Someone sets retention.ms=-1 on a topic to debug an incident and never puts it back, so the disk fills months later. A compacted topic is recreated with the default cleanup.policy=delete and silently starts losing keys. A topic the platform team expects is never created. None of this throws an error. It shows up as an outage or as lost data.
This blueprint describes every topic in a declared policy with the Kafka AdminClient and compares only the keys you care about. It alerts Slack on any drifted key or missing topic, and can set the drifted keys back with TopicUpdate, behind two gates. After a change it describes the topics again, so the run only reports success when the broker really holds the policy value.
This blueprint was created by zkasuran.
list_topics (io.kestra.plugin.kafka.TopicList) lists the topics on the cluster. present splits the policy into topics that exist and topics that are missing, so a missing topic is reported instead of failing the describe.describe_topics (io.kestra.plugin.core.flow.Loop over io.kestra.plugin.kafka.TopicDescribe) reads the live configs of every policy topic, read-only.drift lists every policy key whose live value differs, with the live and the desired value. Keys not in the policy are never looked at.summary logs the result every run.route (io.kestra.plugin.core.flow.If):alert posts to Slack, saying whether a change will be applied.remediate_gate runs only when auto_remediate is true and dry_run is false.remediate sends one TopicUpdate per drifted topic with only its drifted keys.verify describes those topics again, and verify_result fails the run if any key still differs.errors alerts Slack when the flow itself fails, for example on an unreachable broker. A failed check must not read as a compliant cluster.auto_remediate: false, dry_run: true. The hourly trigger is shipped disabled and always runs in safe mode.TopicDescribe and TopicUpdate with gates around them.kafka-configs.sh --describe shows a config at one moment. Kestra runs the comparison on a schedule, keeps the policy next to the flow, turns drift into a Slack alert, applies TopicUpdate only behind auto_remediate and dry_run, and keeps an execution history showing when each key drifted and when it was put back.
On Kestra 2.0.5 OSS against Apache Kafka 3.9.1 (KRaft, one broker), with a local HTTP sink standing in for Slack.
| Run | Inputs | Result |
|---|---|---|
| 1 | defaults | 2 drifted keys found: payments retention.ms=-1 (policy 30 days) and customers-compacted cleanup.policy=delete (policy compact). invoices reported missing. Slack alert sent, nothing changed |
| 2 | auto_remediate: true, dry_run: true |
Same report, the alert says no change was applied. kafka-configs.sh still shows retention.ms=-1 |
| 3 | auto_remediate: true, dry_run: false |
2 TopicUpdate calls, re-describe confirms both keys. kafka-configs.sh shows retention.ms=2592000000 and cleanup.policy=compact |
| 4 | policy without invoices |
Compliant, no alert |
| 5 | unreachable broker | AdminClient timeout, the errors alert is sent |
AlterConfigs if remediation will be used.docker run -d --name kafka -p 9092:9092 apache/kafka:3.9.1. Then create a few topics with kafka-topics.sh and change a config with kafka-configs.sh --alter to see the drift.SLACK_WEBHOOK_URL: Slack incoming webhook used by alert and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.| Input | Default | Purpose |
|---|---|---|
bootstrap_servers |
localhost:9092 |
Brokers |
policy |
5 example topics | Desired configs per topic |
auto_remediate |
false |
Allow TopicUpdate |
dry_run |
true |
Must be false for a change to apply |
For a secured cluster, add security.protocol, sasl.mechanism and sasl.jaas.config to each task's properties, read from secrets.
SLACK_WEBHOOK_URL secret.bootstrap_servers, and replace policy with your topics and keys.auto_remediate: true and dry_run: false to put the keys back.hourly trigger, which always runs in safe mode.Pause.TopicDescribe's other outputs.