summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/administration/container-networking.xml1
-rw-r--r--nixos/doc/manual/release-notes/rl-1809.xml42
-rw-r--r--nixos/doc/manual/release-notes/rl-1903.xml20
-rw-r--r--nixos/modules/config/pulseaudio.nix24
-rw-r--r--nixos/modules/hardware/video/nvidia.nix12
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/profiles/hardened.nix14
-rw-r--r--nixos/modules/security/misc.nix39
-rw-r--r--nixos/modules/services/hardware/lirc.nix4
-rw-r--r--nixos/modules/services/mail/postfix.nix18
-rw-r--r--nixos/modules/services/misc/weechat.nix4
-rw-r--r--nixos/modules/services/misc/weechat.xml2
-rw-r--r--nixos/modules/services/networking/hostapd.nix6
-rw-r--r--nixos/modules/services/networking/znc.nix431
-rw-r--r--nixos/modules/services/networking/znc/default.nix306
-rw-r--r--nixos/modules/services/networking/znc/options.nix268
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix6
-rw-r--r--nixos/modules/virtualisation/containers.nix1
-rw-r--r--nixos/modules/virtualisation/ec2-amis.nix19
19 files changed, 758 insertions, 462 deletions
diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml
index 8aca329c8f1f..2ee8bfdd50f1 100644
--- a/nixos/doc/manual/administration/container-networking.xml
+++ b/nixos/doc/manual/administration/container-networking.xml
@@ -52,6 +52,7 @@ $ ping -c1 10.233.4.2
 networking.networkmanager.unmanaged = [ "interface-name:ve-*" ];
 </programlisting>
  </para>
+
  <para>
   You may need to restart your system for the changes to take effect.
  </para>
diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml
index c5521735428b..0ddf40acbfcc 100644
--- a/nixos/doc/manual/release-notes/rl-1809.xml
+++ b/nixos/doc/manual/release-notes/rl-1809.xml
@@ -477,6 +477,48 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
   <itemizedlist>
    <listitem>
     <para>
+     Some licenses that were incorrectly not marked as unfree now are. This is
+     the case for:
+     <itemizedlist>
+      <listitem>
+       <para>
+        cc-by-nc-sa-20: Creative Commons Attribution Non Commercial Share Alike
+        2.0
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        cc-by-nc-sa-25: Creative Commons Attribution Non Commercial Share Alike
+        2.5
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        cc-by-nc-sa-30: Creative Commons Attribution Non Commercial Share Alike
+        3.0
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        cc-by-nc-sa-40: Creative Commons Attribution Non Commercial Share Alike
+        4.0
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        cc-by-nd-30: Creative Commons Attribution-No Derivative Works v3.00
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        msrla: Microsoft Research License Agreement
+       </para>
+      </listitem>
+     </itemizedlist>
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      The deprecated <varname>services.cassandra</varname> module has seen a
      complete rewrite. (See above.)
     </para>
diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml
index e13770c553f8..baddbcd8c68d 100644
--- a/nixos/doc/manual/release-notes/rl-1903.xml
+++ b/nixos/doc/manual/release-notes/rl-1903.xml
@@ -106,12 +106,12 @@
     </para>
    </listitem>
    <listitem>
-     <para>
-       The <literal>light</literal> module no longer uses setuid binaries, but
-       udev rules. As a consequence users of that module have to belong to the
-       <literal>video</literal> group in order to use the executable
-       (i.e. <literal>users.users.yourusername.extraGroups = ["video"];</literal>).
-     </para>
+    <para>
+     The <literal>light</literal> module no longer uses setuid binaries, but
+     udev rules. As a consequence users of that module have to belong to the
+     <literal>video</literal> group in order to use the executable (i.e.
+     <literal>users.users.yourusername.extraGroups = ["video"];</literal>).
+    </para>
    </listitem>
    <listitem>
     <para>
@@ -122,6 +122,14 @@
      the Python 2 or 3 version of the package.
     </para>
    </listitem>
+   <listitem>
+    <para>
+      Options
+      <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.userName</literal> and
+      <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.modulePackages</literal>
+      were removed. They were never used for anything and can therefore safely be removed.
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index e16a021ec20b..d4aa59506295 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -154,6 +154,18 @@ in {
         '';
       };
 
