New to Kestra?
Use blueprints to kickstart your first workflows.
Audit a domain's SPF, DKIM, and DMARC records from live DNS, report missing or weak configuration, and alert Slack until every check passes.
Diagram unavailable
We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.
Spoofed mail from your own domain is the cheapest attack in the book, and the defenses — SPF, DKIM, DMARC — rot silently: a vendor change breaks the include chain, a selector rotates out, DMARC sits on p=none forever because nobody scheduled the follow-up. This blueprint reads the records straight from live DNS on a cadence, extracts the DMARC policy, probes every selector your senders use, and reports a single verdict. Missing records are findings, not crashes, so the alert tells you exactly which record to add; enable strict mode and a monitoring-only p=none starts failing too.
audit_records (io.kestra.plugin.scripts.shell.Commands on the Docker task runner) installs dig in a throwaway alpine:3.20 container and performs three lookups: SPF TXT on the apex, DMARC TXT at _dmarc.<domain>, and one TXT per selector in dkim_selectors at <selector>._domainkey.<domain>. Quoted chunked TXT records are concatenated before matching (long SPF strings arrive split), the p= policy is cut from the DMARC record, and the verdict — spf_found, dmarc_found, dmarc_policy, dkim_found, dkim_checked, overall_ok — is published through the ::{"outputs": ...}:: protocol. Absent records exit 0 with overall_ok: false; only a broken check (no dig, no network) exits non-zero.check_verdict (io.kestra.plugin.core.flow.If) branches on overall_ok. False: alert_auth_gaps posts each individual gap and the policy in force to Slack. True: log_pass records the configuration so the history shows when policy or selectors changed.errors block alerts Slack when the audit itself fails — a crashed audit must never read as a passing domain.Schedule (shipped disabled) plus a Webhook (email-auth-audit) to confirm record changes right after they are made.p=none into a failure, so DMARC enforcement actually completes.auth_summary JSON output for dashboards or a compliance gate.dig in a terminal shows today's records; Kestra shows the policy over time. The flow adds the cadence, the branch that separates enforcement from monitoring-only, the alert that names the gap, the webhook to verify a change the moment it lands, and an execution history where "when did DMARC go to p=reject" has an answer. It is the same pattern as the DNS propagation blueprint: DNS truth, made operational.
google; Microsoft 365: selector1, selector2; add yours to the list).SLACK_WEBHOOK_URL: Slack incoming webhook URL for gap and verifier-failure alerts.domain and list your real dkim_selectors.auth_summary — compare it with dig TXT output by hand.monthly_audit, then flip require_strict_dmarc to true when you are ready to fail on p=none.If on dmarc_policy == "none" that opens a ticket to finish enforcement — the classic stalled-DMARC pattern.dns-propagation-verifier when you change email-auth records: verify propagation first, audit the verdict second.auth_summary into a dashboard alongside the other domain-health checks.