1{ config, lib, pkgs, ... }: 2 3let 4 5 inherit (builtins) toFile; 6 inherit (lib) concatMapStringsSep concatStringsSep mapAttrsToList 7 mkIf mkEnableOption mkOption types; 8 9 cfg = config.services.strongswan; 10 11 ipsecSecrets = secrets: toFile "ipsec.secrets" ( 12 concatMapStringsSep "\n" (f: "include ${f}") secrets 13 ); 14 15 ipsecConf = {setup, connections, ca}: 16 let 17 # https://wiki.strongswan.org/projects/strongswan/wiki/IpsecConf 18 makeSections = type: sections: concatStringsSep "\n\n" ( 19 mapAttrsToList (sec: attrs: 20 "${type} ${sec}\n" + 21 (concatStringsSep "\n" ( mapAttrsToList (k: v: " ${k}=${v}") attrs )) 22 ) sections 23 ); 24 setupConf = makeSections "config" { inherit setup; }; 25 connectionsConf = makeSections "conn" connections; 26 caConf = makeSections "ca" ca; 27 28 in 29 builtins.toFile "ipsec.conf" '' 30 ${setupConf} 31 ${connectionsConf} 32 ${caConf} 33 ''; 34 35 strongswanConf = {setup, connections, ca, secrets}: toFile "strongswan.conf" '' 36 charon { 37 plugins { 38 stroke { 39 secrets_file = ${ipsecSecrets secrets} 40 } 41 } 42 } 43 44 starter { 45 config_file = ${ipsecConf { inherit setup connections ca; }} 46 } 47 ''; 48 49in 50{ 51 options.services.strongswan = { 52 enable = mkEnableOption "strongSwan"; 53 54 secrets = mkOption { 55 type = types.listOf types.path; 56 default = []; 57 example = [ "/run/keys/ipsec-foo.secret" ]; 58 description = '' 59 A list of paths to IPSec secret files. These 60 files will be included into the main ipsec.secrets file with 61 the <literal>include</literal> directive. It is safer if these 62 paths are absolute. 63 ''; 64 }; 65 66 setup = mkOption { 67 type = types.attrsOf types.str; 68 default = {}; 69 example = { cachecrls = "yes"; strictcrlpolicy = "yes"; }; 70 description = '' 71 A set of options for the config setup section of the 72 <filename>ipsec.conf</filename> file. Defines general 73 configuration parameters. 74 ''; 75 }; 76 77 connections = mkOption { 78 type = types.attrsOf (types.attrsOf types.str); 79 default = {}; 80 example = { 81 "%default" = { 82 keyexchange = "ikev2"; 83 keyingtries = "1"; 84 }; 85 roadwarrior = { 86 auto = "add"; 87 leftcert = "/run/keys/moonCert.pem"; 88 leftid = "@moon.strongswan.org"; 89 leftsubnet = "10.1.0.0/16"; 90 right = "%any"; 91 }; 92 }; 93 description = '' 94 A set of connections and their options for the conn xxx 95 sections of the <filename>ipsec.conf</filename> file. 96 ''; 97 }; 98 99 ca = mkOption { 100 type = types.attrsOf (types.attrsOf types.str); 101 default = {}; 102 example = { 103 strongswan = { 104 auto = "add"; 105 cacert = "/run/keys/strongswanCert.pem"; 106 crluri = "http://crl2.strongswan.org/strongswan.crl"; 107 }; 108 }; 109 description = '' 110 A set of CAs (certification authorities) and their options for 111 the ca xxx sections of the <filename>ipsec.conf</filename> 112 file. 113 ''; 114 }; 115 }; 116 117 config = with cfg; mkIf enable { 118 systemd.services.strongswan = { 119 description = "strongSwan IPSec Service"; 120 wantedBy = [ "multi-user.target" ]; 121 path = with pkgs; [ config.system.sbin.modprobe iproute iptables utillinux ]; # XXX Linux 122 wants = [ "keys.target" ]; 123 after = [ "network.target" "keys.target" ]; 124 environment = { 125 STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secrets; }; 126 }; 127 serviceConfig = { 128 ExecStart = "${pkgs.strongswan}/sbin/ipsec start --nofork"; 129 }; 130 }; 131 }; 132} 133