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