+      extraModules = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.pulseaudio-modules-bt ]";
+        description = ''
+          Extra pulseaudio modules to use. This is intended for out-of-tree
+          pulseaudio modules like extra bluetooth codecs.
+
+          Extra modules take precedence over built-in pulseaudio modules.
+        '';
+      };
+
       daemon = {
         logLevel = mkOption {
           type = types.str;
@@ -236,6 +248,18 @@ in {
       systemd.packages = [ overriddenPackage ];
     })
 
+    (mkIf (cfg.extraModules != []) {
+      hardware.pulseaudio.daemon.config.dl-search-path = let
+        overriddenModules = builtins.map
+          (drv: drv.override { pulseaudio = overriddenPackage; })
+          cfg.extraModules;
+        modulePaths = builtins.map
+          (drv: "${drv}/lib/pulse-${overriddenPackage.version}/modules")
+          # User-provided extra modules take precedence
+          (overriddenModules ++ [ overriddenPackage ]);
+      in lib.concatStringsSep ":" modulePaths;
+    })
+
     (mkIf hasZeroconf {
       services.avahi.enable = true;
     })
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index 6944d1a4f76b..f8524ab99e8a 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -1,6 +1,6 @@
 # This module provides the proprietary NVIDIA X11 / OpenGL drivers.
 
-{ config, lib, pkgs, pkgs_i686, ... }:
+{ stdenv, config, lib, pkgs, pkgs_i686, ... }:
 
 with lib;
 
@@ -23,7 +23,11 @@ let
     else null;
 
   nvidia_x11 = nvidiaForKernel config.boot.kernelPackages;
-  nvidia_libs32 = (nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; };
+  nvidia_libs32 =
+    if versionOlder nvidia_x11.version "391" then
+      ((nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; }).out
+    else
+      (nvidiaForKernel config.boot.kernelPackages).lib32;
 
   enabled = nvidia_x11 != null;
 
@@ -98,7 +102,7 @@ in
     assertions = [
       {
         assertion = config.services.xserver.displayManager.gdm.wayland;
-        message = "NVidia drivers don't support wayland";
+        message = "NVIDIA drivers don't support wayland";
       }
       {
         assertion = !optimusCfg.enable ||
@@ -161,7 +165,7 @@ in
     };
 
     hardware.opengl.package = nvidia_x11.out;
-    hardware.opengl.package32 = nvidia_libs32.out;
+    hardware.opengl.package32 = nvidia_libs32;
 
     environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ]
       ++ lib.filter (p: p != null) [ nvidia_x11.persistenced ];
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index f55c32fa511d..fb6b4262568e 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -149,6 +149,7 @@
   ./security/duosec.nix
   ./security/hidepid.nix
   ./security/lock-kernel-modules.nix
+  ./security/misc.nix
   ./security/oath.nix
   ./security/pam.nix
   ./security/pam_usb.nix
@@ -634,7 +635,7 @@
   ./services/networking/zerobin.nix
   ./services/networking/zeronet.nix
   ./services/networking/zerotierone.nix
-  ./services/networking/znc.nix
+  ./services/networking/znc/default.nix
   ./services/printing/cupsd.nix
   ./services/scheduling/atd.nix
   ./services/scheduling/chronos.nix
diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix
index 38c5a42ba6fb..d712fb2514b1 100644
--- a/nixos/modules/profiles/hardened.nix
+++ b/nixos/modules/profiles/hardened.nix
@@ -16,6 +16,8 @@ with lib;
 
   security.lockKernelModules = mkDefault true;
 
+  security.allowUserNamespaces = mkDefault false;
+
   security.apparmor.enable = mkDefault true;
 
   boot.kernelParams = [
@@ -59,18 +61,6 @@ with lib;
   # ... or at least apply some hardening to it
   boot.kernel.sysctl."net.core.bpf_jit_harden" = mkDefault true;
 
-  # A recurring problem with user namespaces is that there are
-  # still code paths where the kernel's permission checking logic
-  # fails to account for namespacing, instead permitting a
-  # namespaced process to act outside the namespace with the
-  # same privileges as it would have inside it.  This is particularly
-  # bad in the common case of running as root within the namespace.
-  #
-  # Setting the number of allowed user namespaces to 0 effectively disables
-  # the feature at runtime.  Attempting to create a user namespace
-  # with unshare will then fail with "no space left on device".
-  boot.kernel.sysctl."user.max_user_namespaces" = mkDefault 0;
-
   # Raise ASLR entropy for 64bit & 32bit, respectively.
   #
   # Note: mmap_rnd_compat_bits may not exist on 64bit.
diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix
new file mode 100644
index 000000000000..42f872b7b088
--- /dev/null
+++ b/nixos/modules/security/misc.nix
@@ -0,0 +1,39 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+  meta = {
+    maintainers = [ maintainers.joachifm ];
+  };
+
+  options = {
+    security.allowUserNamespaces = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to allow creation of user namespaces.  A recurring problem
+        with user namespaces is the presence of code paths where the kernel's
+        permission checking logic fails to account for namespacing, instead
+        permitting a namespaced process to act outside the namespace with the
+        same privileges as it would have inside it.  This is particularly
+        damaging in the common case of running as root within the namespace.
+        When user namespace creation is disallowed, attempting to create
+        a user namespace fails with "no space left on device" (ENOSPC).
+      '';
+    };
+  };
+
+  config = mkIf (!config.security.allowUserNamespaces) {
+    # Setting the number of allowed user namespaces to 0 effectively disables
+    # the feature at runtime.  Note that root may raise the limit again
+    # at any time.
+    boot.kernel.sysctl."user.max_user_namespaces" = 0;
+
+    assertions = [
+      { assertion = config.nix.useSandbox -> config.security.allowUserNamespaces;
+        message = "`nix.useSandbox = true` conflicts with `!security.allowUserNamespaces`.";
+      }
+    ];
+  };
+}
diff --git a/nixos/modules/services/hardware/lirc.nix b/nixos/modules/services/hardware/lirc.nix
index a66a7fbf495f..5635d6f09715 100644
--- a/nixos/modules/services/hardware/lirc.nix
+++ b/nixos/modules/services/hardware/lirc.nix
@@ -65,6 +65,10 @@ in {
 
       serviceConfig = {
         RuntimeDirectory = "lirc";
+
+        # socket lives in runtime directory; we have to keep is available
+        RuntimeDirectoryPreserve = true;
+
         ExecStart = ''
           ${pkgs.lirc}/bin/lircd --nodaemon \
             ${escapeShellArgs cfg.extraArguments} \
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 33249aa3e554..d43733484ffa 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -602,7 +602,7 @@ in
             target = "postfix";
           };
 
-        # This makes comfortable for root to run 'postqueue' for example.
+        # This makes it comfortable to run 'postqueue/postdrop' for example.
         systemPackages = [ pkgs.postfix ];
       };
 
