14 changed files with 339 additions and 0 deletions
@ -0,0 +1,12 @@ |
|||
##
|
|||
## Makefile for smtprelay quadlet
|
|||
##
|
|||
|
|||
DEPENDENCIES = lego |
|||
|
|||
# smtprelay quadlet is mapped to the 10030 user (smtprelay) and 10000 group (itix-svc)
|
|||
PROJECT_UID = 10030 |
|||
PROJECT_GID = 10000 |
|||
|
|||
# Include common Makefile
|
|||
include ../../scripts/common.mk |
|||
@ -0,0 +1,68 @@ |
|||
# Podman Quadlet: smtprelay |
|||
|
|||
## Overview |
|||
|
|||
[smtprelay](https://github.com/decke/smtprelay) is a small Golang based SMTP relay/proxy server that accepts mail via SMTP and forwards it to an upstream smarthost (ex: Mailgun, Gmail, ...). |
|||
|
|||
This cookbook: |
|||
|
|||
- Builds a custom smtprelay container image locally, from CentOS Stream 10. |
|||
- Runs smtprelay directly as a dedicated, unprivileged UID/GID (no user namespace mapping). |
|||
- Listens on the submission port (587) with STARTTLS, authenticating clients against a local user/password file. |
|||
- Loads TLS certificates issued by the `lego` cookbook and reloads them automatically when renewed. |
|||
- Includes a timer to periodically rebuild the container image. |
|||
|
|||
## Prerequisites |
|||
|
|||
- Configuration file `/etc/quadlets/smtprelay/smtprelay.ini` must exist. |
|||
- File `/etc/quadlets/smtprelay/allowed_users.txt` must exist, listing the users allowed to relay mail. |
|||
- The `lego` cookbook should be configured to provide TLS certificates. |
|||
|
|||
## Usage |
|||
|
|||
In a separate terminal, follow the logs. |
|||
|
|||
```sh |
|||
sudo make tail-logs |
|||
``` |
|||
|
|||
Install the Podman Quadlets and start smtprelay. |
|||
|
|||
```sh |
|||
sudo make clean install |
|||
``` |
|||
|
|||
You should see the **smtprelay-build.service** building the smtprelay container image. |
|||
Then, the **smtprelay.service** should start up. |
|||
|
|||
Verify smtprelay is running: |
|||
|
|||
```sh |
|||
sudo systemctl status smtprelay.service |
|||
``` |
|||
|
|||
Send a test mail with [swaks](https://www.jetmore.org/john/code/swaks/): |
|||
|
|||
```sh |
|||
swaks --to youremail@example.com --from youremail@example.com --auth-user yourusername --auth-password yourpassword --port 587 --tls |
|||
``` |
|||
|
|||
When Let's Encrypt certificates are renewed, the renewal hook automatically restarts smtprelay so it picks up the new certificates. |
|||
|
|||
Restart the **smtprelay.target** unit. |
|||
|
|||
```sh |
|||
sudo systemctl restart smtprelay.target |
|||
``` |
|||
|
|||
Finally, remove the quadlets, their configuration and their data. |
|||
|
|||
```sh |
|||
sudo make uninstall clean |
|||
``` |
|||
|
|||
## Integration tests |
|||
|
|||
```sh |
|||
sudo make test |
|||
``` |
|||
@ -0,0 +1,73 @@ |
|||
# Specification for smtprelay Quadlet Cookbook |
|||
|
|||
You will have to develop a Quadlet cookbook for smtprelay, the mail transfer agent. |
|||
|
|||
## Architecture |
|||
|
|||
smtprelay is a mail transfer agent, deployed as a container image. |
|||
The container image will be built from the CentOS Stream 10 image (`quay.io/centos/centos:stream10`). |
|||
|
|||
## Common requirements |
|||
|
|||
- The `quay.io/centos/centos:stream10` docker image MUST have its own quadlet .image file. |
|||
- Each cookbook MUST have a dedicated unique UID. The GID is 10000. |
|||
|
|||
## Security |
|||
|
|||
Directly set the UID and GID in the quadlet file (no mapping). |
|||
Use the host network, like other quadlet cookbooks. |
|||
Let's Encrypt certificates will be handled by Traefik, so no need to worry about that in the smtprelay cookbook. |
|||
|
|||
## Installation |
|||
|
|||
Create the Containerfile for smtprelay, which will install the smtprelay binary. |
|||
The smtprelay binary can be obtained from the official releases on GitHub: https://github.com/decke/smtprelay. |
|||
|
|||
Look at `cookbooks/base/config/install-fastfetch.sh` for an example of how to install a binary from a GitHub release in a Containerfile. |
|||
|
|||
## Configuration |
|||
|
|||
A sample configuration file for smtprelay: |
|||
|
|||
```ini |
|||
; Hostname for this SMTP server |
|||
hostname = localhost |
|||
|
|||
; File which contains username and password used for |
|||
; authentication before they can send mail. |
|||
allowed_users = /etc/smtprelay/allowed_users.txt |
|||
|
|||
; Networks that are allowed to send mails to us |
|||
; Defaults to localhost. If set to "", then any address is allowed. |
|||
;allowed_nets = 0.0.0.0/0 ::/0 |
|||
allowed_nets = 0.0.0.0/0 |
|||
|
|||
; Enable TLS for incoming connections on port 587 |
|||
listen = starttls://0.0.0.0:587 |
|||
local_cert = /etc/smtprelay/tls/localhost.crt |
|||
local_key = /etc/smtprelay/tls/localhost.key |
|||
|
|||
; Enforce encrypted connection on STARTTLS ports before |
|||
; accepting mails from client. |
|||
local_forcetls = true |
|||
|
|||
; Relay Config (ex: Mailgun) |
|||
remotes = starttls://user:pass@smtp.mailgun.org:587 |
|||
``` |
|||
|
|||
## Entrypoint |
|||
|
|||
```sh |
|||
smtprelay --config /etc/smtprelay/smtprelay.ini -logfile=/dev/stdout |
|||
``` |
|||
|
|||
## How to test |
|||
|
|||
```sh |
|||
swaks --to youremail@example.com --from youremail@example.com --auth-user yourusername --auth-password yourpassword --port 587 --tls |
|||
``` |
|||
|
|||
## Useful examples |
|||
|
|||
You can copy the structure of the `miniflux` cookbook. |
|||
Look at the `samba` cookbook for an example of how to handle the container image building. |
|||
@ -0,0 +1,22 @@ |
|||
FROM quay.io/centos/centos:stream10 AS builder |
|||
|
|||
# Tools needed to fetch and unpack the smtprelay release |
|||
RUN dnf install -y curl jq tar gzip \ |
|||
&& dnf clean all |
|||
|
|||
COPY install-smtprelay.sh / |
|||
RUN /install-smtprelay.sh |
|||
|
|||
FROM quay.io/centos/centos:stream10 |
|||
|
|||
# CA certificates are required to establish TLS connections to the relay host |
|||
RUN dnf install -y ca-certificates \ |
|||
&& dnf clean all |
|||
|
|||
COPY --from=builder /usr/local/bin/smtprelay /usr/local/bin/smtprelay |
|||
|
|||
# Submission port |
|||
EXPOSE 587 |
|||
|
|||
ENTRYPOINT [ "/usr/local/bin/smtprelay" ] |
|||
CMD [ "--config", "/etc/smtprelay/smtprelay.ini", "-logfile=/dev/stdout" ] |
|||
@ -0,0 +1,9 @@ |
|||
#!/bin/bash |
|||
set -Eeuo pipefail |
|||
SMTPRELAY_LATEST_VERSION="$(curl -sSfL https://api.github.com/repos/decke/smtprelay/releases | jq -r '.[] | select(.prerelease == false and .draft == false) | .tag_name' | sort -V | tail -1)" |
|||
SMTPRELAY_VERSION="${SMTPRELAY_VERSION:-$SMTPRELAY_LATEST_VERSION}" |
|||
declare -A ARCH_MAP=( ["x86_64"]="amd64" ["aarch64"]="arm64" ) |
|||
arch="$(arch)" |
|||
arch=${ARCH_MAP[$arch]} |
|||
echo "Installing smtprelay $SMTPRELAY_VERSION for $arch..." |
|||
curl -sSfL https://github.com/decke/smtprelay/releases/download/$SMTPRELAY_VERSION/smtprelay-$SMTPRELAY_VERSION-linux-$arch.tar.gz | tar -zx -C /usr/local/bin --no-same-owner smtprelay |
|||
@ -0,0 +1,16 @@ |
|||
# File which contains username and password used for authentication |
|||
# before clients can relay mail through this server. |
|||
# |
|||
# Format (one user per line, fields separated by spaces): |
|||
# username bcrypt-hash [email[,email[,...]]] |
|||
# |
|||
# username: the SMTP auth username |
|||
# bcrypt-hash: the bcrypt hash of the password |
|||
# email: comma-separated list of "from" addresses the user is |
|||
# allowed to send as (omit to allow any address) |
|||
# |
|||
# Generate the bcrypt hash of a password with: |
|||
# python3 -c "import bcrypt; print(bcrypt.hashpw(b'<password>', bcrypt.gensalt()).decode())" |
|||
# |
|||
# Example user "demo" (password "changeme") allowed to send from any address: |
|||
demo $2b$12$V3XmeosOSoI4B.2D8HLzWu7y2YQaoBeF2unnGopZ2ZJJpQ58sKToa |
|||
@ -0,0 +1,42 @@ |
|||
# ----------------------------------------------------------------------- |
|||
# smtprelay configuration - relay-only SMTP server |
|||
# |
|||
# Copy this file to /etc/quadlets/smtprelay/smtprelay.ini and adjust the |
|||
# values for your environment. |
|||
# ----------------------------------------------------------------------- |
|||
|
|||
; Hostname for this SMTP server |
|||
hostname = mail.example.com |
|||
|
|||
; File which contains username and password used for |
|||
; authentication before they can send mail (see allowed_users.txt example). |
|||
allowed_users = /etc/smtprelay/allowed_users.txt |
|||
|
|||
; Networks that are allowed to send mails to us. |
|||
; The container uses the host network, so clients connect from outside - |
|||
; allow any address and rely on SMTP authentication instead. |
|||
allowed_nets = 0.0.0.0/0 |
|||
|
|||
; ----------------------------------------------------------------------- |
|||
; Inbound TLS (certificates provided by the lego cookbook) |
|||
; |
|||
; Replace "localhost" with the actual certificate filename from |
|||
; /var/lib/quadlets/lego/certificates/. |
|||
; ----------------------------------------------------------------------- |
|||
|
|||
; Enable TLS for incoming connections on port 587 |
|||
listen = starttls://0.0.0.0:587 |
|||
local_cert = /etc/smtprelay/tls/localhost.crt |
|||
local_key = /etc/smtprelay/tls/localhost.key |
|||
|
|||
; Enforce encrypted connection on STARTTLS ports before |
|||
; accepting mails from client. |
|||
local_forcetls = true |
|||
|
|||
; ----------------------------------------------------------------------- |
|||
; Outbound relay |
|||
; ----------------------------------------------------------------------- |
|||
|
|||
; Relay all mail through an upstream smarthost (ex: Mailgun). |
|||
; Adjust the credentials and host for your provider. |
|||
remotes = starttls://user:pass@smtp.mailgun.org:587 |
|||
@ -0,0 +1,6 @@ |
|||
#!/bin/bash |
|||
|
|||
set -Eeuo pipefail |
|||
|
|||
install -o 10030 -g 10000 -m 0600 -t /run/quadlets/smtprelay/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key |
|||
systemctl --no-block restart smtprelay.service |
|||
@ -0,0 +1,9 @@ |
|||
variant: fcos |
|||
version: 1.4.0 |
|||
passwd: |
|||
users: |
|||
- name: smtprelay |
|||
uid: 10030 |
|||
gecos: smtprelay MTA |
|||
home_dir: /var/lib/quadlets/smtprelay |
|||
primary_group: itix-svc |
|||
@ -0,0 +1,10 @@ |
|||
[Unit] |
|||
Description=Rebuild the smtprelay container image |
|||
PartOf=smtprelay.target |
|||
|
|||
[Timer] |
|||
OnCalendar=daily |
|||
Persistent=true |
|||
|
|||
[Install] |
|||
WantedBy=smtprelay.target |
|||
@ -0,0 +1,10 @@ |
|||
[Unit] |
|||
Description=Build of the smtprelay MTA |
|||
Wants=network-online.target |
|||
After=network-online.target centos-stream10-image.service |
|||
Requires=centos-stream10-image.service |
|||
|
|||
[Build] |
|||
File=/etc/quadlets/smtprelay/container/Containerfile |
|||
ImageTag=localhost/smtprelay:latest |
|||
SetWorkingDirectory=/etc/quadlets/smtprelay/container |
|||
@ -0,0 +1,49 @@ |
|||
[Unit] |
|||
Description=smtprelay MTA |
|||
Documentation=https://github.com/decke/smtprelay |
|||
After=local-fs.target network.target smtprelay-build.service lego.target |
|||
Wants=smtprelay-build.service lego.target |
|||
|
|||
# Only start if the main configuration file exists |
|||
ConditionPathExists=/etc/quadlets/smtprelay/smtprelay.ini |
|||
|
|||
# Stop when the target is stopped |
|||
PartOf=smtprelay.target |
|||
|
|||
[Container] |
|||
ContainerName=smtprelay |
|||
|
|||
# Image |
|||
Image=localhost/smtprelay:latest |
|||
AutoUpdate=local |
|||
|
|||
# Security - run directly as a dedicated, unprivileged UID/GID (no mapping) |
|||
User=10030 |
|||
Group=10000 |
|||
|
|||
# Port 587 is a privileged port (< 1024); grant the capability to bind to it |
|||
AddCapability=CAP_NET_BIND_SERVICE |
|||
|
|||
# Command and arguments |
|||
Entrypoint=/usr/local/bin/smtprelay |
|||
Exec=--config /etc/smtprelay/smtprelay.ini -logfile=/dev/stdout |
|||
|
|||
# Storage |
|||
Volume=/etc/quadlets/smtprelay/smtprelay.ini:/etc/smtprelay/smtprelay.ini:ro,Z |
|||
Volume=/etc/quadlets/smtprelay/allowed_users.txt:/etc/smtprelay/allowed_users.txt:ro,Z |
|||
Volume=/run/quadlets/smtprelay/tls:/etc/smtprelay/tls:Z |
|||
|
|||
# Network |
|||
Network=host |
|||
|
|||
[Service] |
|||
Restart=always |
|||
RestartSec=10 |
|||
TimeoutStartSec=120 |
|||
TimeoutStopSec=30 |
|||
|
|||
# Get the TLS certificates in place before starting smtprelay |
|||
ExecStartPre=/bin/sh -c 'install -o 10030 -g 10000 -m 0600 -t /run/quadlets/smtprelay/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key' |
|||
|
|||
[Install] |
|||
WantedBy=smtprelay.target |
|||
@ -0,0 +1,11 @@ |
|||
[Unit] |
|||
Description=smtprelay Service Target |
|||
Documentation=man:systemd.target(5) |
|||
Requires=smtprelay.service smtprelay-build.timer |
|||
After=smtprelay.service smtprelay-build.timer |
|||
|
|||
# Allow isolation - can stop/start this target independently |
|||
AllowIsolate=yes |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
@ -0,0 +1,2 @@ |
|||
d$ /run/quadlets/smtprelay 0700 10030 10000 - |
|||
d$ /run/quadlets/smtprelay/tls 0700 10030 10000 - |
|||
Loading…
Reference in new issue