at 18.09-beta 6.1 kB view raw
1{ config, lib, pkgs, ... }: 2 3let 4 inherit (lib) mkOption types; 5 cfg = config.security.dhparams; 6 7 bitType = types.addCheck types.int (b: b >= 16) // { 8 name = "bits"; 9 description = "integer of at least 16 bits"; 10 }; 11 12 paramsSubmodule = { name, config, ... }: { 13 options.bits = mkOption { 14 type = bitType; 15 default = cfg.defaultBitSize; 16 description = '' 17 The bit size for the prime that is used during a Diffie-Hellman 18 key exchange. 19 ''; 20 }; 21 22 options.path = mkOption { 23 type = types.path; 24 readOnly = true; 25 description = '' 26 The resulting path of the generated Diffie-Hellman parameters 27 file for other services to reference. This could be either a 28 store path or a file inside the directory specified by 29 <option>security.dhparams.path</option>. 30 ''; 31 }; 32 33 config.path = let 34 generated = pkgs.runCommand "dhparams-${name}.pem" { 35 nativeBuildInputs = [ pkgs.openssl ]; 36 } "openssl dhparam -out \"$out\" ${toString config.bits}"; 37 in if cfg.stateful then "${cfg.path}/${name}.pem" else generated; 38 }; 39 40in { 41 options = { 42 security.dhparams = { 43 enable = mkOption { 44 type = types.bool; 45 default = false; 46 description = '' 47 Whether to generate new DH params and clean up old DH params. 48 ''; 49 }; 50 51 params = mkOption { 52 type = with types; let 53 coerce = bits: { inherit bits; }; 54 in attrsOf (coercedTo int coerce (submodule paramsSubmodule)); 55 default = {}; 56 example = lib.literalExample "{ nginx.bits = 3072; }"; 57 description = '' 58 Diffie-Hellman parameters to generate. 59 60 The value is the size (in bits) of the DH params to generate. The 61 generated DH params path can be found in 62 <literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>. 63 64 <note><para>The name of the DH params is taken as being the name of 65 the service it serves and the params will be generated before the 66 said service is started.</para></note> 67 68 <warning><para>If you are removing all dhparams from this list, you 69 have to leave <option>security.dhparams.enable</option> for at 70 least one activation in order to have them be cleaned up. This also 71 means if you rollback to a version without any dhparams the 72 existing ones won't be cleaned up. Of course this only applies if 73 <option>security.dhparams.stateful</option> is 74 <literal>true</literal>.</para></warning> 75 76 <note><title>For module implementers:</title><para>It's recommended 77 to not set a specific bit size here, so that users can easily 78 override this by setting 79 <option>security.dhparams.defaultBitSize</option>.</para></note> 80 ''; 81 }; 82 83 stateful = mkOption { 84 type = types.bool; 85 default = true; 86 description = '' 87 Whether generation of Diffie-Hellman parameters should be stateful or 88 not. If this is enabled, PEM-encoded files for Diffie-Hellman 89 parameters are placed in the directory specified by 90 <option>security.dhparams.path</option>. Otherwise the files are 91 created within the Nix store. 92 93 <note><para>If this is <literal>false</literal> the resulting store 94 path will be non-deterministic and will be rebuilt every time the 95 <package>openssl</package> package changes.</para></note> 96 ''; 97 }; 98 99 defaultBitSize = mkOption { 100 type = bitType; 101 default = 2048; 102 description = '' 103 This allows to override the default bit size for all of the 104 Diffie-Hellman parameters set in 105 <option>security.dhparams.params</option>. 106 ''; 107 }; 108 109 path = mkOption { 110 type = types.str; 111 default = "/var/lib/dhparams"; 112 description = '' 113 Path to the directory in which Diffie-Hellman parameters will be 114 stored. This only is relevant if 115 <option>security.dhparams.stateful</option> is 116 <literal>true</literal>. 117 ''; 118 }; 119 }; 120 }; 121 122 config = lib.mkIf (cfg.enable && cfg.stateful) { 123 systemd.services = { 124 dhparams-init = { 125 description = "Clean Up Old Diffie-Hellman Parameters"; 126 127 # Clean up even when no DH params is set 128 wantedBy = [ "multi-user.target" ]; 129 130 serviceConfig.RemainAfterExit = true; 131 serviceConfig.Type = "oneshot"; 132 133 script = '' 134 if [ ! -d ${cfg.path} ]; then 135 mkdir -p ${cfg.path} 136 fi 137 138 # Remove old dhparams 139 for file in ${cfg.path}/*; do 140 if [ ! -f "$file" ]; then 141 continue 142 fi 143 ${lib.concatStrings (lib.mapAttrsToList (name: { bits, path, ... }: '' 144 if [ "$file" = ${lib.escapeShellArg path} ] && \ 145 ${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \ 146 | head -n 1 | grep "(${toString bits} bit)" > /dev/null; then 147 continue 148 fi 149 '') cfg.params)} 150 rm $file 151 done 152 153 # TODO: Ideally this would be removing the *former* cfg.path, though 154 # this does not seem really important as changes to it are quite 155 # unlikely 156 rmdir --ignore-fail-on-non-empty ${cfg.path} 157 ''; 158 }; 159 } // lib.mapAttrs' (name: { bits, path, ... }: lib.nameValuePair "dhparams-gen-${name}" { 160 description = "Generate Diffie-Hellman Parameters for ${name}"; 161 after = [ "dhparams-init.service" ]; 162 before = [ "${name}.service" ]; 163 wantedBy = [ "multi-user.target" ]; 164 unitConfig.ConditionPathExists = "!${path}"; 165 serviceConfig.Type = "oneshot"; 166 script = '' 167 mkdir -p ${lib.escapeShellArg cfg.path} 168 ${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \ 169 ${toString bits} 170 ''; 171 }) cfg.params; 172 }; 173}