@@ -616,6 +616,22 @@ in
         setgid = true;
       };
 
+      security.wrappers.postqueue = {
+        program = "postqueue";
+        source = "${pkgs.postfix}/bin/postqueue";
+        group = setgidGroup;
+        setuid = false;
+        setgid = true;
+      };
+
+      security.wrappers.postdrop = {
+        program = "postdrop";
+        source = "${pkgs.postfix}/bin/postdrop";
+        group = setgidGroup;
+        setuid = false;
+        setgid = true;
+      };
+
       users.users = optional (user == "postfix")
         { name = "postfix";
           description = "Postfix mail server user";
diff --git a/nixos/modules/services/misc/weechat.nix b/nixos/modules/services/misc/weechat.nix
index 1fcfb440485d..c6ff540ea12f 100644
--- a/nixos/modules/services/misc/weechat.nix
+++ b/nixos/modules/services/misc/weechat.nix
@@ -46,10 +46,12 @@ in
         Group = "weechat";
         RemainAfterExit = "yes";
       };
-      script = "exec ${pkgs.screen}/bin/screen -Dm -S ${cfg.sessionName} ${cfg.binary}";
+      script = "exec ${config.security.wrapperDir}/screen -Dm -S ${cfg.sessionName} ${cfg.binary}";
       wantedBy = [ "multi-user.target" ];
       wants = [ "network.target" ];
     };
+
+    security.wrappers.screen.source = "${pkgs.screen}/bin/screen";
   };
 
   meta.doc = ./weechat.xml;
diff --git a/nixos/modules/services/misc/weechat.xml b/nixos/modules/services/misc/weechat.xml
index 9c9ee0448c92..b7f755bbc5c7 100644
--- a/nixos/modules/services/misc/weechat.xml
+++ b/nixos/modules/services/misc/weechat.xml
@@ -54,7 +54,7 @@
 </programlisting>
    Now, the session can be re-attached like this:
 <programlisting>
