Using SSL/TLS in a Greenmail Docker Container
Complaining
I’m making this post because I literally spent at least 8 hour of my life over the past three days trying to figure this out. For someone who knows crypto stuff, that’s probably going to seem ridiculous, but I do not know crypto stuff, and my eyes immediately glaze over when I see an openssl
command.
So here’s the deal: I’m working on a simple mail client, written in Rust, and I wanted to do some integration testing. I’m using rust-imap, and that project has integration tests that use a tool called Greenmail. Greenmail is a mail server built for doing integration; in other words, exactly what I need.
So I downloaded the docker container and quickly got it up and running, using the rust-imap
tests as a starting point. However, when I say “up and running” I just mean that the server was running and listening for connections, but my client wasn’t able to connect due to an SSL issue: the server’s certificate was untrusted.
What came next was a lot of reading and a lot of barking up wrong trees. For example, since Greenmail doesn’t really have documentation, I was looking at the code to figure out how to configure certificates, but it was at least an hour before I realized that the configuration code had been added in the last couple weeks and they hadn’t pushed a new docker image for it.
So I tried to build the project from source, ran into issues there, yadda yadda, lots of frustration. Here’s the steps I went through to solve this, hopefully it’ll help someone out there.
The Solution
Note: this is for Greenmail 1.6.7. Later version will hopefully make using a custom keystore easier, and so steps 4 and 5 will be different, and you may be able to use a different password for the keystore.
1: Create a certificate and key:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-keyout greenmail.key -out greenmail.crt -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
The subjectAltName
is the critical bit; a lot of places on the internet imply that it’ll work as long as the CN is set to localhost
. However, support for that has been apparently deprecated for almost two decades. Had to learn that from a random post on the python bug tracker. 🙄
2: Generate the .p12
keystore:
openssl pkcs12 -export -out greenmail.p12 \
-inkey greenmail.key -in greenmail.crt
When it asks to set a password, use changeit
. The password is hardcoded in Greenmail.
3: Add certificate as a Trusted Root Certificate Authority
In Linux:
sudo cp greenmail.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
In Windows, use the graphical Certificate Manager (just search “certificate” and it should come up).
4: Add the keystore to the JAR
Get the greenmail-standalone.jar
file for the version of the docker image you’re using. You can find all the JARs at on maven.
Add the keystore: jar uvf greenmail-standalone.jar greenmail.p12
(or just open the JAR in 7zip or whatever).
5: Bind mount the JAR when running docker:
docker run \
--mount src="<full path to greenmail-standalone.jar>",dst="/home/greenmail/greenmail-standalone.jar",type=bind \
-e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' \
-p 3025:3025 -p 3110:3110 -p 3143:3143 -p 3465:3465 -p 3993:3993 -p 3995:3995 \
-it greenmail/standalone:1.6.7
Note that it does have to be the full path, not the relative path, of the local JAR file. Docker will complain if you try to use a relative path.
After all that, I can successfully establish a secure connection with the Greenmail server. Now I can actually write some tests. 😤