129 lines
4.4 KiB
Nix
129 lines
4.4 KiB
Nix
|
let
|
||
|
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||
|
domain = certs.domain;
|
||
|
in
|
||
|
import ./make-test-python.nix {
|
||
|
name = "schleuder";
|
||
|
nodes.machine = { pkgs, ... }: {
|
||
|
imports = [ ./common/user-account.nix ];
|
||
|
services.postfix = {
|
||
|
enable = true;
|
||
|
enableSubmission = true;
|
||
|
tlsTrustedAuthorities = "${certs.ca.cert}";
|
||
|
sslCert = "${certs.${domain}.cert}";
|
||
|
sslKey = "${certs.${domain}.key}";
|
||
|
inherit domain;
|
||
|
destination = [ domain ];
|
||
|
localRecipients = [ "root" "alice" "bob" ];
|
||
|
};
|
||
|
services.schleuder = {
|
||
|
enable = true;
|
||
|
# Don't do it like this in production! The point of this setting
|
||
|
# is to allow loading secrets from _outside_ the world-readable
|
||
|
# Nix store.
|
||
|
extraSettingsFile = pkgs.writeText "schleuder-api-keys.yml" ''
|
||
|
api:
|
||
|
valid_api_keys:
|
||
|
- fnord
|
||
|
'';
|
||
|
lists = [ "security@${domain}" ];
|
||
|
settings.api = {
|
||
|
tls_cert_file = "${certs.${domain}.cert}";
|
||
|
tls_key_file = "${certs.${domain}.key}";
|
||
|
};
|
||
|
};
|
||
|
|
||
|
environment.systemPackages = [
|
||
|
pkgs.gnupg
|
||
|
pkgs.msmtp
|
||
|
(pkgs.writeScriptBin "do-test" ''
|
||
|
#!${pkgs.runtimeShell}
|
||
|
set -exuo pipefail
|
||
|
|
||
|
# Generate a GPG key with no passphrase and export it
|
||
|
sudo -u alice gpg --passphrase-fd 0 --batch --yes --quick-generate-key 'alice@${domain}' rsa4096 sign,encr < <(echo)
|
||
|
sudo -u alice gpg --armor --export alice@${domain} > alice.asc
|
||
|
# Create a new mailing list with alice as the owner, and alice's key
|
||
|
schleuder-cli list new security@${domain} alice@${domain} alice.asc
|
||
|
|
||
|
# Send an email from a non-member of the list. Use --auto-from so we don't have to specify who it's from twice.
|
||
|
msmtp --auto-from security@${domain} --host=${domain} --port=25 --tls --tls-starttls <<EOF
|
||
|
Subject: really big security issue!!
|
||
|
From: root@${domain}
|
||
|
|
||
|
I found a big security problem!
|
||
|
EOF
|
||
|
|
||
|
# Wait for delivery
|
||
|
(set +o pipefail; journalctl -f -n 1000 -u postfix | grep -m 1 'delivered to maildir')
|
||
|
|
||
|
# There should be exactly one email
|
||
|
mail=(/var/spool/mail/alice/new/*)
|
||
|
[[ "''${#mail[@]}" = 1 ]]
|
||
|
|
||
|
# Find the fingerprint of the mailing list key
|
||
|
read list_key_fp address < <(schleuder-cli keys list security@${domain} | grep security@)
|
||
|
schleuder-cli keys export security@${domain} $list_key_fp > list.asc
|
||
|
|
||
|
# Import the key into alice's keyring, so we can verify it as well as decrypting
|
||
|
sudo -u alice gpg --import <list.asc
|
||
|
# And perform the decryption.
|
||
|
sudo -u alice gpg -d $mail >decrypted
|
||
|
# And check that the text matches.
|
||
|
grep "big security problem" decrypted
|
||
|
'')
|
||
|
|
||
|
# For debugging:
|
||
|
# pkgs.vim pkgs.openssl pkgs.sqliteinteractive
|
||
|
];
|
||
|
|
||
|
security.pki.certificateFiles = [ certs.ca.cert ];
|
||
|
|
||
|
# Since we don't have internet here, use dnsmasq to provide MX records from /etc/hosts
|
||
|
services.dnsmasq = {
|
||
|
enable = true;
|
||
|
extraConfig = ''
|
||
|
selfmx
|
||
|
'';
|
||
|
};
|
||
|
|
||
|
networking.extraHosts = ''
|
||
|
127.0.0.1 ${domain}
|
||
|
'';
|
||
|
|
||
|
# schleuder-cli's config is not quite optimal in several ways:
|
||
|
# - A fingerprint _must_ be pinned, it doesn't even have an option
|
||
|
# to trust the PKI
|
||
|
# - It compares certificate fingerprints rather than key
|
||
|
# fingerprints, so renewals break the pin (though that's not
|
||
|
# relevant for this test)
|
||
|
# - It compares them as strings, which means we need to match the
|
||
|
# expected format exactly. This means removing the :s and
|
||
|
# lowercasing it.
|
||
|
# Refs:
|
||
|
# https://0xacab.org/schleuder/schleuder-cli/-/issues/16
|
||
|
# https://0xacab.org/schleuder/schleuder-cli/-/blob/f8895b9f47083d8c7b99a2797c93f170f3c6a3c0/lib/schleuder-cli/helper.rb#L230-238
|
||
|
systemd.tmpfiles.rules = let cliconfig = pkgs.runCommand "schleuder-cli.yml"
|
||
|
{
|
||
|
nativeBuildInputs = [ pkgs.jq pkgs.openssl ];
|
||
|
} ''
|
||
|
fp=$(openssl x509 -in ${certs.${domain}.cert} -noout -fingerprint -sha256 | cut -d = -f 2 | tr -d : | tr 'A-Z' 'a-z')
|
||
|
cat > $out <<EOF
|
||
|
host: localhost
|
||
|
port: 4443
|
||
|
tls_fingerprint: "$fp"
|
||
|
api_key: fnord
|
||
|
EOF
|
||
|
''; in
|
||
|
[
|
||
|
"L+ /root/.schleuder-cli/schleuder-cli.yml - - - - ${cliconfig}"
|
||
|
];
|
||
|
};
|
||
|
|
||
|
testScript = ''
|
||
|
machine.wait_for_unit("multi-user.target")
|
||
|
machine.wait_until_succeeds("nc -z localhost 4443")
|
||
|
machine.succeed("do-test")
|
||
|
'';
|
||
|
}
|