zfs_unstable: 2.3.0-rc3 -> 2.3.0-rc4 (#365045)
[NixPkgs.git] / nixos / modules / services / networking / openconnect.nix
blob6660e769f48ad168a01cd490d5e3421d5a613331
2   config,
3   lib,
4   options,
5   pkgs,
6   ...
7 }:
8 with lib;
9 let
10   cfg = config.networking.openconnect;
11   openconnect = cfg.package;
12   pkcs11 = types.strMatching "pkcs11:.+" // {
13     name = "pkcs11";
14     description = "PKCS#11 URI";
15   };
16   interfaceOptions = {
17     options = {
18       autoStart = mkOption {
19         default = true;
20         description = "Whether this VPN connection should be started automatically.";
21         type = types.bool;
22       };
24       gateway = mkOption {
25         description = "Gateway server to connect to.";
26         example = "gateway.example.com";
27         type = types.str;
28       };
30       protocol = mkOption {
31         description = "Protocol to use.";
32         example = "anyconnect";
33         type = types.enum [
34           "anyconnect"
35           "array"
36           "nc"
37           "pulse"
38           "gp"
39           "f5"
40           "fortinet"
41         ];
42       };
44       user = mkOption {
45         description = "Username to authenticate with.";
46         example = "example-user";
47         type = types.nullOr types.str;
48         default = null;
49       };
51       # Note: It does not make sense to provide a way to declaratively
52       # set an authentication cookie, because they have to be requested
53       # for every new connection and would only work once.
54       passwordFile = mkOption {
55         description = ''
56           File containing the password to authenticate with. This
57           is passed to `openconnect` via the
58           `--passwd-on-stdin` option.
59         '';
60         default = null;
61         example = "/var/lib/secrets/openconnect-passwd";
62         type = types.nullOr types.path;
63       };
65       certificate = mkOption {
66         description = "Certificate to authenticate with.";
67         default = null;
68         example = "/var/lib/secrets/openconnect_certificate.pem";
69         type = with types; nullOr (either path pkcs11);
70       };
72       privateKey = mkOption {
73         description = "Private key to authenticate with.";
74         example = "/var/lib/secrets/openconnect_private_key.pem";
75         default = null;
76         type = with types; nullOr (either path pkcs11);
77       };
79       extraOptions = mkOption {
80         description = ''
81           Extra config to be appended to the interface config. It should
82           contain long-format options as would be accepted on the command
83           line by `openconnect`
84           (see https://www.infradead.org/openconnect/manual.html).
85           Non-key-value options like `deflate` can be used by
86           declaring them as booleans, i. e. `deflate = true;`.
87         '';
88         default = { };
89         example = {
90           compression = "stateless";
92           no-http-keepalive = true;
93           no-dtls = true;
94         };
95         type = with types; attrsOf (either str bool);
96       };
97     };
98   };
99   generateExtraConfig =
100     extra_cfg:
101     strings.concatStringsSep "\n" (
102       attrsets.mapAttrsToList (name: value: if (value == true) then name else "${name}=${value}") (
103         attrsets.filterAttrs (_: value: value != false) extra_cfg
104       )
105     );
106   generateConfig =
107     name: icfg:
108     pkgs.writeText "config" ''
109       interface=${name}
110       ${optionalString (icfg.protocol != null) "protocol=${icfg.protocol}"}
111       ${optionalString (icfg.user != null) "user=${icfg.user}"}
112       ${optionalString (icfg.passwordFile != null) "passwd-on-stdin"}
113       ${optionalString (icfg.certificate != null) "certificate=${icfg.certificate}"}
114       ${optionalString (icfg.privateKey != null) "sslkey=${icfg.privateKey}"}
116       ${generateExtraConfig icfg.extraOptions}
117     '';
118   generateUnit = name: icfg: {
119     description = "OpenConnect Interface - ${name}";
120     requires = [ "network-online.target" ];
121     after = [
122       "network.target"
123       "network-online.target"
124     ];
125     wantedBy = optional icfg.autoStart "multi-user.target";
127     serviceConfig = {
128       Type = "simple";
129       ExecStart = "${openconnect}/bin/openconnect --config=${generateConfig name icfg} ${icfg.gateway}";
130       StandardInput = lib.mkIf (icfg.passwordFile != null) "file:${icfg.passwordFile}";
132       ProtectHome = true;
133     };
134   };
137   options.networking.openconnect = {
138     package = mkPackageOption pkgs "openconnect" { };
140     interfaces = mkOption {
141       description = "OpenConnect interfaces.";
142       default = { };
143       example = {
144         openconnect0 = {
145           gateway = "gateway.example.com";
146           protocol = "anyconnect";
147           user = "example-user";
148           passwordFile = "/var/lib/secrets/openconnect-passwd";
149         };
150       };
151       type = with types; attrsOf (submodule interfaceOptions);
152     };
153   };
155   config = {
156     systemd.services = mapAttrs' (name: value: {
157       name = "openconnect-${name}";
158       value = generateUnit name value;
159     }) cfg.interfaces;
160   };
162   meta.maintainers = with maintainers; [ alyaeanyx ];