summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/config/krb5.nix206
-rw-r--r--nixos/modules/config/krb5/default.nix367
-rw-r--r--nixos/modules/module-list.nix4
-rw-r--r--nixos/modules/services/mail/pfix-srsd.nix56
-rw-r--r--nixos/modules/services/mail/postfix.nix14
-rw-r--r--nixos/modules/services/misc/gitlab.nix3
-rw-r--r--nixos/modules/services/misc/gitlab.xml29
-rw-r--r--nixos/modules/services/misc/gogs.nix12
-rw-r--r--nixos/modules/services/network-filesystems/glusterfs.nix2
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix11
-rw-r--r--nixos/modules/services/web-servers/traefik.nix114
-rw-r--r--nixos/modules/virtualisation/ec2-amis.nix18
-rw-r--r--nixos/modules/virtualisation/grow-partition.nix7
-rw-r--r--nixos/tests/krb5/default.nix5
-rw-r--r--nixos/tests/krb5/deprecated-config.nix48
-rw-r--r--nixos/tests/krb5/example-config.nix106
16 files changed, 788 insertions, 214 deletions
diff --git a/nixos/modules/config/krb5.nix b/nixos/modules/config/krb5.nix
deleted file mode 100644
index d318b7207429..000000000000
--- a/nixos/modules/config/krb5.nix
+++ /dev/null
@@ -1,206 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.krb5;
-
-in
-
-{
-  ###### interface
-
-  options = {
-
-    krb5 = {
-
-      enable = mkOption {
-        default = false;
-        description = "Whether to enable Kerberos V.";
-      };
-
-      defaultRealm = mkOption {
-        default = "ATENA.MIT.EDU";
-        description = "Default realm.";
-      };
-
-      domainRealm = mkOption {
-        default = "atena.mit.edu";
-        description = "Default domain realm.";
-      };
-
-      kdc = mkOption {
-        default = "kerberos.mit.edu";
-        description = "Key Distribution Center";
-      };
-
-      kerberosAdminServer = mkOption {
-        default = "kerberos.mit.edu";
-        description = "Kerberos Admin Server.";
-      };
-
-    };
-
-  };
-
-  ###### implementation
-
-  config = mkIf config.krb5.enable {
-
-    environment.systemPackages = [ pkgs.krb5Full ];
-
-    environment.etc."krb5.conf".text =
-      ''
-        [libdefaults]
-            default_realm = ${cfg.defaultRealm}
-            encrypt = true
-
-        # The following krb5.conf variables are only for MIT Kerberos.
-            krb4_config = /etc/krb.conf
-            krb4_realms = /etc/krb.realms
-            kdc_timesync = 1
-            ccache_type = 4
-            forwardable = true
-            proxiable = true
-
-        # The following encryption type specification will be used by MIT Kerberos
-        # if uncommented.  In general, the defaults in the MIT Kerberos code are
-        # correct and overriding these specifications only serves to disable new
-        # encryption types as they are added, creating interoperability problems.
-
-        #   default_tgs_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-        #   default_tkt_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-        #   permitted_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-
-        # The following libdefaults parameters are only for Heimdal Kerberos.
-            v4_instance_resolve = false
-            v4_name_convert = {
-                host = {
-                    rcmd = host
-                    ftp = ftp
-                }
-                plain = {
-                    something = something-else
-                }
-            }
-            fcc-mit-ticketflags = true
-
-        [realms]
-            ${cfg.defaultRealm} = {
-                kdc = ${cfg.kdc}
-                admin_server = ${cfg.kerberosAdminServer}
-                #kpasswd_server = ${cfg.kerberosAdminServer}
-            }
-            ATHENA.MIT.EDU = {
-                kdc = kerberos.mit.edu:88
-                kdc = kerberos-1.mit.edu:88
-                kdc = kerberos-2.mit.edu:88
-                admin_server = kerberos.mit.edu
-                default_domain = mit.edu
-            }
-            MEDIA-LAB.MIT.EDU = {
-                kdc = kerberos.media.mit.edu
-                admin_server = kerberos.media.mit.edu
-            }
-            ZONE.MIT.EDU = {
-                kdc = casio.mit.edu
-                kdc = seiko.mit.edu
-                admin_server = casio.mit.edu
-            }
-            MOOF.MIT.EDU = {
-                kdc = three-headed-dogcow.mit.edu:88
-                kdc = three-headed-dogcow-1.mit.edu:88
-                admin_server = three-headed-dogcow.mit.edu
-            }
-            CSAIL.MIT.EDU = {
-                kdc = kerberos-1.csail.mit.edu
-                kdc = kerberos-2.csail.mit.edu
-                admin_server = kerberos.csail.mit.edu
-                default_domain = csail.mit.edu
-                krb524_server = krb524.csail.mit.edu
-            }
-            IHTFP.ORG = {
-                kdc = kerberos.ihtfp.org
-                admin_server = kerberos.ihtfp.org
-            }
-            GNU.ORG = {
-                kdc = kerberos.gnu.org
-                kdc = kerberos-2.gnu.org
-                kdc = kerberos-3.gnu.org
-                admin_server = kerberos.gnu.org
-            }
-            1TS.ORG = {
-                kdc = kerberos.1ts.org
-                admin_server = kerberos.1ts.org
-            }
-            GRATUITOUS.ORG = {
-                kdc = kerberos.gratuitous.org
-                admin_server = kerberos.gratuitous.org
-            }
-            DOOMCOM.ORG = {
-                kdc = kerberos.doomcom.org
-                admin_server = kerberos.doomcom.org
-            }
-            ANDREW.CMU.EDU = {
-                kdc = vice28.fs.andrew.cmu.edu
-                kdc = vice2.fs.andrew.cmu.edu
-                kdc = vice11.fs.andrew.cmu.edu
-                kdc = vice12.fs.andrew.cmu.edu
-                admin_server = vice28.fs.andrew.cmu.edu
-                default_domain = andrew.cmu.edu
-            }
-            CS.CMU.EDU = {
-                kdc = kerberos.cs.cmu.edu
-                kdc = kerberos-2.srv.cs.cmu.edu
-                admin_server = kerberos.cs.cmu.edu
-            }
-            DEMENTIA.ORG = {
-                kdc = kerberos.dementia.org
-                kdc = kerberos2.dementia.org
-                admin_server = kerberos.dementia.org
-            }
-            stanford.edu = {
-                kdc = krb5auth1.stanford.edu
-                kdc = krb5auth2.stanford.edu
-                kdc = krb5auth3.stanford.edu
-                admin_server = krb5-admin.stanford.edu
-                default_domain = stanford.edu
-            }
-
-        [domain_realm]
-            .${cfg.domainRealm} = ${cfg.defaultRealm}
-            ${cfg.domainRealm} = ${cfg.defaultRealm}
-            .mit.edu = ATHENA.MIT.EDU
-            mit.edu = ATHENA.MIT.EDU
-            .exchange.mit.edu = EXCHANGE.MIT.EDU
-            exchange.mit.edu = EXCHANGE.MIT.EDU
-            .media.mit.edu = MEDIA-LAB.MIT.EDU
-            media.mit.edu = MEDIA-LAB.MIT.EDU
-            .csail.mit.edu = CSAIL.MIT.EDU
-            csail.mit.edu = CSAIL.MIT.EDU
-            .whoi.edu = ATHENA.MIT.EDU
-            whoi.edu = ATHENA.MIT.EDU
-            .stanford.edu = stanford.edu
-
-        [logging]
-            kdc = SYSLOG:INFO:DAEMON
-            admin_server = SYSLOG:INFO:DAEMON
-            default = SYSLOG:INFO:DAEMON
-            krb4_convert = true
-            krb4_get_tickets = false
-
-        [appdefaults]
-            pam = {
-                debug = false
-                ticket_lifetime = 36000
-                renew_lifetime = 36000
-                max_timeout = 30
-                timeout_shift = 2
-                initial_timeout = 1
-            }
-      '';
-
-  };
-
-}
diff --git a/nixos/modules/config/krb5/default.nix b/nixos/modules/config/krb5/default.nix
new file mode 100644
index 000000000000..c22e99a0a2f1
--- /dev/null
+++ b/nixos/modules/config/krb5/default.nix
@@ -0,0 +1,367 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.krb5;
+
+  # This is to provide support for old configuration options (as much as is
+  # reasonable). This can be removed after 18.03 was released.
+  defaultConfig = {
+    libdefaults = optionalAttrs (cfg.defaultRealm != null)
+      { default_realm = cfg.defaultRealm; };
+
+    realms = optionalAttrs (lib.all (value: value != null) [
+      cfg.defaultRealm cfg.kdc cfg.kerberosAdminServer
+    ]) {
+      "${cfg.defaultRealm}" = {
+        kdc = cfg.kdc;
+        admin_server = cfg.kerberosAdminServer;
+      };
+    };
+
+    domain_realm = optionalAttrs (lib.all (value: value != null) [
+      cfg.domainRealm cfg.defaultRealm
+    ]) {
+      ".${cfg.domainRealm}" = cfg.defaultRealm;
+      "${cfg.domainRealm}" = cfg.defaultRealm;
+    };
+  };
+
+  mergedConfig = (recursiveUpdate defaultConfig {
+    inherit (config.krb5)
+      kerberos libdefaults realms domain_realm capaths appdefaults plugins
+      extraConfig config;
+  });
+
+  filterEmbeddedMetadata = value: if isAttrs value then
+    (filterAttrs
+      (attrName: attrValue: attrName != "_module" && attrValue != null)
+        value)
+    else value;
+
+  mkIndent = depth: concatStrings (builtins.genList (_:  " ") (2 * depth));
+
+  mkRelation = name: value: "${name} = ${mkVal { inherit value; }}";
+
+  mkVal = { value, depth ? 0 }:
+    if (value == true) then "true"
+    else if (value == false) then "false"
+    else if (isInt value) then (toString value)
+    else if (isList value) then
+      concatMapStringsSep " " mkVal { inherit value depth; }
+    else if (isAttrs value) then
+      (concatStringsSep "\n${mkIndent (depth + 1)}"
+        ([ "{" ] ++ (mapAttrsToList
+          (attrName: attrValue: let
+            mappedAttrValue = mkVal {
+              value = attrValue;
+              depth = depth + 1;
+            };
+          in "${attrName} = ${mappedAttrValue}")
+        value))) + "\n${mkIndent depth}}"
+    else value;
+
+  mkMappedAttrsOrString = value: concatMapStringsSep "\n"
+    (line: if builtins.stringLength line > 0
+      then "${mkIndent 1}${line}"
+      else line)
+    (splitString "\n"
+      (if isAttrs value then
+        concatStringsSep "\n"
+            (mapAttrsToList mkRelation value)
+        else value));
+
+in {
+
+  ###### interface
+
+  options = {
+    krb5 = {
+      enable = mkEnableOption "Whether to enable Kerberos V.";
+
+      kerberos = mkOption {
+        type = types.package;
+        default = pkgs.krb5Full;
+        defaultText = "pkgs.krb5Full";
+        example = literalExample "pkgs.heimdalFull";
+        description = ''
+          The Kerberos implementation that will be present in
+          <literal>environment.systemPackages</literal> after enabling this
+          service.
+        '';
+      };
+
+      libdefaults = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        apply = attrs: filterEmbeddedMetadata attrs;
+        example = literalExample ''
+          {
+            default_realm = "ATHENA.MIT.EDU";
+          };
+        '';
+        description = ''
+          Settings used by the Kerberos V5 library.
+        '';
+      };
+
+      realms = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "ATHENA.MIT.EDU" = {
+              admin_server = "athena.mit.edu";
+              kdc = "athena.mit.edu";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = "Realm-specific contact information and settings.";
+      };
+
+      domain_realm = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "example.com" = "EXAMPLE.COM";
+            ".example.com" = "EXAMPLE.COM";
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Map of server hostnames to Kerberos realms.
+        '';
+      };
+
+      capaths = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "ATHENA.MIT.EDU" = {
+              "EXAMPLE.COM" = ".";
+            };
+            "EXAMPLE.COM" = {
+              "ATHENA.MIT.EDU" = ".";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Authentication paths for non-hierarchical cross-realm authentication.
+        '';
+      };
+
+      appdefaults = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            pam = {
+              debug = false;
+              ticket_lifetime = 36000;
+              renew_lifetime = 36000;
+              max_timeout = 30;
+              timeout_shift = 2;
+              initial_timeout = 1;
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Settings used by some Kerberos V5 applications.
+        '';
+      };
+
+      plugins = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            ccselect = {
+              disable = "k5identity";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Controls plugin module registration.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = with types; nullOr lines;
+        default = null;
+        example = ''
+          [logging]
+            kdc          = SYSLOG:NOTICE
+            admin_server = SYSLOG:NOTICE
+            default      = SYSLOG:NOTICE
+        '';
+        description = ''
+          These lines go to the end of <literal>krb5.conf</literal> verbatim.
+          <literal>krb5.conf</literal> may include any of the relations that are
+          valid for <literal>kdc.conf</literal> (see <literal>man
+          kdc.conf</literal>), but it is not a recommended practice.
+        '';
+      };
+
+      config = mkOption {
+        type = with types; nullOr lines;
+        default = null;
+        example = ''
+          [libdefaults]
+            default_realm = EXAMPLE.COM
+
+          [realms]
+            EXAMPLE.COM = {
+              admin_server = kerberos.example.com
+              kdc = kerberos.example.com
+              default_principal_flags = +preauth
+            }
+
+          [domain_realm]
+            example.com  = EXAMPLE.COM
+            .example.com = EXAMPLE.COM
+
+          [logging]
+            kdc          = SYSLOG:NOTICE
+            admin_server = SYSLOG:NOTICE
+            default      = SYSLOG:NOTICE
+        '';
+        description = ''
+          Verbatim <literal>krb5.conf</literal> configuration.  Note that this
+          is mutually exclusive with configuration via
+          <literal>libdefaults</literal>, <literal>realms</literal>,
+          <literal>domain_realm</literal>, <literal>capaths</literal>,
+          <literal>appdefaults</literal>, <literal>plugins</literal> and
+          <literal>extraConfig</literal> configuration options.  Consult
+          <literal>man krb5.conf</literal> for documentation.
+        '';
+      };
+
+      defaultRealm = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "ATHENA.MIT.EDU";
+        description = ''
+          DEPRECATED, please use
+          <literal>krb5.libdefaults.default_realm</literal>.
+        '';
+      };
+
+      domainRealm = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "athena.mit.edu";
+        description = ''
+          DEPRECATED, please create a map of server hostnames to Kerberos realms
+          in <literal>krb5.domain_realm</literal>.
+        '';
+      };
+
+      kdc = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "kerberos.mit.edu";
+        description = ''
+          DEPRECATED, please pass a <literal>kdc</literal> attribute to a realm
+          in <literal>krb5.realms</literal>.
+        '';
+      };
+
+      kerberosAdminServer = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "kerberos.mit.edu";
+        description = ''
+          DEPRECATED, please pass an <literal>admin_server</literal> attribute
+          to a realm in <literal>krb5.realms</literal>.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.kerberos ];
+
+    environment.etc."krb5.conf".text = if isString cfg.config
+      then cfg.config
+      else (''
+        [libdefaults]
+        ${mkMappedAttrsOrString mergedConfig.libdefaults}
+
+        [realms]
+        ${mkMappedAttrsOrString mergedConfig.realms}
+
+        [domain_realm]
+        ${mkMappedAttrsOrString mergedConfig.domain_realm}
+
+        [capaths]
+        ${mkMappedAttrsOrString mergedConfig.capaths}
+
+        [appdefaults]
+        ${mkMappedAttrsOrString mergedConfig.appdefaults}
+
+        [plugins]
+        ${mkMappedAttrsOrString mergedConfig.plugins}
+      '' + optionalString (mergedConfig.extraConfig != null)
+          ("\n" + mergedConfig.extraConfig));
+
+    warnings = flatten [
+      (optional (cfg.defaultRealm != null) ''
+        The option krb5.defaultRealm is deprecated, please use
+        krb5.libdefaults.default_realm.
+      '')
+      (optional (cfg.domainRealm != null) ''
+        The option krb5.domainRealm is deprecated, please use krb5.domain_realm.
+      '')
+      (optional (cfg.kdc != null) ''
+        The option krb5.kdc is deprecated, please pass a kdc attribute to a
+        realm in krb5.realms.
+      '')
+      (optional (cfg.kerberosAdminServer != null) ''
+        The option krb5.kerberosAdminServer is deprecated, please pass an
+        admin_server attribute to a realm in krb5.realms.
+      '')
+    ];
+
+    assertions = [
+      { assertion = !((builtins.any (value: value != null) [
+            cfg.defaultRealm cfg.domainRealm cfg.kdc cfg.kerberosAdminServer
+          ]) && ((builtins.any (value: value != {}) [
+              cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+              cfg.appdefaults cfg.plugins
+            ]) || (builtins.any (value: value != null) [
+              cfg.config cfg.extraConfig
+            ])));
+        message = ''
+          Configuration of krb5.conf by deprecated options is mutually exclusive
+          with configuration by section.  Please migrate your config using the
+          attributes suggested in the warnings.
+        '';
+      }
+      { assertion = !(cfg.config != null
+          && ((builtins.any (value: value != {}) [
+              cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+              cfg.appdefaults cfg.plugins
+            ]) || (builtins.any (value: value != null) [
+              cfg.extraConfig cfg.defaultRealm cfg.domainRealm cfg.kdc
+              cfg.kerberosAdminServer
+            ])));
+        message = ''
+          Configuration of krb5.conf using krb.config is mutually exclusive with
+          configuration by section.  If you want to mix the two, you can pass
+          lines to any configuration section or lines to krb5.extraConfig.
+        '';
+      }
+    ];
+  };
+}
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index e849e634fc96..8ac7e5b52d69 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -9,7 +9,7 @@
   ./config/fonts/ghostscript.nix
   ./config/gnu.nix
   ./config/i18n.nix
