Browse Source

add cookbook for smtprelay

main
Nicolas Massé 2 weeks ago
parent
commit
21ba201b61
  1. 12
      cookbooks/smtprelay/Makefile
  2. 68
      cookbooks/smtprelay/README.md
  3. 73
      cookbooks/smtprelay/SPECS.md
  4. 22
      cookbooks/smtprelay/config/container/Containerfile
  5. 9
      cookbooks/smtprelay/config/container/install-smtprelay.sh
  6. 16
      cookbooks/smtprelay/config/examples/allowed_users.txt
  7. 42
      cookbooks/smtprelay/config/examples/smtprelay.ini
  8. 6
      cookbooks/smtprelay/other/lego/smtprelay.sh
  9. 9
      cookbooks/smtprelay/overlay.bu
  10. 10
      cookbooks/smtprelay/smtprelay-build.timer
  11. 10
      cookbooks/smtprelay/smtprelay.build
  12. 49
      cookbooks/smtprelay/smtprelay.container
  13. 11
      cookbooks/smtprelay/smtprelay.target
  14. 2
      cookbooks/smtprelay/tmpfiles.d/smtprelay.conf

12
cookbooks/smtprelay/Makefile

@ -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

68
cookbooks/smtprelay/README.md

@ -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
```

73
cookbooks/smtprelay/SPECS.md

@ -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.

22
cookbooks/smtprelay/config/container/Containerfile

@ -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" ]

9
cookbooks/smtprelay/config/container/install-smtprelay.sh

@ -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

16
cookbooks/smtprelay/config/examples/allowed_users.txt

@ -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

42
cookbooks/smtprelay/config/examples/smtprelay.ini

@ -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

6
cookbooks/smtprelay/other/lego/smtprelay.sh

@ -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

9
cookbooks/smtprelay/overlay.bu

@ -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

10
cookbooks/smtprelay/smtprelay-build.timer

@ -0,0 +1,10 @@
[Unit]
Description=Rebuild the smtprelay container image
PartOf=smtprelay.target
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=smtprelay.target

10
cookbooks/smtprelay/smtprelay.build

@ -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

49
cookbooks/smtprelay/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

11
cookbooks/smtprelay/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

2
cookbooks/smtprelay/tmpfiles.d/smtprelay.conf

@ -0,0 +1,2 @@
d$ /run/quadlets/smtprelay 0700 10030 10000 -
d$ /run/quadlets/smtprelay/tls 0700 10030 10000 -
Loading…
Cancel
Save