-screen -r weechat-screen
+screen -x weechat/weechat-screen
 </programlisting>
   </para>
 
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 3af0441a89d8..9f74e4963296 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -157,9 +157,9 @@ in
       { description = "hostapd wireless AP";
 
         path = [ pkgs.hostapd ];
-        wantedBy = [ "network.target" ];
-
-        after = [ "${cfg.interface}-cfg.service" "nat.service" "bind.service" "dhcpd.service" "sys-subsystem-net-devices-${cfg.interface}.device" ];
+        after = [ "sys-subsystem-net-devices-${cfg.interface}.device" ];
+        bindsTo = [ "sys-subsystem-net-devices-${cfg.interface}.device" ];
+        requiredBy = [ "network-link-${cfg.interface}.service" ];
 
         serviceConfig =
           { ExecStart = "${pkgs.hostapd}/bin/hostapd ${configFile}";
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
deleted file mode 100644
index f817db2ad000..000000000000
--- a/nixos/modules/services/networking/znc.nix
+++ /dev/null
@@ -1,431 +0,0 @@
-{ config, lib, pkgs, ...}:
-
-with lib;
-
-let
-  cfg = config.services.znc;
-
-  defaultUser = "znc"; # Default user to own process.
-
-  # Default user and pass:
-  # un=znc
-  # pw=nixospass
-
-  defaultUserName = "znc";
-  defaultPassBlock = "
-        <Pass password>
-                Method = sha256
-                Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93
-                Salt = l5Xryew4g*!oa(ECfX2o
-        </Pass>
-  ";
-
-  modules = pkgs.buildEnv {
-    name = "znc-modules";
-    paths = cfg.modulePackages;
-  };
-
-  # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`.
-  mkZncConf = confOpts: ''
-    Version = 1.6.3
-    ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules}
-
-    <Listener l>
-            Port = ${toString confOpts.port}
-            IPv4 = true
-            IPv6 = true
-            SSL = ${boolToString confOpts.useSSL}
-            ${lib.optionalString (confOpts.uriPrefix != null) "URIPrefix = ${confOpts.uriPrefix}"}
-    </Listener>
-
-    <User ${confOpts.userName}>
-            ${confOpts.passBlock}
-            Admin = true
-            Nick = ${confOpts.nick}
-            AltNick = ${confOpts.nick}_
-            Ident = ${confOpts.nick}
-            RealName = ${confOpts.nick}
-            ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules}
-
-            ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: net: ''
-              <Network ${name}>
-                  ${concatMapStrings (m: "LoadModule = ${m}\n") net.modules}
-                  Server = ${net.server} ${lib.optionalString net.useSSL "+"}${toString net.port} ${net.password}
-                  ${concatMapStrings (c: "<Chan #${c}>\n</Chan>\n") net.channels}
-                  ${lib.optionalString net.hasBitlbeeControlChannel ''
-                    <Chan &bitlbee>
-                    </Chan>
-                  ''}
-                  ${net.extraConf}
-              </Network>
-              '') confOpts.networks) }
-    </User>
-    ${confOpts.extraZncConf}
-  '';
-
-  zncConfFile = pkgs.writeTextFile {
-    name = "znc.conf";
-    text = if cfg.zncConf != ""
-      then cfg.zncConf
-      else mkZncConf cfg.confOptions;
-  };
-
-  networkOpts = { ... }: {
-    options = {
-      server = mkOption {
-        type = types.str;
-        example = "chat.freenode.net";
-        description = ''
-          IRC server address.
-        '';
-      };
-
-      port = mkOption {
-        type = types.int;
-        default = 6697;
-        example = 6697;
-        description = ''
-          IRC server port.
-        '';
-      };
-
-      userName = mkOption {
-        default = "";
-        example = "johntron";
-        type = types.string;
-        description = ''
-          A nick identity specific to the IRC server.
-        '';
-      };
-
-      password = mkOption {
-        type = types.str;
-        default = "";
-        description = ''
-          IRC server password, such as for a Slack gateway.
-        '';
-      };
-
-      useSSL = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Whether to use SSL to connect to the IRC server.
-        '';
-      };
-
-      modulePackages = mkOption {
-        type = types.listOf types.package;
-        default = [];
-        example = [ "pkgs.zncModules.push" "pkgs.zncModules.fish" ];
-        description = ''
-          External ZNC modules to build.
-        '';
-      };
-
-      modules = mkOption {
-        type = types.listOf types.str;
-        default = [ "simple_away" ];
-        example = literalExample "[ simple_away sasl ]";
-        description = ''
-          ZNC modules to load.
-        '';
-      };
-
-      channels = mkOption {
-        type = types.listOf types.str;
-        default = [];
-        example = [ "nixos" ];
-        description = ''
-          IRC channels to join.
-        '';
-      };
-
-      hasBitlbeeControlChannel = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to add the special Bitlbee operations channel.
-        '';
-      };
-
-      extraConf = mkOption {
-        default = "";
-        type = types.lines;
-        example = ''
-          Encoding = ^UTF-8
-          FloodBurst = 4
-          FloodRate = 1.00
-          IRCConnectEnabled = true
-          Ident = johntron
-          JoinDelay = 0
-          Nick = johntron
-        '';
-        description = ''
-          Extra config for the network.
-        '';
-      };
-    };
-  };
-
-in
-
-{
-
-  ###### Interface
-
-  options = {
-    services.znc = {
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Enable a ZNC service for a user.
-        '';
-      };
-
-      user = mkOption {
-        default = "znc";
-        example = "john";
-        type = types.string;
-        description = ''
-          The name of an existing user account to use to own the ZNC server process.
-          If not specified, a default user will be created to own the process.
-        '';
-      };
-
-      group = mkOption {
-        default = "";
-        example = "users";
-        type = types.string;
-        description = ''
-          Group to own the ZNCserver process.
-        '';
-      };
-
-      dataDir = mkOption {
-        default = "/var/lib/znc/";
-        example = "/home/john/.znc/";
-        type = types.path;
-        description = ''
-          The data directory. Used for configuration files and modules.
-        '';
-      };
-
-      openFirewall = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to open ports in the firewall for ZNC.
-        '';
-      };
-
-      zncConf = mkOption {
-        default = "";
-        example = "See: http://wiki.znc.in/Configuration";
-        type = types.lines;
-        description = ''
-          Config file as generated with `znc --makeconf` to use for the whole ZNC configuration.
-          If specified, `confOptions` will be ignored, and this value, as-is, will be used.
-          If left empty, a conf file with default values will be used.
-        '';
-      };
-
-      confOptions = {
-        modules = mkOption {
-          type = types.listOf types.str;
-          default = [ "webadmin" "adminlog" ];
-          example = [ "partyline" "webadmin" "adminlog" "log" ];
-          description = ''
-            A list of modules to include in the `znc.conf` file.
-          '';
-        };
-
-        userModules = mkOption {
-          type = types.listOf types.str;
-          default = [ "chansaver" "controlpanel" ];
-          example = [ "chansaver" "controlpanel" "fish" "push" ];
-          description = ''
-            A list of user modules to include in the `znc.conf` file.
-          '';
-        };
-
-        userName = mkOption {
-          default = defaultUserName;
-          example = "johntron";
-          type = types.string;
-          description = ''
-            The user name used to log in to the ZNC web admin interface.
-          '';
-        };
-
-        networks = mkOption {
-          default = { };
-          type = with types; attrsOf (submodule networkOpts);
-          description = ''
-            IRC networks to connect the user to.
-          '';
-          example = {
-            "freenode" = {
-              server = "chat.freenode.net";
-              port = 6697;
-              useSSL = true;
-              modules = [ "simple_away" ];
-            };
-          };
-        };
-
-        nick = mkOption {
-          default = "znc-user";
-          example = "john";
-          type = types.string;
-          description = ''
-            The IRC nick.
-          '';
-        };
-
-        passBlock = mkOption {
-          example = defaultPassBlock;
-          type = types.string;
-          description = ''
-            Generate with `nix-shell -p znc --command "znc --makepass"`.
-            This is the password used to log in to the ZNC web admin interface.
-          '';
-        };
-
-        port = mkOption {
-          default = 5000;
-          example = 5000;
-          type = types.int;
-          description = ''
-            Specifies the port on which to listen.
-          '';
-        };
-
-        useSSL = mkOption {
-          default = true;
-          type = types.bool;
-          description = ''
-            Indicates whether the ZNC server should use SSL when listening on the specified port. A self-signed certificate will be generated.
-          '';
-        };
-
-        uriPrefix = mkOption {
-          type = types.nullOr types.str;
-          default = null;
-          example = "/znc/";
-          description = ''
-            An optional URI prefix for the ZNC web interface. Can be
-            used to make ZNC available behind a reverse proxy.
-          '';
-        };
-
-        extraZncConf = mkOption {
-          default = "";
-          type = types.lines;
-          description = ''
-            Extra config to `znc.conf` file.
-          '';
-        };
-      };
-
-      modulePackages = mkOption {
-        type = types.listOf types.package;
-        default = [ ];
-        example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]";
-        description = ''
-          A list of global znc module packages to add to znc.
-        '';
-      };
-
-      mutable = mkOption {
-        default = true;
-        type = types.bool;
-        description = ''
-          Indicates whether to allow the contents of the `dataDir` directory to be changed
-          by the user at run-time.
-          If true, modifications to the ZNC configuration after its initial creation are not
-            overwritten by a NixOS system rebuild.
-          If false, the ZNC configuration is rebuilt by every system rebuild.
-          If the user wants to manage the ZNC service using the web admin interface, this value
-            should be set to true.
-        '';
-      };
-
-      extraFlags = mkOption {
-        default = [ ];
-        example = [ "--debug" ];
-        type = types.listOf types.str;
-        description = ''
-          Extra flags to use when executing znc command.
-        '';
-      };
-    };
-  };
-
-
-  ###### Implementation
-
-  config = mkIf cfg.enable {
-
-    networking.firewall = mkIf cfg.openFirewall {
-      allowedTCPPorts = [ cfg.confOptions.port ];
-    };
-
-    systemd.services.znc = {
-      description = "ZNC Server";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.service" ];
-      serviceConfig = {
-        User = cfg.user;
-        Group = cfg.group;
-        Restart = "always";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        ExecStop   = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
-      };
-      preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/configs
-
-        # If mutable, regenerate conf file every time.
-        ${optionalString (!cfg.mutable) ''
-          ${pkgs.coreutils}/bin/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated."
-          ${pkgs.coreutils}/bin/rm -f ${cfg.dataDir}/configs/znc.conf
-        ''}
-
-        # Ensure essential files exist.
-        if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then
-            ${pkgs.coreutils}/bin/echo "No znc.conf file found in ${cfg.dataDir}. Creating one now."
-            ${pkgs.coreutils}/bin/cp --no-clobber ${zncConfFile} ${cfg.dataDir}/configs/znc.conf
-            ${pkgs.coreutils}/bin/chmod u+rw ${cfg.dataDir}/configs/znc.conf
-            ${pkgs.coreutils}/bin/chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf
-        fi
-
-        if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then
-          ${pkgs.coreutils}/bin/echo "No znc.pem file found in ${cfg.dataDir}. Creating one now."
-          ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir}
-        fi
-
-        # Symlink modules
-        rm ${cfg.dataDir}/modules || true
-        ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules
-      '';
-      script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}";
-    };
-
-    users.users = optional (cfg.user == defaultUser)
-      { name = defaultUser;
-        description = "ZNC server daemon owner";
-        group = defaultUser;
-        uid = config.ids.uids.znc;
-        home = cfg.dataDir;
-        createHome = true;
-      };
-
-    users.groups = optional (cfg.user == defaultUser)
-      { name = defaultUser;
-        gid = config.ids.gids.znc;
-        members = [ defaultUser ];
-      };
-
-  };
-}
diff --git a/nixos/modules/services/networking/znc/default.nix b/nixos/modules/services/networking/znc/default.nix
new file mode 100644
index 000000000000..bce5b15a19ec
--- /dev/null
+++ b/nixos/modules/services/networking/znc/default.nix
@@ -0,0 +1,306 @@
+{ config, lib, pkgs, ...}:
+
+with lib;
+
+let
+
+  cfg = config.services.znc;
+
+  defaultUser = "znc";
+
+  modules = pkgs.buildEnv {
+    name = "znc-modules";
+    paths = cfg.modulePackages;
+  };
+
+  listenerPorts = concatMap (l: optional (l ? Port) l.Port)
+    (attrValues (cfg.config.Listener or {}));
+
+  # Converts the config option to a string
+  semanticString = let
+
+      sortedAttrs = set: sort (l: r:
+        if l == "extraConfig" then false # Always put extraConfig last
+        else if isAttrs set.${l} == isAttrs set.${r} then l < r
+        else isAttrs set.${r} # Attrsets should be last, makes for a nice config
+        # This last case occurs when any side (but not both) is an attrset
+        # The order of these is correct when the attrset is on the right
+        # which we're just returning
+      ) (attrNames set);
+
+      # Specifies an attrset that encodes the value according to its type
+      encode = name: value: {
+          null = [];
+          bool = [ "${name} = ${boolToString value}" ];
+          int = [ "${name} = ${toString value}" ];
+
+          # extraConfig should be inserted verbatim
+          string = [ (if name == "extraConfig" then value else "${name} = ${value}") ];
+
+          # Values like `Foo = [ "bar" "baz" ];` should be transformed into
+          #   Foo=bar
+          #   Foo=baz
+          list = concatMap (encode name) value;
+
+          # Values like `Foo = { bar = { Baz = "baz"; Qux = "qux"; Florps = null; }; };` should be transmed into
+          #   <Foo bar>
+          #     Baz=baz
+          #     Qux=qux
+          #   </Foo>
+          set = concatMap (subname: [
+              "<${name} ${subname}>"
+            ] ++ map (line: "\t${line}") (toLines value.${subname}) ++ [
+              "</${name}>"
+            ]) (filter (v: v != null) (attrNames value));
+
+        }.${builtins.typeOf value};
+
+      # One level "above" encode, acts upon a set and uses encode on each name,value pair
+      toLines = set: concatMap (name: encode name set.${name}) (sortedAttrs set);
+
+    in
+      concatStringsSep "\n" (toLines cfg.config);
+
+  semanticTypes = with types; rec {
+    zncAtom = nullOr (either (either int bool) str);
+    zncAttr = attrsOf (nullOr zncConf);
+    zncAll = either (either zncAtom (listOf zncAtom)) zncAttr;
+    zncConf = attrsOf (zncAll // {
+      # Since this is a recursive type and the description by default contains
+      # the description of its subtypes, infinite recursion would occur without
+      # explicitly breaking this cycle
+      description = "znc values (null, atoms (str, int, bool), list of atoms, or attrsets of znc values)";
+    });
+  };
+
+in
+
+{
+
+  imports = [ ./options.nix ];
+
+  options = {
+    services.znc = {
+      enable = mkEnableOption "ZNC";
+
+      user = mkOption {
+        default = "znc";
+        example = "john";
+        type = types.str;
+        description = ''
+          The name of an existing user account to use to own the ZNC server
+          process. If not specified, a default user will be created.
+        '';
+      };
+
+      group = mkOption {
+        default = defaultUser;
+        example = "users";
+        type = types.str;
+        description = ''
+          Group to own the ZNC process.
+        '';
+      };
+
+      dataDir = mkOption {
+        default = "/var/lib/znc/";
+        example = "/home/john/.znc/";
+        type = types.path;
+        description = ''
+          The state directory for ZNC. The config and the modules will be linked
+          to from this directory as well.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to open ports in the firewall for ZNC. Does work with
+          ports for listeners specified in
+          <option>services.znc.config.Listener</option>.
+        '';
+      };
+
+      config = mkOption {
+        type = semanticTypes.zncConf;
+        default = {};
+        example = literalExample ''
+          {
+            LoadModule = [ "webadmin" "adminlog" ];
+            User.paul = {
+              Admin = true;
+              Nick = "paul";
+              AltNick = "paul1";
+              LoadModule = [ "chansaver" "controlpanel" ];
+              Network.freenode = {
+                Server = "chat.freenode.net +6697";
+                LoadModule = [ "simple_away" ];
+                Chan = {
+                  "#nixos" = { Detached = false; };
+                  "##linux" = { Disabled = true; };
+                };
+              };
+              Pass.password = {
+                Method = "sha256";
+                Hash = "e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93";
+                Salt = "l5Xryew4g*!oa(ECfX2o";
+              };
+            };
+          }
+        '';
+        description = ''
+          Configuration for ZNC, see
+          <literal>https://wiki.znc.in/Configuration</literal> for details. The
+          Nix value declared here will be translated directly to the xml-like
+          format ZNC expects. This is much more flexible than the legacy options
+          under <option>services.znc.confOptions.*</option>, but also can't do
+          any type checking.
+          </para>
+          <para>
+          You can use <command>nix-instantiate --eval --strict '&lt;nixpkgs/nixos&gt;' -A config.services.znc.config</command>
+          to view the current value. By default it contains a listener for port
+          5000 with SSL enabled.
+          </para>
+          <para>
+          Nix attributes called <literal>extraConfig</literal> will be inserted
+          verbatim into the resulting config file.
+          </para>
+          <para>
+          If <option>services.znc.useLegacyConfig</option> is turned on, the
+          option values in <option>services.znc.confOptions.*</option> will be
+          gracefully be applied to this option.
+          </para>
+          <para>
+          If you intend to update the configuration through this option, be sure
+          to enable <option>services.znc.mutable</option>, otherwise none of the
+          changes here will be applied after the initial deploy.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        example = "~/.znc/configs/znc.conf";
+        description = ''
+          Configuration file for ZNC. It is recommended to use the
+          <option>config</option> option instead.
+          </para>
+          <para>
+          Setting this option will override any auto-generated config file
+          through the <option>confOptions</option> or <option>config</option>
+          options.
+        '';
+      };
+
+      modulePackages = mkOption {
+        type = types.listOf types.package;
+        default = [ ];
+        example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]";
+        description = ''
+          A list of global znc module packages to add to znc.
+        '';
+      };
+
+      mutable = mkOption {
+        default = true; # TODO: Default to true when config is set, make sure to not delete the old config if present
+        type = types.bool;
+        description = ''
+          Indicates whether to allow the contents of the
+          <literal>dataDir</literal> directory to be changed by the user at
+          run-time.
+          </para>
+          <para>
+          If enabled, modifications to the ZNC configuration after its initial
+          creation are not overwritten by a NixOS rebuild. If disabled, the
+          ZNC configuration is rebuilt on every NixOS rebuild.
+          </para>
+          <para>
+          If the user wants to manage the ZNC service using the web admin
+          interface, this option should be enabled.
+        '';
+      };
+
+      extraFlags = mkOption {
+        default = [ ];
+        example = [ "--debug" ];
+        type = types.listOf types.str;
+        description = ''
+          Extra arguments to use for executing znc.
+        '';
+      };
+    };
+  };
+
+
+  ###### Implementation
+
+  config = mkIf cfg.enable {
+
+    services.znc = {
+      configFile = mkDefault (pkgs.writeText "znc-generated.conf" semanticString);
+      config = {
+        Version = (builtins.parseDrvName pkgs.znc.name).version;
+        Listener.l.Port = mkDefault 5000;
+        Listener.l.SSL = mkDefault true;
+      };
+    };
+
+    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall listenerPorts;
+
+    systemd.services.znc = {
+      description = "ZNC Server";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart = "always";
+        ExecStart = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${escapeShellArgs cfg.extraFlags}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
+      };
+      preStart = ''
+        mkdir -p ${cfg.dataDir}/configs
+
+        # If mutable, regenerate conf file every time.
+        ${optionalString (!cfg.mutable) ''
+          echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated."
+          rm -f ${cfg.dataDir}/configs/znc.conf
+        ''}
+
+        # Ensure essential files exist.
+        if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then
+            echo "No znc.conf file found in ${cfg.dataDir}. Creating one now."
+            cp --no-clobber ${cfg.configFile} ${cfg.dataDir}/configs/znc.conf
+            chmod u+rw ${cfg.dataDir}/configs/znc.conf
+            chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf
+        fi
+
+        if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then
+          echo "No znc.pem file found in ${cfg.dataDir}. Creating one now."
+          ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir}
+        fi
+
+        # Symlink modules
+        rm ${cfg.dataDir}/modules || true
+        ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules
+      '';
+    };
+
+    users.users = optional (cfg.user == defaultUser)
+      { name = defaultUser;
+        description = "ZNC server daemon owner";
+        group = defaultUser;
+        uid = config.ids.uids.znc;
+        home = cfg.dataDir;
+        createHome = true;
+      };
+
+    users.groups = optional (cfg.user == defaultUser)
+      { name = defaultUser;
+        gid = config.ids.gids.znc;
+        members = [ defaultUser ];
+      };
+
+  };
+}
diff --git a/nixos/modules/services/networking/znc/options.nix b/nixos/modules/services/networking/znc/options.nix
new file mode 100644
index 000000000000..505ebb3bf0ad
--- /dev/null
+++ b/nixos/modules/services/networking/znc/options.nix
@@ -0,0 +1,268 @@
+{ lib, config, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.znc;
+
+  networkOpts = {
+    options = {
+
+      server = mkOption {
+        type = types.str;
+        example = "chat.freenode.net";
+        description = ''
+          IRC server address.
+        '';
+      };
+
+      port = mkOption {
+        type = types.ints.u16;
+        default = 6697;
+        description = ''
+          IRC server port.
+        '';
+      };
+
+      password = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          IRC server password, such as for a Slack gateway.
+        '';
+      };
+
+      useSSL = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to use SSL to connect to the IRC server.
+        '';
+      };
+
+      modules = mkOption {
+        type = types.listOf types.str;
+        default = [ "simple_away" ];
+        example = literalExample "[ simple_away sasl ]";
+        description = ''
+          ZNC network modules to load.
+        '';
+      };
+
+      channels = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "nixos" ];
+        description = ''
+          IRC channels to join.
+        '';
+      };
+
+      hasBitlbeeControlChannel = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to add the special Bitlbee operations channel.
+        '';
+      };
+
+      extraConf = mkOption {
+        default = "";
+        type = types.lines;
+        example = ''
+          Encoding = ^UTF-8
+          FloodBurst = 4
+          FloodRate = 1.00
+          IRCConnectEnabled = true
+          Ident = johntron
+          JoinDelay = 0
+          Nick = johntron
+        '';
+        description = ''
+          Extra config for the network. Consider using
+          <option>services.znc.config</option> instead.
+        '';
+      };
+    };
+  };
+
+in
+
+{
+
+  options = {
+    services.znc = {
+
+      useLegacyConfig = mkOption {
+        default = true;
+        type = types.bool;
+        description = ''
+          Whether to propagate the legacy options under
+          <option>services.znc.confOptions.*</option> to the znc config. If this
+          is turned on, the znc config will contain a user with the default name
+          "znc", global modules "webadmin" and "adminlog" will be enabled by
+          default, and more, all controlled through the
+          <option>services.znc.confOptions.*</option> options.
+          You can use <command>nix-instantiate --eval --strict '&lt;nixpkgs/nixos&gt;' -A config.services.znc.config</command>
+          to view the current value of the config.
+          </para>
+          <para>
+          In any case, if you need more flexibility,
+          <option>services.znc.config</option> can be used to override/add to
+          all of the legacy options.
+        '';
+      };
+
+      confOptions = {
+        modules = mkOption {
+          type = types.listOf types.str;
+          default = [ "webadmin" "adminlog" ];
+          example = [ "partyline" "webadmin" "adminlog" "log" ];
+          description = ''
+            A list of modules to include in the `znc.conf` file.
+          '';
+        };
+
+        userModules = mkOption {
+          type = types.listOf types.str;
+          default = [ "chansaver" "controlpanel" ];
+          example = [ "chansaver" "controlpanel" "fish" "push" ];
+          description = ''
+            A list of user modules to include in the `znc.conf` file.
+          '';
+        };
+
+        userName = mkOption {
+          default = "znc";
+          example = "johntron";
+          type = types.str;
+          description = ''
+            The user name used to log in to the ZNC web admin interface.
+          '';
+        };
+
+        networks = mkOption {
+          default = { };
+          type = with types; attrsOf (submodule networkOpts);
+          description = ''
+            IRC networks to connect the user to.
+          '';
+          example = literalExample ''
+            {
+              "freenode" = {
+                server = "chat.freenode.net";
+                port = 6697;
+                useSSL = true;
+                modules = [ "simple_away" ];
+              };
+            };
+          '';
+        };
+
+        nick = mkOption {
+          default = "znc-user";
+          example = "john";
+          type = types.str;
+          description = ''
+            The IRC nick.
+          '';
+        };
+
+        passBlock = mkOption {
+          example = literalExample ''
+            &lt;Pass password&gt;
+               Method = sha256
+               Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93
+               Salt = l5Xryew4g*!oa(ECfX2o
+            &lt;/Pass&gt;
+          '';
+          type = types.str;
+          description = ''
+            Generate with `nix-shell -p znc --command "znc --makepass"`.
+            This is the password used to log in to the ZNC web admin interface.
+            You can also set this through
+            <option>services.znc.config.User.&lt;username&gt;.Pass.Method</option>
+            and co.
+          '';
+        };
+
+        port = mkOption {
+          default = 5000;
+          type = types.int;
+          description = ''
+            Specifies the port on which to listen.
+          '';
+        };
+
+        useSSL = mkOption {
+          default = true;
+          type = types.bool;
+          description = ''
+            Indicates whether the ZNC server should use SSL when listening on
+            the specified port. A self-signed certificate will be generated.
+          '';
+        };
+
+        uriPrefix = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "/znc/";
+          description = ''
+            An optional URI prefix for the ZNC web interface. Can be
+            used to make ZNC available behind a reverse proxy.
+          '';
+        };
+
+        extraZncConf = mkOption {
+          default = "";
+          type = types.lines;
+          description = ''
+            Extra config to `znc.conf` file.
+          '';
+        };
+      };
+
+    };
+  };
+
+  config = mkIf cfg.useLegacyConfig {
+
+    services.znc.config = let
+      c = cfg.confOptions;
+      # defaults here should override defaults set in the non-legacy part
+      mkDefault = mkOverride 900;
+    in {
+      LoadModule = mkDefault c.modules;
+      Listener.l = {
+        Port = mkDefault c.port;
+        IPv4 = mkDefault true;
+        IPv6 = mkDefault true;
+        SSL = mkDefault c.useSSL;
+      };
+      User.${c.userName} = {
+        Admin = mkDefault true;
+        Nick = mkDefault c.nick;
+        AltNick = mkDefault "${c.nick}_";
+        Ident = mkDefault c.nick;
+        RealName = mkDefault c.nick;
+        LoadModule = mkDefault c.userModules;
+        Network = mapAttrs (name: net: {
+          LoadModule = mkDefault net.modules;
+          Server = mkDefault "${net.server} ${optionalString net.useSSL "+"}${toString net.port} ${net.password}";
+          Chan = optionalAttrs net.hasBitlbeeControlChannel { "&bitlbee" = mkDefault {}; } //
+            listToAttrs (map (n: nameValuePair "#${n}" (mkDefault {})) net.channels);
+          extraConfig = if net.extraConf == "" then mkDefault null else net.extraConf;
+        }) c.networks;
+        extraConfig = [ c.passBlock ] ++ optional (c.extraZncConf != "") c.extraZncConf;
+      };
+    };
+  };
+
+  imports = [
+    (mkRemovedOptionModule ["services" "znc" "zncConf"] ''
+      Instead of `services.znc.zncConf = "... foo ...";`, use
+      `services.znc.configFile = pkgs.writeText "znc.conf" "... foo ...";`.
+    '')
+  ];
+}
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index e9e935e90202..c92570582f20 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -145,8 +145,12 @@ let cfg = config.ec2; in
     environment.systemPackages = [ pkgs.cryptsetup ];
 
     boot.initrd.supportedFilesystems = [ "unionfs-fuse" ];
