feat: drive Zitadel SMTP from a platform SMTPSender#12
Conversation
Add spec.smtp to AuthStack so the running Zitadel instance's SMTP provider is configured from a platform SMTPSender (SES + Cloudflare DKIM), entirely declaratively: - 040 observes the referenced SMTPSender for host/port/username + DKIM status - 160 pulls the bare SES password from AWS SM via ESO (whole-secret, no property) - 170/175 assemble a zitadel ProviderConfig from this stack's published iam-admin PAT (push auto-enabled by spec.smtp.enabled) - 180 drives Zitadel's SMTP via a smtp.zitadel Config MR Gating avoids destructive-omit: the durable Secrets + ProviderConfig gate on stable intent (smtp.enabled + smtpSenderRef.name); only the Config MR gates on observed existence ($smtp.render). No .ready/dkim gates (would delete the live SMTP config on a chart upgrade or status flip). fromAddress is validated against the SMTPSender's verified SES domain once observed. Verified end-to-end on pat-local: Zitadel SMTP config 375049110438290685 created (Synced/Ready). 23/23 render tests pass. Implements [[tasks/authstack-smtp-sender]] Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (12)
📝 WalkthroughWalkthroughThis PR adds SMTP support to AuthStack by extending the CRD schema with ChangesSMTP Configuration Support for AuthStack
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Published Crossplane PackageThe following Crossplane package was published as part of this PR: Package: ghcr.io/hops-ops/auth-stack:pr-12-3411fe947d0157a1fbca81269abcf84112459445 |
Summary
Adds
spec.smtpto AuthStack so the running Zitadel instance's SMTP provider is configured from a platform SMTPSender (AWS SES + Cloudflare DKIM) — entirely declaratively. The operator flips one boolean and references the SMTPSender; no helm values, no secret plumbing.How it works (render pipeline)
040-observed-smtp-senderdefaultPC) for host/port/username + DKIM160-external-secret-smtp-passwordproperty)170/175ProviderConfigfrom this stack's published iam-admin PAT (push auto-enabled byspec.smtp.enabled)180-zitadel-smtp-configsmtp.zitadel.m.crossplane.ioConfig MR000/010/999fromAddress-domain validation, status surfaceMirrors the email-marketing 400/410/420 consumer pattern.
Lifecycle / destructive-omit safety
A multi-lens adversarial review surfaced (and this PR fixes) a destructive-omit hazard:
smtp.enabled && smtpSenderRef.name) — they survive a transient Observe miss instead of being deleted.$smtp.render). It deliberately does not gate on the Zitadel release.ready(a chart upgrade would delete the live SMTP config) nor ondkimVerified(DKIM signing follows the published DNS records, not SES's status reporting).status.smtp.readyreflects Config-MR composition accurately.Tests
make test— 23/23 pass, including:smtp-wires-smtpsender-consumer-chain(full chain renders with observed)smtp-durable-resources-render-without-observed(durability guard: durable resources render on intent alone; Config MR absent until observed)Verified end-to-end on
pat-localInstalled the Configuration on colima, enabled
spec.smtpon the livepat-localAuthStack:Synced/Ready=True; AuthStack XRSynced/Ready=True375049110438290685(Config MRSynced/Ready=True)zitadel-smtpSecret: 44-char SES password;zitadel-smtp-credentials: valid creds JSON (domain=auth.ops.com.ai)Prerequisite (tracked separately — not in this PR)
The
040Observe of the SMTPSender XR requires the control-plane provider-kubernetes ServiceAccount to have read+dry-run access to the*.hops.ops.com.aiXR groups. The platform doesn't grant this by default (the provider's:systemrole doesn't aggregate XR roles). It was satisfied for the e2e via a temporary colima ClusterRole; the permanent home is thehopslocal CLI provider bootstrap. Listmonk/OpenPanel consumers will need the same.No breaking changes — additive (
spec.smtpdefaults off).🤖 Generated with Claude Code
Summary by CodeRabbit
New Features