at 23.11-pre 4.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.opendkim; 8 9 defaultSock = "local:/run/opendkim/opendkim.sock"; 10 11 keyFile = "${cfg.keyPath}/${cfg.selector}.private"; 12 13 args = [ "-f" "-l" 14 "-p" cfg.socket 15 "-d" cfg.domains 16 "-k" keyFile 17 "-s" cfg.selector 18 ] ++ optionals (cfg.configFile != null) [ "-x" cfg.configFile ]; 19 20in { 21 imports = [ 22 (mkRenamedOptionModule [ "services" "opendkim" "keyFile" ] [ "services" "opendkim" "keyPath" ]) 23 ]; 24 25 ###### interface 26 27 options = { 28 29 services.opendkim = { 30 31 enable = mkOption { 32 type = types.bool; 33 default = false; 34 description = lib.mdDoc "Whether to enable the OpenDKIM sender authentication system."; 35 }; 36 37 socket = mkOption { 38 type = types.str; 39 default = defaultSock; 40 description = lib.mdDoc "Socket which is used for communication with OpenDKIM."; 41 }; 42 43 user = mkOption { 44 type = types.str; 45 default = "opendkim"; 46 description = lib.mdDoc "User for the daemon."; 47 }; 48 49 group = mkOption { 50 type = types.str; 51 default = "opendkim"; 52 description = lib.mdDoc "Group for the daemon."; 53 }; 54 55 domains = mkOption { 56 type = types.str; 57 default = "csl:${config.networking.hostName}"; 58 defaultText = literalExpression ''"csl:''${config.networking.hostName}"''; 59 example = "csl:example.com,mydomain.net"; 60 description = lib.mdDoc '' 61 Local domains set (see `opendkim(8)` for more information on datasets). 62 Messages from them are signed, not verified. 63 ''; 64 }; 65 66 keyPath = mkOption { 67 type = types.path; 68 description = lib.mdDoc '' 69 The path that opendkim should put its generated private keys into. 70 The DNS settings will be found in this directory with the name selector.txt. 71 ''; 72 default = "/var/lib/opendkim/keys"; 73 }; 74 75 selector = mkOption { 76 type = types.str; 77 description = lib.mdDoc "Selector to use when signing."; 78 }; 79 80 configFile = mkOption { 81 type = types.nullOr types.path; 82 default = null; 83 description = lib.mdDoc "Additional opendkim configuration."; 84 }; 85 86 }; 87 88 }; 89 90 91 ###### implementation 92 93 config = mkIf cfg.enable { 94 95 users.users = optionalAttrs (cfg.user == "opendkim") { 96 opendkim = { 97 group = cfg.group; 98 uid = config.ids.uids.opendkim; 99 }; 100 }; 101 102 users.groups = optionalAttrs (cfg.group == "opendkim") { 103 opendkim.gid = config.ids.gids.opendkim; 104 }; 105 106 environment.systemPackages = [ pkgs.opendkim ]; 107 108 systemd.tmpfiles.rules = [ 109 "d '${cfg.keyPath}' - ${cfg.user} ${cfg.group} - -" 110 ]; 111 112 systemd.services.opendkim = { 113 description = "OpenDKIM signing and verification daemon"; 114 after = [ "network.target" ]; 115 wantedBy = [ "multi-user.target" ]; 116 117 preStart = '' 118 cd "${cfg.keyPath}" 119 if ! test -f ${cfg.selector}.private; then 120 ${pkgs.opendkim}/bin/opendkim-genkey -s ${cfg.selector} -d all-domains-generic-key 121 echo "Generated OpenDKIM key! Please update your DNS settings:\n" 122 echo "-------------------------------------------------------------" 123 cat ${cfg.selector}.txt 124 echo "-------------------------------------------------------------" 125 fi 126 ''; 127 128 serviceConfig = { 129 ExecStart = "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; 130 User = cfg.user; 131 Group = cfg.group; 132 RuntimeDirectory = optional (cfg.socket == defaultSock) "opendkim"; 133 StateDirectory = "opendkim"; 134 StateDirectoryMode = "0700"; 135 ReadWritePaths = [ cfg.keyPath ]; 136 137 AmbientCapabilities = []; 138 CapabilityBoundingSet = ""; 139 DevicePolicy = "closed"; 140 LockPersonality = true; 141 MemoryDenyWriteExecute = true; 142 NoNewPrivileges = true; 143 PrivateDevices = true; 144 PrivateMounts = true; 145 PrivateTmp = true; 146 PrivateUsers = true; 147 ProtectClock = true; 148 ProtectControlGroups = true; 149 ProtectHome = true; 150 ProtectHostname = true; 151 ProtectKernelLogs = true; 152 ProtectKernelModules = true; 153 ProtectKernelTunables = true; 154 ProtectSystem = "strict"; 155 RemoveIPC = true; 156 RestrictAddressFamilies = [ "AF_INET" "AF_INET6 AF_UNIX" ]; 157 RestrictNamespaces = true; 158 RestrictRealtime = true; 159 RestrictSUIDSGID = true; 160 SystemCallArchitectures = "native"; 161 SystemCallFilter = [ "@system-service" "~@privileged @resources" ]; 162 UMask = "0077"; 163 }; 164 }; 165 166 }; 167}