summary refs log tree commit diff
path: root/nixos/modules/services/security
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/security')
-rw-r--r--nixos/modules/services/security/clamav.nix13
-rw-r--r--nixos/modules/services/security/hologram-agent.nix7
-rw-r--r--nixos/modules/services/security/hologram-server.nix38
-rw-r--r--nixos/modules/services/security/physlock.nix64
-rw-r--r--nixos/modules/services/security/tor.nix138
-rw-r--r--nixos/modules/services/security/torify.nix2
-rw-r--r--nixos/modules/services/security/torsocks.nix2
-rw-r--r--nixos/modules/services/security/usbguard.nix4
8 files changed, 219 insertions, 49 deletions
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index f71f30fee97a..4161c61ed375 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -76,8 +76,9 @@ in
     };
   };
 
-  config = mkIf cfg.updater.enable or cfg.daemon.enable {
+  config = mkIf (cfg.updater.enable || cfg.daemon.enable) {
     environment.systemPackages = [ pkg ];
+
     users.extraUsers = singleton {
       name = clamavUser;
       uid = config.ids.uids.clamav;
@@ -94,10 +95,10 @@ in
     environment.etc."clamav/freshclam.conf".source = freshclamConfigFile;
     environment.etc."clamav/clamd.conf".source = clamdConfigFile;
 
-    systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
+    systemd.services.clamav-daemon = optionalAttrs cfg.daemon.enable {
       description = "ClamAV daemon (clamd)";
-      after = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
-      requires = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
+      after = optional cfg.updater.enable "clamav-freshclam.service";
+      requires = optional cfg.updater.enable "clamav-freshclam.service";
       wantedBy = [ "multi-user.target" ];
       restartTriggers = [ clamdConfigFile ];
 
@@ -115,7 +116,7 @@ in
       };
     };
 
-    systemd.timers.clamav-freshclam = mkIf cfg.updater.enable {
+    systemd.timers.clamav-freshclam = optionalAttrs cfg.updater.enable {
       description = "Timer for ClamAV virus database updater (freshclam)";
       wantedBy = [ "timers.target" ];
       timerConfig = {
@@ -124,7 +125,7 @@ in
       };
     };
 
-    systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
+    systemd.services.clamav-freshclam = optionalAttrs cfg.updater.enable {
       description = "ClamAV virus database updater (freshclam)";
       restartTriggers = [ freshclamConfigFile ];
 
diff --git a/nixos/modules/services/security/hologram-agent.nix b/nixos/modules/services/security/hologram-agent.nix
index 6c53a2df6306..39ed506f7617 100644
--- a/nixos/modules/services/security/hologram-agent.nix
+++ b/nixos/modules/services/security/hologram-agent.nix
@@ -35,10 +35,9 @@ in {
   config = mkIf cfg.enable {
     boot.kernelModules = [ "dummy" ];
 
-    networking.interfaces.dummy0 = {
-      ipAddress = "169.254.169.254";
-      prefixLength = 32;
-    };
+    networking.interfaces.dummy0.ipv4.addresses = [
+      { address = "169.254.169.254"; prefixLength = 32; }
+    ];
 
     systemd.services.hologram-agent = {
       description = "Provide EC2 instance credentials to machines outside of EC2";
diff --git a/nixos/modules/services/security/hologram-server.nix b/nixos/modules/services/security/hologram-server.nix
index e267fed27955..bad02c7440ba 100644
--- a/nixos/modules/services/security/hologram-server.nix
+++ b/nixos/modules/services/security/hologram-server.nix
@@ -12,16 +12,20 @@ let
         dn       = cfg.ldapBindDN;
         password = cfg.ldapBindPassword;
       };
-      insecureldap = cfg.ldapInsecure;
-      userattr     = cfg.ldapUserAttr;
-      baseDN       = cfg.ldapBaseDN;
+      insecureldap    = cfg.ldapInsecure;
+      userattr        = cfg.ldapUserAttr;
+      baseDN          = cfg.ldapBaseDN;
+      enableldapRoles = cfg.enableLdapRoles;
+      roleAttr        = cfg.roleAttr;
+      groupClassAttr  = cfg.groupClassAttr;
     };
     aws = {
       account     = cfg.awsAccount;
       defaultrole = cfg.awsDefaultRole;
     };
-    stats  = cfg.statsAddress;
-    listen = cfg.listenAddress;
+    stats        = cfg.statsAddress;
+    listen       = cfg.listenAddress;
+    cachetimeout = cfg.cacheTimeoutSeconds;
   });
 in {
   options = {
@@ -70,6 +74,24 @@ in {
         description = "Password of account to use to query the LDAP server";
       };
 
+      enableLdapRoles = mkOption {
+        type        = types.bool;
+        default     = false;
+        description = "Whether to assign user roles based on the user's LDAP group memberships";
+      };
+
+      groupClassAttr = mkOption {
+        type = types.str;
+        default = "groupOfNames";
+        description = "The objectclass attribute to search for groups when enableLdapRoles is true";
+      };
+
+      roleAttr = mkOption {
+        type        = types.str;
+        default     = "businessCategory";
+        description = "Which LDAP group attribute to search for authorized role ARNs";
+      };
+
       awsAccount = mkOption {
         type        = types.str;
         description = "AWS account number";
@@ -85,6 +107,12 @@ in {
         default     = "";
         description = "Address of statsd server";
       };
+
+      cacheTimeoutSeconds = mkOption {
+        type        = types.int;
+        default     = 3600;
+        description = "How often (in seconds) to refresh the LDAP cache";
+      };
     };
   };
 
diff --git a/nixos/modules/services/security/physlock.nix b/nixos/modules/services/security/physlock.nix
index 30224d7fc6ba..97fbd6aae6e0 100644
--- a/nixos/modules/services/security/physlock.nix
+++ b/nixos/modules/services/security/physlock.nix
@@ -30,6 +30,20 @@ in
         '';
       };
 
+      allowAnyUser = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to allow any user to lock the screen. This will install a
+          setuid wrapper to allow any user to start physlock as root, which
+          is a minor security risk. Call the physlock binary to use this instead
+          of using the systemd service.
+
+          Note that you might need to relog to have the correct binary in your
+          PATH upon changing this option.
+        '';
+      };
+
       disableSysRq = mkOption {
         type = types.bool;
         default = true;
@@ -79,28 +93,36 @@ in
 
   ###### implementation
 
-  config = mkIf cfg.enable {
-
-    # for physlock -l and physlock -L
-    environment.systemPackages = [ pkgs.physlock ];
-
-    systemd.services."physlock" = {
-      enable = true;
-      description = "Physlock";
-      wantedBy = optional cfg.lockOn.suspend   "suspend.target"
-              ++ optional cfg.lockOn.hibernate "hibernate.target"
-              ++ cfg.lockOn.extraTargets;
-      before   = optional cfg.lockOn.suspend   "systemd-suspend.service"
-              ++ optional cfg.lockOn.hibernate "systemd-hibernate.service"
-              ++ cfg.lockOn.extraTargets;
-      serviceConfig.Type = "forking";
-      script = ''
-        ${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}
-      '';
-    };
+  config = mkIf cfg.enable (mkMerge [
+    {
+
+      # for physlock -l and physlock -L
+      environment.systemPackages = [ pkgs.physlock ];
+
+      systemd.services."physlock" = {
+        enable = true;
+        description = "Physlock";
+        wantedBy = optional cfg.lockOn.suspend   "suspend.target"
+                ++ optional cfg.lockOn.hibernate "hibernate.target"
+                ++ cfg.lockOn.extraTargets;
+        before   = optional cfg.lockOn.suspend   "systemd-suspend.service"
+                ++ optional cfg.lockOn.hibernate "systemd-hibernate.service"
+                ++ cfg.lockOn.extraTargets;
+        serviceConfig = {
+          Type = "forking";
+          ExecStart = "${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}";
+        };
+      };
 
-    security.pam.services.physlock = {};
+      security.pam.services.physlock = {};
 
-  };
+    }
+
+    (mkIf cfg.allowAnyUser {
+
+      security.wrappers.physlock = { source = "${pkgs.physlock}/bin/physlock"; user = "root"; };
+
+    })
+  ]);
 
 }
diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
index bc79d9f2a590..806252f49b8d 100644
--- a/nixos/modules/services/security/tor.nix
+++ b/nixos/modules/services/security/tor.nix
@@ -5,10 +5,31 @@ with lib;
 let
   cfg = config.services.tor;
   torDirectory = "/var/lib/tor";
+  torRunDirectory = "/run/tor";
 
   opt    = name: value: optionalString (value != null) "${name} ${value}";
   optint = name: value: optionalString (value != null && value != 0)    "${name} ${toString value}";
 
+  isolationOptions = {
+    type = types.listOf (types.enum [
+      "IsolateClientAddr"
+      "IsolateSOCKSAuth"
+      "IsolateClientProtocol"
+      "IsolateDestPort"
+      "IsolateDestAddr"
+    ]);
+    default = [];
+    example = [
+      "IsolateClientAddr"
+      "IsolateSOCKSAuth"
+      "IsolateClientProtocol"
+      "IsolateDestPort"
+      "IsolateDestAddr"
+    ];
+    description = "Tor isolation options";
+  };
+
+
   torRc = ''
     User tor
     DataDirectory ${torDirectory}
@@ -18,12 +39,23 @@ let
     ''}
 
     ${optint "ControlPort" cfg.controlPort}
+    ${optionalString cfg.controlSocket.enable "ControlSocket ${torRunDirectory}/control GroupWritable RelaxDirModeCheck"}
   ''
   # Client connection config
-  + optionalString cfg.client.enable  ''
-    SOCKSPort ${cfg.client.socksListenAddress} IsolateDestAddr
+  + optionalString cfg.client.enable ''
+    SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions}
     SOCKSPort ${cfg.client.socksListenAddressFaster}
     ${opt "SocksPolicy" cfg.client.socksPolicy}
