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; [ kmod iproute iptables utillinux ]; # XXX Linux
122 wants = [ "keys.target" ];
123 after = [ "network-online.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