-  ./config/krb5.nix
+  ./config/krb5/default.nix
   ./config/ldap.nix
   ./config/networking.nix
   ./config/no-x-libs.nix
@@ -269,6 +269,7 @@
   ./services/mail/offlineimap.nix
   ./services/mail/opendkim.nix
   ./services/mail/opensmtpd.nix
+  ./services/mail/pfix-srsd.nix
   ./services/mail/postfix.nix
   ./services/mail/postsrsd.nix
   ./services/mail/postgrey.nix
@@ -621,6 +622,7 @@
   ./services/web-servers/phpfpm/default.nix
   ./services/web-servers/shellinabox.nix
   ./services/web-servers/tomcat.nix
+  ./services/web-servers/traefik.nix
   ./services/web-servers/uwsgi.nix
   ./services/web-servers/varnish/default.nix
   ./services/web-servers/winstone.nix
diff --git a/nixos/modules/services/mail/pfix-srsd.nix b/nixos/modules/services/mail/pfix-srsd.nix
new file mode 100644
index 000000000000..ab5f4c39e8c2
--- /dev/null
+++ b/nixos/modules/services/mail/pfix-srsd.nix
@@ -0,0 +1,56 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.pfix-srsd = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Whether to run the postfix sender rewriting scheme daemon.";
+      };
+
+      domain = mkOption {
+        description = "The domain for which to enable srs";
+        type = types.str;
+        example = "example.com";
+      };
+
+      secretsFile = mkOption {
+        description = ''
+          The secret data used to encode the SRS address.
+          to generate, use a command like:
+          <literal>for n in $(seq 5); do dd if=/dev/urandom count=1 bs=1024 status=none | sha256sum | sed 's/  -$//' | sed 's/^/          /'; done</literal>
+        '';
+        type = types.path;
+        default = "/var/lib/pfix-srsd/secrets";
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf config.services.pfix-srsd.enable {
+    environment = {
+      systemPackages = [ pkgs.pfixtools ];
+    };
+
+    systemd.services."pfix-srsd" = {
+      description = "Postfix sender rewriting scheme daemon";
+      before = [ "postfix.service" ];
+      #note that we use requires rather than wants because postfix
+      #is unable to process (almost) all mail without srsd
+      requiredBy = [ "postfix.service" ];
+      serviceConfig = {
+        Type = "forking";
+        PIDFile = "/var/run/pfix-srsd.pid";
+        ExecStart = "${pkgs.pfixtools}/bin/pfix-srsd -p /var/run/pfix-srsd.pid -I ${config.services.pfix-srsd.domain} ${config.services.pfix-srsd.secretsFile}";
+      };
+    };
+  };
+}
\ No newline at end of file
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index d88a38def82c..ad4e58149847 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -79,6 +79,12 @@ let
   // optionalAttrs haveTransport { transport_maps = "hash:/etc/postfix/transport"; }
   // optionalAttrs haveVirtual { virtual_alias_maps = "${cfg.virtualMapType}:/etc/postfix/virtual"; }
   // optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; }