+
+    ${optionalString cfg.client.transparentProxy.enable ''
+    TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions}
+    ''}
+
+    ${optionalString cfg.client.dns.enable ''
+    DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions}
+    AutomapHostsOnResolve 1
+    AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes}
+    ''}
   ''
   # Relay config
   + optionalString cfg.relay.enable ''
@@ -58,6 +90,9 @@ let
     ${flip concatMapStrings v.map (p: ''
       HiddenServicePort ${toString p.port} ${p.destination}
     '')}
+    ${optionalString (v.authorizeClient != null) ''
+      HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames}
+    ''}
   ''))
   + cfg.extraConfig;
 
@@ -107,6 +142,17 @@ in
         '';
       };
 
+      controlSocket = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Wheter to enable Tor control socket. Control socket is created
+            in <literal>${torRunDirectory}/control</literal>
+          '';
+        };
+      };
+
       client = {
         enable = mkOption {
           type = types.bool;
@@ -154,6 +200,55 @@ in
           '';
         };
 
+        socksIsolationOptions = mkOption (isolationOptions // {
+          default = ["IsolateDestAddr"];
+        });
+
+        transparentProxy = {
+          enable = mkOption {
+            type = types.bool;
+            default = false;
+            description = "Whether to enable tor transaprent proxy";
+          };
+
+          listenAddress = mkOption {
+            type = types.str;
+            default = "127.0.0.1:9040";
+            example = "192.168.0.1:9040";
+            description = ''
+              Bind transparent proxy to this address.
+            '';
+          };
+
+          isolationOptions = mkOption isolationOptions;
+        };
+
+        dns = {
+          enable = mkOption {
+            type = types.bool;
+            default = false;
+            description = "Whether to enable tor dns resolver";
+          };
+
+          listenAddress = mkOption {
+            type = types.str;
+            default = "127.0.0.1:9053";
+            example = "192.168.0.1:9053";
+            description = ''
+              Bind tor dns to this address.
+            '';
+          };
+
+          isolationOptions = mkOption isolationOptions;
+
+          automapHostsSuffixes = mkOption {
+            type = types.listOf types.str;
+            default = [".onion" ".exit"];
+            example = [".onion"];
+            description = "List of suffixes to use with automapHostsOnResolve";
+          };
+        };
+
         privoxy.enable = mkOption {
           type = types.bool;
           default = true;
@@ -540,6 +635,33 @@ in
                }));
              };
 
