GSA-TTS / cg-egress-proxy

Provides controlled egress for apps in a restricted-egress cloud.gov space
Other
12 stars 4 forks source link

Implement SMTP egress proxy #17

Closed mogul closed 1 year ago

mogul commented 1 year ago

This PR implements an outbound SMTPS proxy for apps to use when sending mail from an egress-restricted space.

Potential solutions:

mogul commented 1 year ago

Having researched more: I'd like to stick with Caddy for everything, but from what I can tell this is the more straightforward option due to explicit support for what we want to do:

The mail module is not included in the nginx-buildpack so we'll need to build it and load it dynamically.

robert-bryson commented 1 year ago

The mail module is not included in the nginx-buildpack so we'll need to build it and load it dynamically.

We tried using the nginx dynamically loading modules thing in the past. It did work eventually (though the ticket ended up not working correctly, so we went a different direction) and here is the PR we had if it helps at all to help you to see our efforts.

One blocker we had was that 'dynamic' in this case is not as it would be in another language where you can just import <module>. You still need to compile your nginx extension yourself to be able to provide a binary that was generated with the exact same set of flags/versions that your ngnix instance is running. For example, check nginx -V. The module's ./configure call needs to match that exactly. Here is our vendor script and here is the action to build it. I'm sure you've already figured this all out @mogul, but hope it helps if not.

In any case, hello and hope you're doing well!

mogul commented 1 year ago

I had an idea of what was required but I hadn't gone anywhere near this far... Thanks so much!

mogul commented 1 year ago

I want to try to enable the mail module in the nginx_buildpack upstream before I fully commit to maintaining our own .so (and then having to update it every time a new version NGINX appears!)

There's precedent for this having been done for another module so I'm hopeful it will be merged without issue.

mogul commented 1 year ago

I want to try to enable the mail module in the nginx_buildpack upstream before I fully commit to maintaining our own .so (and then having to update it every time a new version NGINX appears!)

They merged my PR! 🥳

mogul commented 1 year ago

While I'm waiting for a new release of the nginx-buildpack to drop that includes the dynamic mail module natively: I figured out how to build it in such a way that it loads up no problem. The key difference from the PR that you referenced, @robert-bryson, was that I used the cloudfoundry/cflinuxfs4 image to ensure I was compiling in an environment that exactly matches where nginx will be running.

#!/bin/bash 

# Generate a ngx_mail_module.so ready for dynamic loading by the nginx_buildpack.
# 
# This is only necessary until the following PR is incorporated into an nginx-buildpack.
# https://github.com/cloudfoundry/buildpacks-ci/pull/279
# 
# The actual process runs inside a Docker container; Docker is the only local
# prerequisite.

# Latest as of the time of writing
nginx_version="1.23.4"

# Current stack in use on cloud.gov as of writing
image="cloudfoundry/cflinuxfs4:latest"

if [[ ! -f "nginx-${nginx_version}.tar.gz" ]]; then
  wget "http://nginx.org/download/nginx-${nginx_version}.tar.gz"
fi
mkdir -p modules
owner=$(id -u)
group=$(id -g)

# The bind mount here enables us to write back to the host filesystem
docker run \
    --mount type=bind,source="$(pwd)",target=/home/vcap/app \
    --tmpfs /home/vcap/app/src \
    --rm \
    --interactive \
    ${image} /bin/bash \
    -eu \
    <<EOF
apt update
apt install gcc libpcre3-dev zlib1g-dev make libssl-dev -y

# Go where the app files are
cd /home/vcap/app

tar -xzvf nginx-${nginx_version}.tar.gz
cd nginx-${nginx_version}
./configure --with-compat --with-mail=dynamic --with-mail_ssl_module 
make modules
cp objs/ngx_mail_module.so /home/vcap/app/modules
chown ${owner}:${group} /home/vcap/app/modules/ngx_mail_module.so
cd -
rm -fr nginx-${nginx_version}
EOF
robert-bryson commented 1 year ago

The key difference from the PR that you referenced, @robert-bryson, was that I used the cloudfoundry/cflinuxfs4 image to ensure I was compiling in an environment that exactly matches where nginx will be running.

That is a much better solution! Great work, @mogul!

mogul commented 1 year ago

After an embarrassingly long and frustrating time spent trying to implement this with the NGINX mail module and failing, I found a stupidly easy way to implement this using the stream module, which is already made available by the buildpack.

mogul commented 1 year ago

Since I've implemented an SMTP proxy without using Caddy over here, I'm going to close this PR. (That module will be added to https://github.com/18F/terraform-cloudgov soon.)