fix(mail): rotate the Sweego credentials + correct the §5 guidance #385
Inga granskare
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra!385
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "fix/sweego-credentials-rotated"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Rotates the Sweego API key and SMTP credentials, and corrects the §5 guidance that sent this
investigation the wrong way.
Already applied to production (Forgejo, portal and Alertmanager restarted; both hosts reconverge
at
changed=0). This PR bringsmainin line with what is deployed — the vault edit was madedirectly on the host-facing tree while portal mail was down.
The failure
Portal mail was returning
401on every sender, includingalerts@mail.gitborg.se, which hadreturned
200hours earlier. Meanwhile:identical
sha256fingerprints,Freshly minted credentials fixed it immediately. The old key had been invalidated provider-side
without its value changing and without the domain list reflecting it.
Portal mail is API-only (
src/lib/email.ts), so while this was broken new sign-ups received nosetup link and could not complete registration.
What the guidance said, and why it was wrong
Two places stated that the API key was not the problem, must not be re-scoped or re-minted, and
that no vault edit should be expected. The measurement underneath was correct — authorisation is
per-domain, not per-address — but the inference was not: that the key authorised the old domain
did not make the key healthy. Corrected in place rather than deleted, because the reasoning looked
sound and will look sound again.
Why a 401 cannot be diagnosed from a host
Recorded so nobody re-derives it. Sweego returns an identical
401 {"detail":"Unauthorized"}for aninvalid key and for a valid key with an unauthorised sender. Every route that might have
discriminated was probed:
/contacts/lists/campaigns/templates/webhooks/transactions/messages/segments/emails/suppressions/bounces/domains/senders/sending-domains/identities/account/me/transac/domains404 Route Not Found/channels/stats401for any key/sendwith empty body422for any key — body validated before credential/channelsis the trap: it returns the same 200 body with a garbage key, an empty key, and noheader at all. It nearly read as proof the key was valid, and was only caught because the negative
control was run.
The only decisive test is a freshly minted key. The guidance now says to re-mint early.
Also added
Gate step 0 before the apply, not after. Step 0 can be run against the vaulted value from the
prod host with a throwaway play (
uri+no_logon the request,failed_when: false, debug thestatus only), proving the credential before anything restarts. That is how this rotation was
verified — both domains returned
200with transaction ids before the apply, so no restart wasspent on an untested key.
Side effect: §5 is unblocked
email.bitborg.senow returns200for the first time, so step 0 passes and steps 1–3 of themail-domain move are available. None of them are done here — step 1 remains applied, step 2 stays
reverted, step 3 has never been applied.
Note on the rotation mechanism
forgejo_mailer_passwd_secretis content-addressed:Podman secrets cannot be mutated in place, so rotating the password renames the secret, which
changes the Quadlet unit, which restarts Forgejo onto it. Two of the apply's changed tasks are
consequences of that one root cause, not independent drift.