+  // optionalAttrs cfg.useSrs {
+    sender_canonical_maps = "tcp:127.0.0.1:10001";
+    sender_canonical_classes = "envelope_sender";
+    recipient_canonical_maps = "tcp:127.0.0.1:10002";
+    recipient_canonical_classes= "envelope_recipient";
+  }
   // optionalAttrs cfg.enableHeaderChecks { header_checks = "regexp:/etc/postfix/header_checks"; }
   // optionalAttrs (cfg.sslCert != "") {
     smtp_tls_CAfile = cfg.sslCACert;
@@ -626,6 +632,12 @@ in
         description = "Maps to be compiled and placed into /var/lib/postfix/conf.";
       };
 
+      useSrs = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable sender rewriting scheme";
+      };
+
     };
 
   };
@@ -646,6 +658,8 @@ in
         systemPackages = [ pkgs.postfix ];
       };
 
+      services.pfix-srsd.enable = config.services.postfix.useSrs;
+
       services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
         program = "sendmail";
         source = "${pkgs.postfix}/bin/sendmail";
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 280c66d0aaf2..0fa9e417785f 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -414,7 +414,7 @@ in {
           Make sure the secret is an RSA private key in PEM format. You can
           generate one with
 
-          openssl genrsa 2048openssl genpkey -algorithm RSA -out - -pkeyopt rsa_keygen_bits:2048
+          openssl genrsa 2048
         '';
       };
 
