summaryrefslogtreecommitdiff
path: root/hostnix/elmo/email.nix
blob: ee169f27afe5d7157881af960212b4e654f822e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
{ config, pkgs, ... }:

{
  imports = [ ./dyndns.nix ];

  systemd.tmpfiles.rules = [
    "d /var/lib/postfix/tls 0770 root root"
  ];

  security.acme.certs."${config.networking.fqdn}".postRun = ''
    rm -rf /var/lib/postfix/tls/new
    mkdir /var/lib/postfix/tls/new
    cp -a fullchain.pem key.pem /var/lib/postfix/tls/new/
    systemctl start postfix-tls-rotate
  '';

  systemd.services.postfix-tls-rotate = {
    requires = [ "network-online.target" ];
    after = [ "network-online.target" ];
    unitConfig = {
      OnFailure = "status-email@%n.service";
    };
    serviceConfig = {
      Type = "oneshot";
      # Not really necessary indirection but interesting to try out. Note we
      # must run as root (not DynamicUser) to run systemctl.
      LoadCredential = [ "dyndns:/var/secrets/dyndns/" ];
    };
    environment = {
      "DYNDNS" = "%d/dyndns";
    };
    script = ''
      cd /var/lib/postfix/tls

      publish() {
        fqdn=${config.networking.fqdn}
        tlsfps_fqdn=_tlsfps.''${fqdn%%.*}.dynamic.''${fqdn#*.}

        ${pkgs.dnsutils}/bin/nsupdate -v -k ''${DYNDNS}_$(< ''${DYNDNS}_basename).private <<.
      update delete $tlsfps_fqdn. TXT
      $(
        for cert in */fullchain.pem; do
          echo -n "update add $tlsfps_fqdn. 300 TXT "
          ${pkgs.openssl}/bin/openssl x509 -noout -fingerprint -sha256 -in "$cert" | cut -d= -f2
        done
      )
      send
      .
      }

      # If a certificate is next, we must have been invoked by our timer;
      # rotate it to live.
      if [[ -d next ]]; then
        rm -rf prev
        mv live prev
        mv next live
        systemctl reload postfix
      # If a certificate is new then publish it.
      elif [[ -d new ]]; then
        publish
        # We'll run again in at least an hour, after the postfix master picks up
        # the new TLS fingerprints. But if this is the first run (there are no
        # live certificates), rotate immediately.
        if [[ -d live ]]; then
          mv new next
        else
          mv new live
          systemctl reload postfix
        fi
      fi
    '';
  };

  systemd.timers.postfix-tls-rotate = {
    wantedBy = [ "multi-user.target" ];
    timerConfig = {
      OnBootSec = "2h";
      OnUnitInactiveSec = "2h";
    };
  };

  services.postfix = {
    enable = true;
    hostname = config.networking.fqdn;
    relayHost = "smtp.mou.fo";
    relayPort = 587;
    sslCert = "/var/lib/postfix/tls/live/fullchain.pem";
    sslKey = "/var/lib/postfix/tls/live/key.pem";
    extraAliases = ''
      root: joe
      joe: joe@mou.fo
    '';
    config = {
      smtp_tls_security_level = "encrypt";
      smtp_tls_session_cache_database = "btree:\${data_directory}/smtp_scache";
      message_size_limit = "51200000";
      default_destination_rate_delay = "1s";
    };
  };
}