Repository navigation
Replies: 2 comments
|
The idea of a discussion is to have a discussion before opening a pull request. As there is already a pull request, let's continue it there: #52361 |
0 replies
|
I'm afraid we can't support and maintain proprietary mechanisms for sending emails. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
The problem
Keycloak can already send through Amazon SES today — over SMTP. What that costs is a credential: SES's SMTP interface requires a username and password derived from a long-lived IAM user's secret access key. That credential cannot be an assumed role, AWS never rotates it, and it ends up stored in
realm.smtpServer.password— inside the one component in an estate whose job is to hold no shared secrets.server_admin/topics/realms/email.adocstates the dead end plainly today:A Keycloak running on EKS, ECS or EC2 already has an identity — an IRSA service account, a task role, an instance profile. It cannot use it for email.
The proposal
An
EmailSenderProviderwith the idaws-sesthat signs SES v2SendEmailrequests with SigV4 and resolves credentials from the standard AWS chain (system properties, environment, web identity token, shared config files, container credentials, IMDSv2 — in the SDK's order). Selected with--spi-email-sender--provider=aws-ses; completely inert otherwise, andorder()stays 0 so it can never win default-provider resolution by accident.The message is composed exactly as
DefaultEmailSenderProvidercomposes it — samemultipart/alternative, same header order, same RFC 2047 subject encoding,Reply-Todefaulting toFrom, the same IDN handlingconvertEmaildoes — and sent asContent.Raw. Switching a realm changes the transport and nothing a recipient can observe. The realm's existing email settings keep their meaning;envelopeFrommaps toFeedbackForwardingEmailAddress, which is a partial mapping and documented as one.No new dependencies. No AWS SDK. SigV4, the credential chain, JSON and MIME are implemented against what the server already ships:
HttpClientProvider,JsonSerialization,jakarta.mail. The change is one package underservices/src/main/java/org/keycloak/email/aws/and one appended line inMETA-INF/services/org.keycloak.email.EmailSenderProviderFactory— the same shape as #36665 (SMTP XOAUTH2), so no new Maven module and no pom edits.On testability — the objection I want to answer first
@ahus1, in #47669 you wrote that specific providers have been postponed because "we didn't have the means to integration test them… you might need to make the case why this is not needed here, or on how to test such setups in a simple manner."
That shaped the design rather than being an afterthought. The provider takes an
endpointoption (falling back toAWS_ENDPOINT_URL_SESV2, the standard AWS variable for exactly this), which makes a hermetic integration test possible:AwsSesEmailSenderTestintests/basepoints that option at the@InjectHttpServerstub, creates a user, triggers an admin execute-actions email, and asserts on the bytes that left the server: the SigV4Authorizationheader and its credential scope, and — after base64-decodingContent.Raw.Data— the parsed MIME message'sTo,From, structure and line endings. A second test flips the stub to aMessageRejected400 and asserts the failure reaches the administrator instead of being swallowed.SMTPConnectionTestuses for XOAUTH2.It is written and green. 234 unit tests in
services, plus the integration test intests/base(org.keycloak.tests.providers, already in Base3, socheck-base-suites.shneeds no edit). I have additionally run the same code against realquay.io/keycloak/keycloakcontainers for 26.0.7 and 26.7.3 to confirm the SPI compatibility story, sinceEmailSenderProvider.validate(Map)exists on some 26.x releases and not others.What I am deliberately not proposing
I have not built this on top of the messaging-SPI reshape sketched in #37848. That is a broader design question; this is a small, concrete, testable increment that does not foreclose it.
And if the outcome here is that vendor providers belong outside the core, I would be glad to contribute the documentation instead: a subsection in
email.adocinside the existingifeval::[{project_community}==true]guard, pointing at an out-of-tree provider — which is the precedent the XOAUTH2 vendor section already sets.Happy to be told which of the two you prefer before anything goes up for review.
Disclosure per CONTRIBUTING: AI agents were used in researching and writing this work.
All reactions