diff options
author | alyaeanyx <alexandra.hollmeier@mailbox.org> | 2022-03-26 22:54:02 +0100 |
---|---|---|
committer | alyaeanyx <alexandra.hollmeier@mailbox.org> | 2022-04-08 11:39:09 +0200 |
commit | 0c066f0d0e1ce6739a9a2f1e11429ddc22d8c7ba (patch) | |
tree | 18afea87dd4de58d11180f53f976b12b8a4a303f /nixos/modules/services/networking/openconnect.nix | |
parent | 9c27834e3268fbb98cff85de893b1c9ac6aa1650 (diff) |
nixos/openconnect: add module
Diffstat (limited to 'nixos/modules/services/networking/openconnect.nix')
-rw-r--r-- | nixos/modules/services/networking/openconnect.nix | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/openconnect.nix b/nixos/modules/services/networking/openconnect.nix new file mode 100644 index 0000000000000..7b2ef48e1c42a --- /dev/null +++ b/nixos/modules/services/networking/openconnect.nix @@ -0,0 +1,135 @@ +{ config, lib, options, pkgs, ... }: +with lib; +let + cfg = config.networking.openconnect; + openconnect = cfg.package; + pkcs11 = types.strMatching "pkcs11:.+" // { + name = "pkcs11"; + description = "PKCS#11 URI"; + }; + interfaceOptions = { + options = { + gateway = mkOption { + description = "Gateway server to connect to."; + example = "gateway.example.com"; + type = types.str; + }; + + protocol = mkOption { + description = "Protocol to use."; + example = "anyconnect"; + type = + types.enum [ "anyconnect" "array" "nc" "pulse" "gp" "f5" "fortinet" ]; + }; + + user = mkOption { + description = "Username to authenticate with."; + example = "example-user"; + type = types.nullOr types.str; + }; + + # Note: It does not make sense to provide a way to declaratively + # set an authentication cookie, because they have to be requested + # for every new connection and would only work once. + passwordFile = mkOption { + description = '' + File containing the password to authenticate with. This + is passed to <code>openconnect</code> via the + <code>--passwd-on-stdin</code> option. + ''; + default = null; + example = "/var/lib/secrets/openconnect-passwd"; + type = types.nullOr types.path; + }; + + certificate = mkOption { + description = "Certificate to authenticate with."; + default = null; + example = "/var/lib/secrets/openconnect_certificate.pem"; + type = with types; nullOr (either path pkcs11); + }; + + privateKey = mkOption { + description = "Private key to authenticate with."; + example = "/var/lib/secrets/openconnect_private_key.pem"; + default = null; + type = with types; nullOr (either path pkcs11); + }; + + extraOptions = mkOption { + description = '' + Extra config to be appended to the interface config. It should + contain long-format options as would be accepted on the command + line by <code>openconnect</code> + (see https://www.infradead.org/openconnect/manual.html). + Non-key-value options like <code>deflate</code> can be used by + declaring them as booleans, i. e. <code>deflate = true;</code>. + ''; + default = { }; + example = { + compression = "stateless"; + + no-http-keepalive = true; + no-dtls = true; + }; + type = with types; attrsOf (either str bool); + }; + }; + }; + generateExtraConfig = extra_cfg: + strings.concatStringsSep "\n" (attrsets.mapAttrsToList + (name: value: if (value == true) then name else "${name}=${value}") + (attrsets.filterAttrs (_: value: value != false) extra_cfg)); + generateConfig = name: icfg: + pkgs.writeText "config" '' + interface=${name} + ${optionalString (icfg.user != null) "user=${icfg.user}"} + ${optionalString (icfg.passwordFile != null) "passwd-on-stdin"} + ${optionalString (icfg.certificate != null) + "certificate=${icfg.certificate}"} + ${optionalString (icfg.privateKey != null) "sslkey=${icfg.privateKey}"} + + ${generateExtraConfig icfg.extraOptions} + ''; + generateUnit = name: icfg: { + description = "OpenConnect Interface - ${name}"; + requires = [ "network-online.target" ]; + after = [ "network.target" "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + ExecStart = "${openconnect}/bin/openconnect --config=${ + generateConfig name icfg + } ${icfg.gateway}"; + StandardInput = "file:${icfg.passwordFile}"; + }; + }; +in { + options.networking.openconnect = { + package = mkPackageOption pkgs "openconnect" { }; + + interfaces = mkOption { + description = "OpenConnect interfaces."; + default = { }; + example = { + openconnect0 = { + gateway = "gateway.example.com"; + protocol = "anyconnect"; + user = "example-user"; + passwordFile = "/var/lib/secrets/openconnect-passwd"; + }; + }; + type = with types; attrsOf (submodule interfaceOptions); + }; + }; + + config = { + systemd.services = mapAttrs' (name: value: { + name = "openconnect-${name}"; + value = generateUnit name value; + }) cfg.interfaces; + }; + + meta.maintainers = with maintainers; [ alyaeanyx ]; +} |