Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
system: [debian-12, debian-13, ubuntu-22.04, ubuntu-24.04, ubuntu-26.04, rocky-9, almalinux-10]
group: [base, security, scanners, web, runtime, database, database-alt, container, backup, backup-alt, monitoring, network]
group: [base, security, scanners, web, runtime, database, database-alt, container, backup, backup-alt, monitoring, network, mail]
arch: [x64, arm64]
include:
- group: base
Expand Down Expand Up @@ -66,6 +66,11 @@ jobs:
modules: node-exporter prometheus,alertmanager,grafana nginx,prometheus,grafana loki,alloy wireguard,netdata smartd
- group: network
modules: wireguard dns-resolver ntp-server
# mail-relay alone, then with the guard, whose daily summary it delivers to root; the mail server, then with
# webmail behind nginx. tests/integration/mail-flow.sh sends, receives and checks DKIM, SPF, DMARC and the spam
# filter without public DNS.
- group: mail
modules: mail-relay guard,mail-relay mailserver nginx,php,mailserver,webmail
steps:
- uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
with:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ now or later.
the time module serves the WireGuard network or everyone, rate-limited).
- Profile `devops` (minimal-secure, Docker and the monitoring stack); `webhosting` adds restic and db-dumps, `all`
every new module.
- Mail modules: `mail-relay` (send-only Postfix on the loopback addresses, through a smarthost with a checked
certificate or directly with opportunistic TLS or DANE), `mailserver` (Postfix, Dovecot and Rspamd: submission with
TLS and login only, senders tied to their login, spam filter, DKIM signing, SPF, DKIM and DMARC checks; it prints the
MX, SPF, DKIM, DMARC and PTR records to set) and `webmail` (checksum-verified Roundcube on the web server). guard
sends its e-mail through them. Profile `office`; `all` adds mailserver and webmail.
- guard checks the age of the last backup (`LSS_GUARD_BACKUP_MAX_AGE`), runs a restore test every week and exports
its results for Prometheus through the node exporter.
- The services of the backup, monitoring and network modules run with a systemd sandbox drop-in; a service that
Expand Down
65 changes: 62 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,12 @@ up). Peak RAM covers install and `lss verify`; "while running" is what stays res
| `wireguard` | 15 s | 260 MiB | 100 MiB | – (kernel) |
| `dns-resolver` | 45 s | 180 MiB | 40 MiB | Unbound about 20 MiB |
| `ntp-server` | 15 s | 195 MiB | 10 MiB | – (the chronyd of `time`, about 10 MiB) |
| `mail-relay` | 35 s | 250 MiB | 180 MiB (dnf), else 135 MiB | Postfix (master, queue manager, pickup) |
| `mailserver` | 90 s | 800 MiB (dnf), else 225 MiB | 235 MiB (dnf), else 120 MiB | Postfix, Dovecot and Rspamd, up to 180 MiB |
| `webmail` | 135 s with nginx, php and mailserver | 390 MiB together | 265 MiB together | Roundcube in PHP-FPM; with nginx and the mail server up to 290 MiB |

Modules the tests install together are measured together. The Rocky 9 VM in CI is slow throughout (eight minutes even
for `wireguard`); those outliers are left out.
for `wireguard`); those outliers are left out, like one Rocky 9 container run of `mail-relay` that took six minutes.