-    
+
     # EC2 has its own NTP server provided by the hypervisor
     networking.timeServers = [ "169.254.169.123" ];
+
+    # udisks has become too bloated to have in a headless system
+    # (e.g. it depends on GTK+).
+    services.udisks2.enable = false;
   };
 }
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index b91165ce3b82..8fe59badd335 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -130,6 +130,7 @@ let
         --bind-ro=/nix/var/nix/daemon-socket \
         --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
         --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
+        --link-journal=try-guest \
         --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
         --setenv HOST_BRIDGE="$HOST_BRIDGE" \
         --setenv HOST_ADDRESS="$HOST_ADDRESS" \
diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix
index 76facac39fc6..aaea06bb9a63 100644
--- a/nixos/modules/virtualisation/ec2-amis.nix
+++ b/nixos/modules/virtualisation/ec2-amis.nix
@@ -257,5 +257,22 @@ let self = {
   "18.03".sa-east-1.hvm-ebs = "ami-163e1f7a";
   "18.03".ap-south-1.hvm-ebs = "ami-6a390b05";
 
-  latest = self."18.03";
+  # 18.09.910.c15e342304a
+  "18.09".eu-west-1.hvm-ebs = "ami-0f412186fb8a0ec97";
+  "18.09".eu-west-2.hvm-ebs = "ami-0dada3805ce43c55e";
+  "18.09".eu-west-3.hvm-ebs = "ami-074df85565f2e02e2";
+  "18.09".eu-central-1.hvm-ebs = "ami-07c9b884e679df4f8";
+  "18.09".us-east-1.hvm-ebs = "ami-009c9c3f1af480ff3";
+  "18.09".us-east-2.hvm-ebs = "ami-08199961085ea8bc6";
+  "18.09".us-west-1.hvm-ebs = "ami-07aa7f56d612ddd38";
+  "18.09".us-west-2.hvm-ebs = "ami-01c84b7c368ac24d1";
+  "18.09".ca-central-1.hvm-ebs = "ami-04f66113f76198f6c";
+  "18.09".ap-southeast-1.hvm-ebs = "ami-0892c7e24ebf2194f";
+  "18.09".ap-southeast-2.hvm-ebs = "ami-010730f36424b0a2c";
+  "18.09".ap-northeast-1.hvm-ebs = "ami-0cdba8e998f076547";
+  "18.09".ap-northeast-2.hvm-ebs = "ami-0400a698e6a9f4a15";
+  "18.09".sa-east-1.hvm-ebs = "ami-0e4a8a47fd6db6112";
+  "18.09".ap-south-1.hvm-ebs = "ami-0880a678d3f555313";
+
+  latest = self."18.09";
 }; in self