@@ -567,6 +567,7 @@ in {
         mkdir -p ${cfg.statePath}/log
         mkdir -p ${cfg.statePath}/tmp/pids
         mkdir -p ${cfg.statePath}/tmp/sockets
+        mkdir -p ${cfg.statePath}/shell
 
         rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks
         mkdir -p ${cfg.statePath}/config
diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml
index f9636f8e1278..4b00f50abd63 100644
--- a/nixos/modules/services/misc/gitlab.xml
+++ b/nixos/modules/services/misc/gitlab.xml
@@ -66,6 +66,35 @@ services.gitlab = {
     db = "uPgq1gtwwHiatiuE0YHqbGa5lEIXH7fMsvuTNgdzJi8P0Dg12gibTzBQbq5LT7PNzcc3BP9P1snHVnduqtGF43PgrQtU7XL93ts6gqe9CBNhjtaqUwutQUDkygP5NrV6";
     secret = "devzJ0Tz0POiDBlrpWmcsjjrLaltyiAdS8TtgT9YNBOoUcDsfppiY3IXZjMVtKgXrFImIennFGOpPN8IkP8ATXpRgDD5rxVnKuTTwYQaci2NtaV1XxOQGjdIE50VGsR3";
     otp = "e1GATJVuS2sUh7jxiPzZPre4qtzGGaS22FR50Xs1TerRVdgI3CBVUi5XYtQ38W4xFeS4mDqi5cQjExE838iViSzCdcG19XSL6qNsfokQP9JugwiftmhmCadtsnHErBMI";
+    jws = ''
+      -----BEGIN RSA PRIVATE KEY-----
+      MIIEpAIBAAKCAQEArrtx4oHKwXoqUbMNqnHgAklnnuDon3XG5LJB35yPsXKv/8GK
+      ke92wkI+s1Xkvsp8tg9BIY/7c6YK4SR07EWL+dB5qwctsWR2Q8z+/BKmTx9D99pm
+      hnsjuNIXTF7BXrx3RX6BxZpH5Vzzh9nCwWKT/JCFqtwH7afNGGL7aMf+hdaiUg/Q
+      SD05yRObioiO4iXDolsJOhrnbZvlzVHl1ZYxFJv0H6/Snc0BBA9Fl/3uj6ANpbjP
+      eXF1SnJCqT87bj46r5NdVauzaRxAsIfqHroHK4UZ98X5LjGQFGvSqTvyjPBS4I1i
+      s7VJU28ObuutHxIxSlH0ibn4HZqWmKWlTS652wIDAQABAoIBAGtPcUTTw2sJlR3x
+      4k2wfAvLexkHNbZhBdKEa5JiO5mWPuLKwUiZEY2CU7Gd6csG3oqNWcm7/IjtC7dz
+      xV8p4yp8T4yq7vQIJ93B80NqTLtBD2QTvG2RCMJEPMzJUObWxkVmyVpLQyZo7KOd
+      KE/OM+aj94OUeEYLjRkSCScz1Gvq/qFG/nAy7KPCmN9JDHuhX26WHo2Rr1OnPNT/
+      7diph0bB9F3b8gjjNTqXDrpdAqVOgR/PsjEBz6DMY+bdyMIn87q2yfmMexxRofN6
+      LulpzSaa6Yup8N8H6PzVO6KAkQuf1aQRj0sMwGk1IZEnj6I0KbuHIZkw21Nc6sf2
+      ESFySDECgYEA1PnCNn5tmLnwe62Ttmrzl20zIS3Me1gUVJ1NTfr6+ai0I9iMYU21
+      5czuAjJPm9JKQF2vY8UAaCj2ZoObtHa/anb3xsCd8NXoM3iJq5JDoXI1ldz3Y+ad
+      U/bZUg1DLRvAniTuXmw9iOTwTwPxlDIGq5k+wG2Xmi1lk7zH8ezr9BMCgYEA0gfk
+      EhgcmPH8Z5cU3YYwOdt6HSJOM0OyN4k/5gnkv+HYVoJTj02gkrJmLr+mi1ugKj46
+      7huYO9TVnrKP21tmbaSv1dp5hS3letVRIxSloEtVGXmmdvJvBRzDWos+G+KcvADi
+      fFCz6w8v9NmO40CB7y/3SxTmSiSxDQeoi9LhDBkCgYEAsPgMWm25sfOnkY2NNUIv
+      wT8bAlHlHQT2d8zx5H9NttBpR3P0ShJhuF8N0sNthSQ7ULrIN5YGHYcUH+DyLAWU
+      TuomP3/kfa+xL7vUYb269tdJEYs4AkoppxBySoz8qenqpz422D0G8M6TpIS5Y5Qi
+      GMrQ6uLl21YnlpiCaFOfSQMCgYEAmZxj1kgEQmhZrnn1LL/D7czz1vMMNrpAUhXz
+      wg9iWmSXkU3oR1sDIceQrIhHCo2M6thwyU0tXjUft93pEQocM/zLDaGoVxtmRxxV
+      J08mg8IVD3jFoyFUyWxsBIDqgAKRl38eJsXvkO+ep3mm49Z+Ma3nM+apN3j2dQ0w
+      3HLzXaECgYBFLMEAboVFwi5+MZjGvqtpg2PVTisfuJy2eYnPwHs+AXUgi/xRNFjI
+      YHEa7UBPb5TEPSzWImQpETi2P5ywcUYL1EbN/nqPWmjFnat8wVmJtV4sUpJhubF4
+      Vqm9LxIWc1uQ1q1HDCejRIxIN3aSH+wgRS3Kcj8kCTIoXd1aERb04g==
+      -----END RSA PRIVATE KEY-----
+    '';
   };
   extraConfig = {
     gitlab = {
diff --git a/nixos/modules/services/misc/gogs.nix b/nixos/modules/services/misc/gogs.nix
index d6e827a53fdf..f6d326e43d94 100644
--- a/nixos/modules/services/misc/gogs.nix
+++ b/nixos/modules/services/misc/gogs.nix
@@ -25,6 +25,7 @@ let
     HTTP_ADDR = ${cfg.httpAddress}
     HTTP_PORT = ${toString cfg.httpPort}
     ROOT_URL = ${cfg.rootUrl}
+    STATIC_ROOT_PATH = ${cfg.staticRootPath}
 
     [session]
     COOKIE_NAME = session
@@ -175,6 +176,13 @@ in
         '';
       };
 
+      staticRootPath = mkOption {
+        type = types.str;
+        default = "${pkgs.gogs.data}";
+        example = "/var/lib/gogs/data";
+        description = "Upper level of template and static files path.";
+      };
+
       extraConfig = mkOption {
         type = types.str;
         default = "";
@@ -195,6 +203,8 @@ in
         runConfig = "${cfg.stateDir}/custom/conf/app.ini";
         secretKey = "${cfg.stateDir}/custom/conf/secret_key";
       in ''
+        mkdir -p ${cfg.stateDir}
+
         # copy custom configuration and generate a random secret key if needed
         ${optionalString (cfg.useWizard == false) ''
           mkdir -p ${cfg.stateDir}/custom/conf
@@ -240,7 +250,7 @@ in
       };
     };
 
-    users = {
+    users = mkIf (cfg.user == "gogs") {
       extraUsers.gogs = {
         description = "Go Git Service";
         uid = config.ids.uids.gogs;
diff --git a/nixos/modules/services/network-filesystems/glusterfs.nix b/nixos/modules/services/network-filesystems/glusterfs.nix
index 15777d45f785..8ac9f801dcb8 100644
--- a/nixos/modules/services/network-filesystems/glusterfs.nix
+++ b/nixos/modules/services/network-filesystems/glusterfs.nix
@@ -156,7 +156,7 @@ in
       wantedBy = [ "multi-user.target" ];
 
       requires = lib.optional cfg.useRpcbind "rpcbind.service";
-      after = [ "network.target" "local-fs.target" ] ++ lib.optional cfg.useRpcbind [ "rpcbind.service" ];
+      after = [ "network.target" "local-fs.target" ] ++ lib.optional cfg.useRpcbind "rpcbind.service";
 
       preStart = ''
         install -m 0755 -d /var/log/glusterfs
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
index 36e5efecf431..d4a695ef5880 100644
--- a/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -7,7 +7,7 @@ let
 
   ipfsFlags = toString ([
     (optionalString  cfg.autoMount                   "--mount")
-    (optionalString  cfg.autoMigrate                 "--migrate")
+    #(optionalString  cfg.autoMigrate                 "--migrate")
     (optionalString  cfg.enableGC                    "--enable-gc")
     (optionalString (cfg.serviceFdlimit != null)     "--manage-fdlimit=false")
     (optionalString (cfg.defaultMode == "offline")   "--offline")
@@ -36,6 +36,7 @@ let
 
   baseService = recursiveUpdate commonEnv {
     wants = [ "ipfs-init.service" ];
+    # NB: migration must be performed prior to pre-start, else we get the failure message!
     preStart = ''
       ipfs repo fsck # workaround for BUG #4212 (https://github.com/ipfs/go-ipfs/issues/4214)
       ipfs --local config Addresses.API ${cfg.apiAddress}
@@ -97,11 +98,17 @@ in {
         description = "systemd service that is enabled by default";
       };
 
+      /*
       autoMigrate = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether IPFS should try to migrate the file system automatically";
+        description = ''
+          Whether IPFS should try to migrate the file system automatically.
+
+          The daemon will need to be able to download a binary from https://ipfs.io to perform the migration.
+        '';
       };
+      */
 
       autoMount = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/web-servers/traefik.nix b/nixos/modules/services/web-servers/traefik.nix
new file mode 100644
index 000000000000..53f5a3c3c2be
--- /dev/null
+++ b/nixos/modules/services/web-servers/traefik.nix
@@ -0,0 +1,114 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.traefik;
+  configFile =
+    if cfg.configFile == null then
+      pkgs.runCommand "config.toml" {
+        buildInputs = [ pkgs.remarshal ];
+      } ''
+        remarshal -if json -of toml \
+          < ${pkgs.writeText "config.json" (builtins.toJSON cfg.configOptions)} \
+          > $out
+      ''
+    else cfg.configFile;
+
+in {
+  options.services.traefik = {
+    enable = mkEnableOption "Traefik web server";
+
+    configFile = mkOption {
+      default = null;
+      example = /path/to/config.toml;
+      type = types.nullOr types.path;
+      description = ''
+        Path to verbatim traefik.toml to use.
+        (Using that option has precedence over <literal>configOptions</literal>)
+      '';
+    };
+
+    configOptions = mkOption {
+      description = ''
+        Config for Traefik.
+      '';
+      type = types.attrs;
+      default = {
+        defaultEntryPoints = ["http"];
+        entryPoints.http.address = ":80";
+      };
+      example = {
+        defaultEntrypoints = [ "http" ];
+        web.address = ":8080";
+        entryPoints.http.address = ":80";
+
+        file = {};
+        frontends = {
+          frontend1 = {
+            backend = "backend1";
+            routes.test_1.rule = "Host:localhost";
+          };
+        };
+        backends.backend1 = {
+          servers.server1.url = "http://localhost:8000";
+        };
+      };
+    };
+
+    dataDir = mkOption {
+      default = "/var/lib/traefik";
+      type = types.path;
+      description = ''
+      Location for any persistent data traefik creates, ie. acme
+      '';
+    };
+
+    package = mkOption {
+      default = pkgs.traefik;
+      defaultText = "pkgs.traefik";
+      type = types.package;
+      description = "Traefik package to use.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.traefik = {
+      description = "Traefik web server";
+      after = [ "network-online.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        PermissionsStartOnly = true;
+        ExecStart = ''${cfg.package.bin}/bin/traefik --configfile=${configFile}'';
+        ExecStartPre = [
+          ''${pkgs.coreutils}/bin/mkdir -p "${cfg.dataDir}"''
+          ''${pkgs.coreutils}/bin/install -d -m700 --owner traefik --group traefik "${cfg.dataDir}"''
+        ];
+        Type = "simple";
+        User = "traefik";
+        Group = "traefik";
+        Restart = "on-failure";
+        StartLimitInterval = 86400;
+        StartLimitBurst = 5;
+        AmbientCapabilities = "cap_net_bind_service";
+        CapabilityBoundingSet = "cap_net_bind_service";
+        NoNewPrivileges = true;
+        LimitNPROC = 64;
+        LimitNOFILE = 1048576;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        ProtectHome = true;
+        ProtectSystem = "full";
+        ReadWriteDirectories = cfg.dataDir;
+      };
+    };
+
+    users.extraUsers.traefik = {
+      group = "traefik";
+      home = cfg.dataDir;
+      createHome = true;
+    };
+
+    users.extraGroups.traefik = {};
+  };
+}
diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix
index 745518f85972..14826b6272f7 100644
--- a/nixos/modules/virtualisation/ec2-amis.nix
+++ b/nixos/modules/virtualisation/ec2-amis.nix
@@ -223,5 +223,21 @@ let self = {
   "17.03".us-west-2.hvm-ebs = "ami-a93daac9";
   "17.03".us-west-2.hvm-s3 = "ami-5139ae31";
 
-  latest = self."17.03";
+  # 17.09.1483.d0f0657ca0
+  "17.09".eu-west-1.hvm-ebs = "ami-cf33e7b6";
+  "17.09".eu-west-2.hvm-ebs = "ami-7d061419";
+  "17.09".eu-central-1.hvm-ebs = "ami-7548fa1a";
+  "17.09".us-east-1.hvm-ebs = "ami-6f669d15";
+  "17.09".us-east-2.hvm-ebs = "ami-cbe1ccae";
+  "17.09".us-west-1.hvm-ebs = "ami-9d95a5fd";
+  "17.09".us-west-2.hvm-ebs = "ami-d3956fab";
+  "17.09".ca-central-1.hvm-ebs = "ami-ee4ef78a";
+  "17.09".ap-southeast-1.hvm-ebs = "ami-1dfc807e";
+  "17.09".ap-southeast-2.hvm-ebs = "ami-dcb350be";
+  "17.09".ap-northeast-1.hvm-ebs = "ami-00ec3d66";
+  "17.09".ap-northeast-2.hvm-ebs = "ami-1107dd7f";
+  "17.09".sa-east-1.hvm-ebs = "ami-0377086f";
+  "17.09".ap-south-1.hvm-ebs = "ami-4a064625";
+
+  latest = self."17.09";
 }; in self
diff --git a/nixos/modules/virtualisation/grow-partition.nix b/nixos/modules/virtualisation/grow-partition.nix
index 5039118d78ee..2cb932d208f0 100644
--- a/nixos/modules/virtualisation/grow-partition.nix
+++ b/nixos/modules/virtualisation/grow-partition.nix
@@ -24,7 +24,12 @@ with lib;
       copy_bin_and_libs ${pkgs.gnused}/bin/sed
       copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
       copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk
-      cp -v ${pkgs.cloud-utils}/bin/.growpart-wrapped $out/bin/growpart
+
+      substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \
+        --replace "${pkgs.bash}/bin/sh" "/bin/sh" \
+        --replace "awk" "gawk" \
+        --replace "sed" "gnused"
+
       ln -s sed $out/bin/gnused
     '';
 
diff --git a/nixos/tests/krb5/default.nix b/nixos/tests/krb5/default.nix
new file mode 100644
index 000000000000..dd5b2f37202e
--- /dev/null
+++ b/nixos/tests/krb5/default.nix
@@ -0,0 +1,5 @@
+{ system ? builtins.currentSystem }:
+{
+  example-config = import ./example-config.nix { inherit system; };
+  deprecated-config = import ./deprecated-config.nix { inherit system; };
+}
diff --git a/nixos/tests/krb5/deprecated-config.nix b/nixos/tests/krb5/deprecated-config.nix
new file mode 100644
index 000000000000..980b3e762dc6
--- /dev/null
+++ b/nixos/tests/krb5/deprecated-config.nix
@@ -0,0 +1,48 @@
+# Verifies that the configuration suggested in deprecated example values
+# will result in the expected output.
+
+import ../make-test.nix ({ pkgs, ...} : {
+  name = "krb5-with-deprecated-config";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ eqyiel ];
+  };
+
+  machine =
+    { config, pkgs, ... }: {
+      krb5 = {
+        enable = true;
+        defaultRealm = "ATHENA.MIT.EDU";
+        domainRealm = "athena.mit.edu";
+        kdc = "kerberos.mit.edu";
+        kerberosAdminServer = "kerberos.mit.edu";
+      };
+    };
+
+  testScript =
+    let snapshot = pkgs.writeText "krb5-with-deprecated-config.conf" ''
+      [libdefaults]
+        default_realm = ATHENA.MIT.EDU
+
+      [realms]
+        ATHENA.MIT.EDU = {
+          admin_server = kerberos.mit.edu
+          kdc = kerberos.mit.edu
+        }
+
+      [domain_realm]
+        .athena.mit.edu = ATHENA.MIT.EDU
+        athena.mit.edu = ATHENA.MIT.EDU
+
+      [capaths]
+
+
+      [appdefaults]
+
+
+      [plugins]
+
+    '';
+  in ''
+    $machine->succeed("diff /etc/krb5.conf ${snapshot}");
+  '';
+})
diff --git a/nixos/tests/krb5/example-config.nix b/nixos/tests/krb5/example-config.nix
new file mode 100644
index 000000000000..d5328720931e
--- /dev/null
+++ b/nixos/tests/krb5/example-config.nix
@@ -0,0 +1,106 @@
+# Verifies that the configuration suggested in (non-deprecated) example values
+# will result in the expected output.
+
+import ../make-test.nix ({ pkgs, ...} : {
+  name = "krb5-with-example-config";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ eqyiel ];
+  };
+
+  machine =
+    { config, pkgs, ... }: {
+      krb5 = {
+        enable = true;
+        kerberos = pkgs.krb5Full;
+        libdefaults = {
+          default_realm = "ATHENA.MIT.EDU";
+        };
+        realms = {
+          "ATHENA.MIT.EDU" = {
+            admin_server = "athena.mit.edu";
+            kdc = "athena.mit.edu";
+          };
+        };
+        domain_realm = {
+          "example.com" = "EXAMPLE.COM";
+          ".example.com" = "EXAMPLE.COM";
+        };
+        capaths = {
+          "ATHENA.MIT.EDU" = {
+            "EXAMPLE.COM" = ".";
+          };
+          "EXAMPLE.COM" = {
+            "ATHENA.MIT.EDU" = ".";
+          };
+        };
+        appdefaults = {
+          pam = {
+            debug = false;
+            ticket_lifetime = 36000;
+            renew_lifetime = 36000;
+            max_timeout = 30;
+            timeout_shift = 2;
+            initial_timeout = 1;
+          };
+        };
+        plugins = {
+          ccselect = {
+            disable = "k5identity";
+          };
+        };
+        extraConfig = ''
+          [logging]
+            kdc          = SYSLOG:NOTICE
+            admin_server = SYSLOG:NOTICE
+            default      = SYSLOG:NOTICE
+        '';
+      };
+    };
+
+  testScript =
+    let snapshot = pkgs.writeText "krb5-with-example-config.conf" ''
+      [libdefaults]
+        default_realm = ATHENA.MIT.EDU
+
+      [realms]
+        ATHENA.MIT.EDU = {
+          admin_server = athena.mit.edu
+          kdc = athena.mit.edu
+        }
+
+      [domain_realm]
+        .example.com = EXAMPLE.COM
+        example.com = EXAMPLE.COM
+
+      [capaths]
+        ATHENA.MIT.EDU = {
+          EXAMPLE.COM = .
+        }
+        EXAMPLE.COM = {
+          ATHENA.MIT.EDU = .
+        }
+
+      [appdefaults]
+        pam = {
+          debug = false
+          initial_timeout = 1
+          max_timeout = 30
+          renew_lifetime = 36000
+          ticket_lifetime = 36000
+          timeout_shift = 2
+        }
+
+      [plugins]
+        ccselect = {
+          disable = k5identity
+        }
+
+      [logging]
+        kdc          = SYSLOG:NOTICE
+        admin_server = SYSLOG:NOTICE
+        default      = SYSLOG:NOTICE
+    '';
+  in ''
+    $machine->succeed("diff /etc/krb5.conf ${snapshot}");
+  '';
+})