Web, runtime and database modules, measured the same way. Modules that only work together are tested together; their
row is the cost of the whole set, including the web server or PHP it needs.
Expand Down Expand Up @@ -213,7 +216,7 @@ first password with `lss secrets show pgadmin-admin-password`), all on the admin
together with `docker`). See [Containers](#containers).

The [hardening guide](docs/hardening.md) lists what each security module changes, the CIS Benchmark areas it covers
and where lss deliberately deviates. Mail follows as a further module group.
and where lss deliberately deviates.

**Backup:** `restic` (daily, encrypted backups to a local path, SFTP or S3) and `db-dumps` (dumps of the databases
before each backup). See [Backup](#backup).
Expand All @@ -224,6 +227,9 @@ before each backup). See [Backup](#backup).
**Network:** `wireguard` (VPN server), `dns-resolver` (Unbound with DNSSEC), `ntp-server` (chrony serves the time).
See [WireGuard, DNS and NTP](#wireguard-dns-and-ntp).

**Mail:** `mail-relay` (the server sends its own mail, through a smarthost or directly) or `mailserver` (Postfix,
Dovecot and Rspamd for your domains), `webmail` (Roundcube on the web server). See [Mail](#mail).

### Web sites

One web server owns ports 80 and 443. It answers only for the sites you set up; requests for any other host name get
Expand Down Expand Up @@ -342,6 +348,58 @@ resolvers, over TLS with `LSS_DNS_RESOLVER_FORWARD_TLS=true`.
`ntp-server` opens chrony of the `time` module to the WireGuard network (or to everyone with
`LSS_NTP_SERVER_ACCESS=public`), with rate limiting.

### Mail

`mail-relay` is for servers that only send: mail from root, cron, the guard and applications goes out through
`LSS_MAIL_RELAY_RELAYHOST` (STARTTLS on 587 or TLS on 465, the certificate checked, `LSS_MAIL_RELAY_USER` and the
password in the lss secrets) or, without a smarthost, straight to the recipients' servers with opportunistic TLS
(DANE when `dns-resolver` is installed; `mailserver` does the same, and `lss configure` picks up a
resolver added later). Postfix listens on 127.0.0.1 and ::1 only. Mail for root stays in
`/var/mail/root` unless `LSS_MAIL_RELAY_FORWARD` names an address. Most smarthosts accept only their own sender
addresses; set `LSS_MAIL_RELAY_FROM`.

```bash
LSS_MAIL_RELAY_RELAYHOST=smtp.example.com:587
LSS_MAIL_RELAY_USER=server1@example.com
LSS_MAIL_RELAY_PASSWORD=...
LSS_MAIL_RELAY_FROM=server1@example.com
LSS_MAIL_RELAY_FORWARD=admin@example.com
```

`mailserver` receives and delivers mail for `LSS_MAILSERVER_DOMAINS`: Postfix on port 25, submission on 587
(STARTTLS) and 465 (TLS) with login only, Dovecot with IMAPS on 993, Rspamd as spam filter (reject from score 15, a
header from 6) that signs outgoing mail with DKIM and checks SPF, DKIM and DMARC of incoming mail. Mailboxes are
`LSS_MAILSERVER_USERS`, aliases `LSS_MAILSERVER_ALIASES`; postmaster and abuse of every domain go to the first mailbox.
A login sends only as its own address and the aliases that lead to it, in the envelope (Postfix) and in the From
header (Rspamd); anything else is rejected. DKIM signs mail of a login with the key of the login's domain only, so an
alias in another domain goes out unsigned. Mail the server sends itself (sendmail, cron, the guard) is signed when its
From names a hosted domain. Each password is a secret:

```bash
LSS_MAILSERVER_DOMAINS=example.com example.org
LSS_MAILSERVER_USERS=alice bob@example.org
LSS_MAILSERVER_ALIASES=info:alice,bob@example.org
sudo lss secrets show mailbox-alice_example.com
```

lss cannot set DNS records, so it prints the ones the domains need after every change and keeps them in
`/etc/lss/mailserver-dns.txt`: MX, A and AAAA of the mail host (`mail.<first domain>` unless
`LSS_MAILSERVER_HOSTNAME`), SPF, the DKIM key (selector `lss`), DMARC (`LSS_MAILSERVER_DMARC_POLICY`, quarantine)
and the reverse DNS (PTR) the hosting provider has to set for the server's addresses. Without them other servers
reject or file the mail as spam. The certificate is self-signed until `LSS_MAILSERVER_CERTIFICATE=default` takes the
one of the `tls` module (with the mail host in `LSS_TLS_DOMAINS`); Postfix and Dovecot reload on every renewal.
Many providers block outgoing port 25; ask for it to be opened or relay through a smarthost of your provider.

`webmail` runs Roundcube as a site of the web server (`LSS_WEBMAIL_DOMAINS`, by default the mail host), with the
certificate of the `tls` module when it is installed. It talks to Dovecot and Postfix on 127.0.0.1 only. The profile
`office` installs `minimal-secure`, nginx with `tls` and `php`, `mailserver`, `webmail` and `restic`:

```bash
sudo lss install --profile office --set LSS_ADMIN_USER_NAME=alice --set LSS_ADMIN_USER_GITHUB_USER=alice-on-github --set LSS_MAILSERVER_DOMAINS=example.com --set LSS_MAILSERVER_USERS=alice --set LSS_TLS_DOMAINS=mail.example.com
```

`restic` backs up the mailboxes (`/var/vmail`), the DKIM keys and the Roundcube database by default.

## Guard

The `guard` module checks the server every day: it runs `lss verify`, repairs modules that fail or whose files were
Expand All @@ -350,7 +408,8 @@ falling Lynis index, vulnerable packages (debsecan on Debian, `dnf updateinfo` o
images with HIGH or CRITICAL vulnerabilities (Trivy, with `docker` or `podman`). It passes on
what the daily AIDE, rkhunter and ClamAV runs found, and reports more failed SSH logins than
`LSS_GUARD_LOGIN_THRESHOLD` with their main sources. Successful SSH logins and active fail2ban or CrowdSec bans are
listed as notes. Findings go to a webhook (Slack, Teams, Mattermost, Discord, ntfy) or by e-mail.
listed as notes. Findings go to a webhook (Slack, Teams, Mattermost, Discord, ntfy) or by e-mail to
`LSS_GUARD_EMAIL`, which needs `mail-relay` or `mailserver`; the guard warns when the server cannot send mail.

With `restic` installed, the guard reports a last successful backup older than `LSS_GUARD_BACKUP_MAX_AGE` hours (30)
and runs a restore test every week. With `node-exporter` installed, the number of findings goes to Prometheus as
Expand Down
3 changes: 3 additions & 0 deletions data/checksums.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ phpmyadmin-5.2.3 any 57881348297c4412f86c410547cf76b4d8a236574dd2c6b7d6a2beebe7f
# Adminer 6.1.2: SHA-256 digest of the release asset on GitHub (gh api repos/vrana/adminer/releases/tags/v6.1.2,
# checked 2026-10-13).
adminer-6.1.2 any b32316156bd18ffa99c1a27617142c2e5ad72260e37f15da4e9937a3dbb15f57 https://github.com/vrana/adminer/releases/download/v6.1.2/adminer-6.1.2.php
# Roundcube 1.7.4 (complete package with its PHP libraries): SHA-256 digest of the release asset on GitHub (gh api
# repos/roundcube/roundcubemail/releases/tags/1.7.4, checked 2026-10-15; the download matched it).
roundcube-1.7.4 any 2c6c878f0093f1bf7fb6086781d2dd9269d652c016b86939c157c5f1729139a2 https://github.com/roundcube/roundcubemail/releases/download/1.7.4/roundcubemail-1.7.4-complete.tar.gz
# pgAdmin 4 9.18 and gunicorn 26.2.0: SHA-256 of the wheels as published by PyPI (https://pypi.org/pypi/pgadmin4/9.18/json,
# https://pypi.org/pypi/gunicorn/26.2.0/json, checked 2026-10-13).
pgadmin4-9.18 any 9ea084fc416265e4fc95c9fb6e6ae0f6668d34da8670c9b65c79cea054124356 https://files.pythonhosted.org/packages/0e/80/86d7e7123e2b6de41890bd1edc3e27348e2572acea337088faa0ec41c7f5/pgadmin4-9.18-py3-none-any.whl
Expand Down
65 changes: 65 additions & 0 deletions data/keys/rspamd.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFW3VB8BEADAV1lBy8DPcSEBSLYVKgwsBx/dRmgenKeliMpiZyNYJJmF6tSV
s3v5DtDIUESgI2mBKNeptdneri3CDJScI/LgPLKqemrLBkAMfe+f57JgppY5ti4H
xo+VZdbF9bhCAwYwJnqnyuLjYSUu6nCuW4uPDoqBHXynwsIWr1O3fREpY+vgIgaT
Oqm3ncssqxSicymd6k0yuo55xuUvrc4Yu4IEnhFVRU53e0E3zmHg/7ONI99YtBan
7G/w2IfA1bfRDYZ2Avau+JqGcEl8vy+eLmYayKirdsMPN8Tx6RFOstDf1CnjW/bj
IX7SDOklIGJjJwcWW/iY+1P9SfNNqSDgXavJj2wmLMlUhgjyJFTXfdDRjmN0PFxo
f6OQu5xok1WHfKFJL+hLGknjHdXLmGd5MSuFlutdVHJQrieknjBea9xCiEsrfe8V
zyNqGhzgIYjOi/bO7jGpY/WiFHvM9XtBVp862tqM1S1WbAWW5u+es6NK4q9Cv0DR
tIalss+5gFhdsIFGFYQWfY7CrjOIC+C0+c5IGaBkHte35hCCvDpOO909xxVqUZYe
9Pl8zYgPDe1H4arMO+p6rSvVntvIWOqLqkuWYSiOY4TGADJTkeZRbopZhvqs/9mc
847fVMbOwKfkbeuGiHhUK0QFewXSu+cXJyGtyu3RgokBWr2yyzJFXIvJbQARAQAB
tDxWc2V2b2xvZCBTdGFraG92IChSc3BhbWQgcGFja2FnZXMga2V5KSA8dnNldm9s
b2RAcnNwYW1kLmNvbT6JAk4EEwEKADgCGwMCHgUCF4AFCwkIBwMFFQoJCAsFFgID
AQAWIQQ/o0fV5Zm+RZXKJXb/ojLtvyHiXgUCZRrQ/AAKCRD/ojLtvyHiXjNXD/0Z
9E03yzFU6IIMwxr4++ZaOPyRnel6UoRpmQErAzQukaMaSOUP0uAEdfZ5TVOZAydJ
kGwXefk15pgYdXNJ8uznomfBEvgimQKqpOxt7QNm8MbBnXJijwxCflJ3FvlQvxF9
5iu4nS9wZ/pJjw66eTgiv9UY3k1LT88VXZPKURoqwmb4FuZO6WBI5XBp1Wl51V2h
IorWxvVtoolEPuucpyTIKU1Tdp3oMDy/caF3/YIP+Y0e7DGO8YDxgfOhJwTY2oqw
uTTveVFhtnVPbCEqzv4D66Ukosd97zeRGoQ9kh5RKoAitnc0nmLpYbp3IfbN1bO/
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
=Zuyq
-----END PGP PUBLIC KEY BLOCK-----
17 changes: 17 additions & 0 deletions data/repos/rspamd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2025-2026 VectoDE
#
# SPDX-License-Identifier: MIT

# Rspamd from its official repositories (https://rspamd.com/downloads.html): one apt suite per release for Debian and
# Ubuntu, centos-9 and centos-10 builds for the RHEL family, x86_64 and aarch64 each. The distributions package no
# Rspamd for the RHEL family and older ones for Debian and Ubuntu; this way every system runs the same version. Key
# https://rspamd.com/apt-stable/gpg.key (the same as https://rspamd.com/rpm/rspamd.asc), fetched on 2026-10-15.
# Rspamd signs the RPM packages and the metadata. The RPM packages need EPEL (libsodium, hyperscan, jemalloc).
KEY=rspamd.asc
FINGERPRINTS=3FA347D5E599BE4595CA2576FFA232EDBF21E25E
DEB_URL=https://rspamd.com/apt-stable/
DEB_SUITE={{codename}}
DEB_COMPONENTS=main
RPM_BASEURL=https://rspamd.com/rpm-stable/centos-{{major}}/$basearch
RPM_GPGCHECK=1
RPM_REPO_GPGCHECK=1
3 changes: 3 additions & 0 deletions docs/hardening.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ Docker, databases and its own sudo rules) 78. CI checks that it stays at 82 on D
| `k3s` | Pinned, checksum-verified binary; secrets encrypted at rest, kubeconfig 0600, `protect-kernel-defaults` with the kernel values the kubelet expects, Pod Security admission (`restricted` everywhere except `kube-system`), an audit log (metadata, 30 days), idle streaming connections closed after 5 minutes, finished pods collected; k3s-selinux on the RHEL family; the API on 127.0.0.1 unless opened; pod traffic to the host only from the pod network on its bridge | CIS Kubernetes Benchmark as applied by the k3s CIS Hardening Guide (control plane, kubelet, Pod Security) |
| `guard` with a container engine | Trivy scans every image daily and reports HIGH and CRITICAL vulnerabilities per image | CIS Docker, section 4 (images) |
| `haproxy` | Statistics only on 127.0.0.1, admin socket readable by root only, chroot, systemd sandbox, ports in the firewall only for services that are not `local` | (operations) |
| `mail-relay` | Postfix on 127.0.0.1 and ::1 only, no relaying for anyone else; TLS to the smarthost with its certificate checked against the system CAs (DANE or opportunistic TLS without one), the smarthost password in a 0600 table; no delivery to programs, files or `~/.forward`; no chroot, a systemd sandbox instead | (operations) |
| `mailserver` | Postfix: no open relay, submission on 587 and 465 only with TLS 1.2 or later and a login, the sender address tied to the login in the envelope and, through an Rspamd prefilter, in the From header, login attempts rate-limited, no VRFY, strict HELO and recipient checks; Dovecot: IMAPS only (plain IMAP on 127.0.0.1 for webmail), SHA-512-crypt passwords in a 0640 file, mailboxes in `/var/vmail` (0700, own user); Rspamd: rejects spam, signs with DKIM (RSA 2048, keys 0640) only for the domain of the login or for mail of the server itself, checks SPF, DKIM and DMARC, its web interface off; every service in a systemd sandbox | (operations; Mozilla TLS guidelines) |
| `webmail` | Checksum-verified Roundcube without the installer, configuration readable by root and PHP-FPM only, a generated DES key, IMAP and SMTP on 127.0.0.1 only, strict SameSite session cookies bound to the client address, HTTPS only through the web server | OWASP Session Management |

## Deliberate deviations

Expand Down
Loading