From 05d963e751070f6a5b4a831b075176a7bdae0b38 Mon Sep 17 00:00:00 2001 From: Joey Hewitt Date: Sun, 30 Jun 2019 02:43:29 -0600 Subject: [PATCH 1/4] lower dhparam bits, for faster tests Make a tests/lib/config.nix file that is imported into the configuration of all testing VMs. --- tests/clamav.nix | 5 +++++ tests/extern.nix | 4 ++++ tests/intern.nix | 1 + tests/lib/config.nix | 3 +++ 4 files changed, 13 insertions(+) create mode 100644 tests/lib/config.nix diff --git a/tests/clamav.nix b/tests/clamav.nix index 7c81b2d..f53de4c 100644 --- a/tests/clamav.nix +++ b/tests/clamav.nix @@ -34,6 +34,7 @@ import { { imports = [ ../default.nix + ./lib/config.nix ]; virtualisation.memorySize = 1500; @@ -103,6 +104,10 @@ import { exec grep '${clientIP}' "$@" ''; in { + imports = [ + ./lib/config.nix + ]; + environment.systemPackages = with pkgs; [ fetchmail msmtp procmail findutils grep-ip ]; diff --git a/tests/extern.nix b/tests/extern.nix index 0816d91..4b5b91f 100644 --- a/tests/extern.nix +++ b/tests/extern.nix @@ -21,6 +21,7 @@ import { { imports = [ ../default.nix + ./lib/config.nix ]; services.rsyslogd = { @@ -134,6 +135,9 @@ import { imap.close() ''; in { + imports = [ + ./lib/config.nix + ]; environment.systemPackages = with pkgs; [ fetchmail msmtp procmail findutils grep-ip check-mail-id test-imap-spam test-imap-ham ]; diff --git a/tests/intern.nix b/tests/intern.nix index ce50123..5abf379 100644 --- a/tests/intern.nix +++ b/tests/intern.nix @@ -21,6 +21,7 @@ import { { imports = [ ./../default.nix + ./lib/config.nix ]; mailserver = { diff --git a/tests/lib/config.nix b/tests/lib/config.nix new file mode 100644 index 0000000..1d56ad1 --- /dev/null +++ b/tests/lib/config.nix @@ -0,0 +1,3 @@ +{ + security.dhparams.defaultBitSize = 16; # really low for quicker tests +} From 0e6bb4e898f14af1b476c07cd1da65f4cccc3ee1 Mon Sep 17 00:00:00 2001 From: Joey Hewitt Date: Mon, 1 Jul 2019 11:32:30 -0600 Subject: [PATCH 2/4] workaround GitLab CI KVM issue Their CI environment currently doesn't have KVM. This commit should be reverted when/if they do, for much better CI speed. You can still run tests locally on your KVM-enabled machine as documented on the wiki. Workaround on GitLab is several pieces (injected through .gitlab-ci.yml): - Make a /dev/kvm file so that nix thinks we have "kvm" system feature and proceeds with executing the tests. - Inject a QEMU package that replaces qemu-kvm with a full emulator. - Monkey-patch the test script to wait longer for the VM to boot, since it's slow on full emulation. 1200 seconds, double the previous value. The patch method is not bulletproof, but better than maintaining forks of nixpkgs. - Set systemd's DefaultTimeoutStartSec=15min, so nix's "backdoor" test service doesn't time out on the slow boot. --- .gitlab-ci.yml | 18 ++++++++++++------ tests/lib/config.nix | 8 ++++++++ tests/lib/pkgs.nokvm.nix | 31 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 tests/lib/pkgs.nokvm.nix diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e5b6aa..ac6f54b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,41 +1,47 @@ +before_script: + # report CPU info so we can monitor if real KVM becomes available. create /dev/kvm to fool nix + - cat /proc/cpuinfo + - ls -l /dev/kvm || true + - touch /dev/kvm + nixos-intern: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz" script: - - nix-build tests/intern.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/intern.nix nixos-extern: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz" script: - - nix-build tests/extern.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/extern.nix nixos-clamav: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz" script: - - nix-build tests/clamav.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/clamav.nix nixos-unstable-intern: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz" script: - - nix-build tests/intern.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/intern.nix nixos-unstable-extern: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz" script: - - nix-build tests/extern.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/extern.nix nixos-unstable-clamav: image: nixos/nix variables: NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz" script: - - nix-build tests/clamav.nix + - nix-build --arg pkgs 'import tests/lib/pkgs.nokvm.nix' tests/clamav.nix diff --git a/tests/lib/config.nix b/tests/lib/config.nix index 1d56ad1..b247c66 100644 --- a/tests/lib/config.nix +++ b/tests/lib/config.nix @@ -1,3 +1,11 @@ { security.dhparams.defaultBitSize = 16; # really low for quicker tests + + # For slow non-kvm tests. + # nixos/modules/testing/test-instrumentation.nix also sets this. I don't know if there's a better way than etc to override theirs. + environment.etc."systemd/system.conf.d/bigdefaulttimeout.conf".text = '' + [Manager] + # Allow extremely slow start (default for test-VMs is 5 minutes) + DefaultTimeoutStartSec=15min + ''; } diff --git a/tests/lib/pkgs.nokvm.nix b/tests/lib/pkgs.nokvm.nix new file mode 100644 index 0000000..fa13fde --- /dev/null +++ b/tests/lib/pkgs.nokvm.nix @@ -0,0 +1,31 @@ +let + pkgs = (import { system = builtins.currentSystem; config = {}; }); + patchedMachinePM = pkgs.writeTextFile { + name = "Machine.pm.patched-to-wait-longer-for-vm"; + text = builtins.replaceStrings ["alarm 600;"] ["alarm 1200;"] (builtins.readFile (+"/nixos/lib/test-driver/Machine.pm")); + }; +in +(pkgs // { + qemu_test = with pkgs; stdenv.mkDerivation { + name = "qemu_test_no_kvm"; + buildInputs = [ coreutils qemu_test ]; + inherit qemu_test; + inherit coreutils; + builder = builtins.toFile "builder.sh" '' + PATH=$coreutils/bin:$PATH + mkdir -p $out/bin + cp $qemu_test/bin/* $out/bin/ + ln -sf $out/bin/qemu-system-${stdenv.hostPlatform.qemuArch} $out/bin/qemu-kvm + ''; + }; + stdenv = pkgs.stdenv // { + mkDerivation = args: (pkgs.stdenv.mkDerivation (args // ( + pkgs.lib.optionalAttrs (args.name == "nixos-test-driver") { + installPhase = args.installPhase + '' + rm $libDir/Machine.pm + cp ${patchedMachinePM} $libDir/Machine.pm + ''; + } + ))); + }; +}) From 93660eabcdd6ff2ccc8cb2fecb3ed9098ee3de82 Mon Sep 17 00:00:00 2001 From: Joey Hewitt Date: Sat, 6 Jul 2019 03:31:24 -0600 Subject: [PATCH 3/4] fixes to tests - restructure rspamd config. It's nicer now, and it was getting overridden the old way. - "scan_mime_parts = false" apparently must be used in rspamd for ClamAV to work - refactor the clamav test a bit for cleanliness - wait for rspamd and clamd sockets to open, before testing - use clamdscan for speed, and verify that the virus was found - verify msmtp returns virus scan result --- mail-server/rspamd.nix | 29 ++++++++++++++++------------- tests/clamav.nix | 24 ++++++++++++++++-------- tests/extern.nix | 5 ++++- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/mail-server/rspamd.nix b/mail-server/rspamd.nix index 55fe21a..47fe33b 100644 --- a/mail-server/rspamd.nix +++ b/mail-server/rspamd.nix @@ -27,19 +27,22 @@ in config = with cfg; lib.mkIf enable { services.rspamd = { enable = true; - extraConfig = '' - extended_spam_headers = yes; - '' + (lib.optionalString cfg.virusScanning '' - antivirus { - clamav { - action = "reject"; - symbol = "CLAM_VIRUS"; - type = "clamav"; - log_clean = true; - servers = "/run/clamav/clamd.ctl"; - } - } - ''); + inherit debug; + locals = { + "milter_headers.conf" = { text = '' + extended_spam_headers = yes; + ''; }; + "antivirus.conf" = lib.mkIf cfg.virusScanning { text = '' + clamav { + action = "reject"; + symbol = "CLAM_VIRUS"; + type = "clamav"; + log_clean = true; + servers = "/run/clamav/clamd.ctl"; + scan_mime_parts = false; # scan mail as a whole unit, not parts. seems to be needed to work at all + } + ''; }; + }; workers.rspamd_proxy = { type = "rspamd_proxy"; diff --git a/tests/clamav.nix b/tests/clamav.nix index f53de4c..434b196 100644 --- a/tests/clamav.nix +++ b/tests/clamav.nix @@ -125,10 +125,15 @@ import { }; "root/.msmtprc" = { text = '' - account test2 + defaults + tls on + tls_certcheck off + + account user2 host ${serverIP} port 587 from user@example2.com + auth on user user@example2.com password user2 ''; @@ -169,7 +174,7 @@ import { X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* --Apple-Mail=_2689C63E-FD18-4E4D-8822-54797BDA9607-- ''; - "root/email2".text = '' + "root/safe-email".text = '' From: User To: User1 Cc: @@ -187,13 +192,17 @@ import { }; }; - testScript = + testScript = { nodes, ... }: '' startAll; $server->waitForUnit("multi-user.target"); $client->waitForUnit("multi-user.target"); + # TODO put this blocking into the systemd units? I am not sure if rspamd already waits for the clamd socket. + $server->waitUntilSucceeds("timeout 1 ${nodes.server.pkgs.netcat}/bin/nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ \$? -eq 124 ]"); + $server->waitUntilSucceeds("timeout 1 ${nodes.server.pkgs.netcat}/bin/nc -U /run/clamav/clamd.ctl < /dev/null; [ \$? -eq 124 ]"); + $client->execute("cp -p /etc/root/.* ~/"); $client->succeed("mkdir -p ~/mail"); $client->succeed("ls -la ~/ >&2"); @@ -206,7 +215,7 @@ import { # Verify that mail can be sent and received before testing virus scanner $client->execute("rm ~/mail/*"); - $client->succeed("msmtp -a test2 --tls=on --tls-certcheck=off --auth=on user1\@example.com < /etc/root/email2 >&2"); + $client->succeed("msmtp -a user2 user1\@example.com < /etc/root/safe-email >&2"); # give the mail server some time to process the mail $server->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]'); $client->execute("rm ~/mail/*"); @@ -214,13 +223,12 @@ import { $client->succeed("fetchmail -v >&2"); $client->execute("rm ~/mail/*"); - subtest "virus scan file", sub { - $server->fail("clamscan --follow-file-symlinks=2 -r /etc/root/ >&2"); + $server->succeed("clamdscan \$(readlink -f /etc/root/eicar.com.txt) | grep \"Txt\\.Malware\\.Agent-1787597 FOUND\" >&2"); }; - subtest "virus scanner", sub { - $client->fail("msmtp -a test2 --tls=on --tls-certcheck=off --auth=on user1\@example.com < /etc/root/virus-email >&2"); + subtest "virus scan email", sub { + $client->succeed("msmtp -a user2 user1\@example.com < /etc/root/virus-email 2>&1 | grep \"server message: 554 5\\.7\\.1 clamav: virus found: .*\\(Eicar\\|EICAR\\)\" >&2"); # for some reason this ID is nondetermistic... # give the mail server some time to process the mail $server->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]'); }; diff --git a/tests/extern.nix b/tests/extern.nix index 4b5b91f..78a5266 100644 --- a/tests/extern.nix +++ b/tests/extern.nix @@ -275,13 +275,16 @@ import { }; }; - testScript = + testScript = { nodes, ... }: '' startAll; $server->waitForUnit("multi-user.target"); $client->waitForUnit("multi-user.target"); + # TODO put this blocking into the systemd units? + $server->waitUntilSucceeds("timeout 1 ${nodes.server.pkgs.netcat}/bin/nc -U /run/rspamd/rspamd-milter.sock < /dev/null; [ \$? -eq 124 ]"); + $client->execute("cp -p /etc/root/.* ~/"); $client->succeed("mkdir -p ~/mail"); $client->succeed("ls -la ~/ >&2"); From 7e718e0e33cc3a9ae38f88a66d51c36ef44e51cb Mon Sep 17 00:00:00 2001 From: Joey Hewitt Date: Sat, 6 Jul 2019 06:55:52 -0600 Subject: [PATCH 4/4] dkim: transition to PermissionsStartOnly=false That's how nixpkgs-unstable is now, so to be compatible with both we have to force that setting. Use systemd tmpfiles to provision directory with correct owner. --- mail-server/opendkim.nix | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/mail-server/opendkim.nix b/mail-server/opendkim.nix index d060323..33e2e06 100644 --- a/mail-server/opendkim.nix +++ b/mail-server/opendkim.nix @@ -40,16 +40,6 @@ let fi ''; createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.domains); - create_dkim_cert = - '' - # Create dkim dir - mkdir -p "${cfg.dkimKeyDirectory}" - chown ${dkimUser}:${dkimGroup} "${cfg.dkimKeyDirectory}" - - ${createAllCerts} - - chown -R ${dkimUser}:${dkimGroup} "${cfg.dkimKeyDirectory}" - ''; keyTable = pkgs.writeText "opendkim-KeyTable" (lib.concatStringsSep "\n" (lib.flip map cfg.domains @@ -80,11 +70,17 @@ in }; users.users = optionalAttrs (config.services.postfix.user == "postfix") { - postfix.extraGroups = [ "${config.services.opendkim.group}" ]; + postfix.extraGroups = [ "${dkimGroup}" ]; }; systemd.services.opendkim = { - preStart = create_dkim_cert; - serviceConfig.ExecStart = lib.mkForce "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; + preStart = lib.mkForce createAllCerts; + serviceConfig = { + ExecStart = lib.mkForce "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; + PermissionsStartOnly = lib.mkForce false; + }; }; + systemd.tmpfiles.rules = [ + "d '${cfg.dkimKeyDirectory}' - ${dkimUser} ${dkimGroup} - -" + ]; }; -} \ No newline at end of file +}