about summary refs log tree commit diff
path: root/nixos/modules/services/networking/spiped.nix
diff options
context:
space:
mode:
authorAustin Seipp <aseipp@pobox.com>2014-04-15 03:21:53 -0500
committerAustin Seipp <aseipp@pobox.com>2014-04-15 03:33:47 -0500
commitae207efc071ded1bc54f26c563711b496b8dbae7 (patch)
tree3938830754d23a005a6dfc3c8ad6f2c4e9062431 /nixos/modules/services/networking/spiped.nix
parent3275e47613d2ece61385fec9c2645c2d483e4286 (diff)
downloadnixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar.gz
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar.bz2
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar.lz
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar.xz
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.tar.zst
nixlib-ae207efc071ded1bc54f26c563711b496b8dbae7.zip
nixos: add spiped service module
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Diffstat (limited to 'nixos/modules/services/networking/spiped.nix')
-rw-r--r--nixos/modules/services/networking/spiped.nix212
1 files changed, 212 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/spiped.nix b/nixos/modules/services/networking/spiped.nix
new file mode 100644
index 000000000000..ec5908b182fb
--- /dev/null
+++ b/nixos/modules/services/networking/spiped.nix
@@ -0,0 +1,212 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.spiped;
+in
+{
+  options = {
+    services.spiped = mkOption {
+      type = types.attrsOf (types.submodule (
+        {
+          options = {
+            encrypt = mkOption {
+              type    = types.bool;
+              default = false;
+              description = ''
+                Take unencrypted connections from the
+                <literal>source</literal> socket and send encrypted
+                connections to the <literal>target</literal> socket.
+              '';
+            };
+
+            decrypt = mkOption {
+              type    = types.bool;
+              default = false;
+              description = ''
+                Take encrypted connections from the
+                <literal>source</literal> socket and send unencrypted
+                connections to the <literal>target</literal> socket.
+              '';
+            };
+
+            source = mkOption {
+              type    = types.str;
+              description = ''
+                Address on which spiped should listen for incoming
+                connections.  Must be in one of the following formats:
+                <literal>/absolute/path/to/unix/socket</literal>,
+                <literal>host.name:port</literal>,
+                <literal>[ip.v4.ad.dr]:port</literal> or
+                <literal>[ipv6::addr]:port</literal> - note that
+                hostnames are resolved when spiped is launched and are
+                not re-resolved later; thus if DNS entries change
+                spiped will continue to connect to the expired
+                address.
+              '';
+            };
+
+            target = mkOption {
+              type    = types.str;
+              description = "Address to which spiped should connect.";
+            };
+
+            keyfile = mkOption {
+              type    = types.path;
+              description = ''
+                Name of a file containing the spiped key. As the
+                daemon runs as the <literal>spiped</literal> user, the
+                key file must be somewhere owned by that user. By
+                default, we recommend putting the keys for any spipe
+                services in <literal>/var/lib/spiped</literal>.
+              '';
+            };
+
+            timeout = mkOption {
+              type = types.int;
+              default = 5;
+              description = ''
+                Timeout, in seconds, after which an attempt to connect to
+                the target or a protocol handshake will be aborted (and the
+                connection dropped) if not completed
+              '';
+            };
+
+            maxConns = mkOption {
+              type = types.int;
+              default = 100;
+              description = ''
+                Limit on the number of simultaneous connections allowed.
+              '';
+            };
+
+            waitForDNS = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Wait for DNS. Normally when <literal>spiped</literal> is
+                launched it resolves addresses and binds to its source
+                socket before the parent process returns; with this option
+                it will daemonize first and retry failed DNS lookups until
+                they succeed. This allows <literal>spiped</literal> to
+                launch even if DNS isn't set up yet, but at the expense of
+                losing the guarantee that once <literal>spiped</literal> has
+                finished launching it will be ready to create pipes.
+              '';
+            };
+
+            disableKeepalives = mkOption {
+              type = types.bool;
+              default = false;
+              description = "Disable transport layer keep-alives.";
+            };
+
+            weakHandshake = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Use fast/weak handshaking: This reduces the CPU time spent
+                in the initial connection setup, at the expense of losing
+                perfect forward secrecy.
+              '';
+            };
+
+            resolveRefresh = mkOption {
+              type = types.int;
+              default = 60;
+              description = ''
+                Resolution refresh time for the target socket, in seconds.
+              '';
+            };
+
+            disableReresolution = mkOption {
+              type = types.bool;
+              default = false;
+              description = "Disable target address re-resolution.";
+            };
+          };
+        }
+      ));
+
+      default = {};
+
+      example = literalExample ''
+        {
+          pipe1 =
+            { keyfile = "/var/lib/spiped/pipe1.key";
+              encrypt = true;
+              source  = "localhost:6000";
+              target  = "endpoint.example.com:7000";
+            };
+          pipe2 =
+            { keyfile = "/var/lib/spiped/pipe2.key";
+              decrypt = true;
+              source  = "0.0.0.0:7000";
+              target  = "localhost:3000";
+            };
+        }
+      '';
+
+      description = ''
+        Configuration for a secure pipe daemon. The daemon can be
+        started, stopped, or examined using
+        <literal>systemctl</literal>, under the name
+        <literal>spiped@foo</literal>.
+      '';
+    };
+  };
+
+  config = {
+    assertions = mapAttrsToList (name: c: {
+      assertion = (c.encrypt -> !c.decrypt) || (c.decrypt -> c.encrypt);
+      message   = "A pipe must either encrypt or decrypt";
+    }) cfg;
+
+    users.extraGroups.spiped.gid = config.ids.gids.spiped;
+    users.extraUsers.spiped = {
+      description = "Secure Pipe Service user";
+      group       = "spiped";
+      uid         = config.ids.uids.spiped;
+    };
+
+    systemd.services."spiped@" = {
+      description = "Secure pipe '%i'";
+      after       = [ "network.target" ];
+
+      serviceConfig = {
+        Restart   = "always";
+        User      = "spiped";
+        PermissionsStartOnly = true;
+      };
+
+      preStart  = ''
+        cd /var/lib/spiped
+        chmod -R 0660 *
+        chown -R spiped:spiped *
+      '';
+      scriptArgs = "%i";
+      script = "exec ${pkgs.spiped}/bin/spiped -F `cat /etc/spiped/$1.spec`";
+    };
+
+    system.activationScripts.spiped = optionalString (cfg != {})
+      "mkdir -p /var/lib/spiped";
+
+    # Setup spiped config files
+    environment.etc = mapAttrs' (name: cfg: nameValuePair "spiped/${name}.spec"
+      { text = concatStringsSep " "
+          [ (if cfg.encrypt then "-e" else "-d")        # Mode
+            "-s ${cfg.source}"                          # Source
+            "-t ${cfg.target}"                          # Target
+            "-k ${cfg.keyfile}"                         # Keyfile
+            "-n ${toString cfg.maxConns}"               # Max number of conns
+            "-o ${toString cfg.timeout}"                # Timeout
+            (optionalString cfg.waitForDNS "-D")        # Wait for DNS
+            (optionalString cfg.weakHandshake "-f")     # No PFS
+            (optionalString cfg.disableKeepalives "-j") # Keepalives
+            (if cfg.disableReresolution then "-R"
+              else "-r ${toString cfg.resolveRefresh}")
+          ];
+      }) cfg;
+  };
+}