+             authorizeClient = mkOption {
+               default = null;
+               description = "If configured, the hidden service is accessible for authorized clients only.";
+               type = types.nullOr (types.submodule ({config, ...}: {
+
+                 options = {
+
+                   authType = mkOption {
+                     type = types.enum [ "basic" "stealth" ];
+                     description = ''
+                       Either <literal>"basic"</literal> for a general-purpose authorization protocol
+                       or <literal>"stealth"</literal> for a less scalable protocol
+                       that also hides service activity from unauthorized clients.
+                     '';
+                   };
+
+                   clientNames = mkOption {
+                     type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+");
+                     description = ''
+                       Only clients that are listed here are authorized to access the hidden service.
+                       Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>.
+                       Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>.
+                     '';
+                   };
+                 };
+               }));
+             };
           };
 
           config = {
@@ -581,14 +703,10 @@ in
         after    = [ "network.target" ];
         restartTriggers = [ torRcFile ];
 
-        # Translated from the upstream contrib/dist/tor.service.in
-        preStart = ''
-          install -o tor -g tor -d ${torDirectory}/onion
-          ${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config
-        '';
-
         serviceConfig =
           { Type         = "simple";
+            # Translated from the upstream contrib/dist/tor.service.in
+            ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
             ExecStart    = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
             ExecReload   = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
             KillSignal   = "SIGINT";
@@ -603,11 +721,13 @@ in
             #   DeviceAllow /dev/urandom r
             # .. but we can't specify DeviceAllow multiple times. 'closed'
             # is close enough.
+            RuntimeDirectory        = "tor";
+            StateDirectory          = [ "tor" "tor/onion" ];
             PrivateTmp              = "yes";
             DevicePolicy            = "closed";
             InaccessibleDirectories = "/home";
             ReadOnlyDirectories     = "/";
-            ReadWriteDirectories    = torDirectory;
+            ReadWriteDirectories    = [torDirectory torRunDirectory];
             NoNewPrivileges         = "yes";
           };
       };
diff --git a/nixos/modules/services/security/torify.nix b/nixos/modules/services/security/torify.nix
index a29cb3f33dae..08da726437ea 100644
--- a/nixos/modules/services/security/torify.nix
+++ b/nixos/modules/services/security/torify.nix
@@ -7,7 +7,7 @@ let
   torify = pkgs.writeTextFile {
     name = "tsocks";
     text = ''
-        #!${pkgs.stdenv.shell}
+        #!${pkgs.runtimeShell}
         TSOCKS_CONF_FILE=${pkgs.writeText "tsocks.conf" cfg.tsocks.config} LD_PRELOAD="${pkgs.tsocks}/lib/libtsocks.so $LD_PRELOAD" "$@"
     '';
     executable = true;
diff --git a/nixos/modules/services/security/torsocks.nix b/nixos/modules/services/security/torsocks.nix
index 1b5a05b21e77..c60c745443bc 100644
--- a/nixos/modules/services/security/torsocks.nix
+++ b/nixos/modules/services/security/torsocks.nix
@@ -23,7 +23,7 @@ let
   wrapTorsocks = name: server: pkgs.writeTextFile {
     name = name;
     text = ''
-        #!${pkgs.stdenv.shell}
+        #!${pkgs.runtimeShell}
         TORSOCKS_CONF_FILE=${pkgs.writeText "torsocks.conf" (configFile server)} ${pkgs.torsocks}/bin/torsocks "$@"
     '';
     executable = true;
diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix
index 1f2c56a9efa1..5d469cabe2cb 100644
--- a/nixos/modules/services/security/usbguard.nix
+++ b/nixos/modules/services/security/usbguard.nix
@@ -56,7 +56,7 @@ in {
       };
 
       rules = mkOption {
-        type = types.nullOr types.str;
+        type = types.nullOr types.lines;
         default = null;
         example = ''
           allow with-interface equals { 08:*:* }
@@ -192,7 +192,7 @@ in {
 
       serviceConfig = {
         Type = "simple";
-        ExecStart = ''${pkgs.usbguard}/bin/usbguard-daemon -d -k -c ${daemonConfFile}'';
+        ExecStart = ''${pkgs.usbguard}/bin/usbguard-daemon -P -d -k -c ${daemonConfFile}'';
         Restart = "on-failure";
       };
     };