about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/config/nsswitch.nix2
-rw-r--r--nixos/modules/config/system-path.nix1
-rw-r--r--nixos/modules/services/misc/gitlab.nix5
-rw-r--r--nixos/modules/services/scheduling/atd.nix4
-rw-r--r--nixos/modules/system/boot/resolved.nix72
-rw-r--r--nixos/modules/tasks/encrypted-devices.nix3
-rw-r--r--nixos/release.nix3
-rw-r--r--nixos/tests/atd.nix36
-rw-r--r--nixos/tests/gitolite.nix139
-rw-r--r--nixos/tests/prometheus.nix3
10 files changed, 250 insertions, 18 deletions
diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix
index 97278238dcd5..7b36d4f1cbdf 100644
--- a/nixos/modules/config/nsswitch.nix
+++ b/nixos/modules/config/nsswitch.nix
@@ -18,7 +18,7 @@ let
 
   hostArray = [ "files" ]
     ++ optionals mymachines [ "mymachines" ]
-    ++ optionals nssmdns [ "mdns_minimal [!UNAVAIL=return]" ]
+    ++ optionals nssmdns [ "mdns_minimal [NOTFOUND=return]" ]
     ++ optionals nsswins [ "wins" ]
     ++ optionals resolved ["resolve [!UNAVAIL=return]"]
     ++ [ "dns" ]
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 5d339eaea485..d3212d931605 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -31,6 +31,7 @@ let
       pkgs.nano
       pkgs.ncurses
       pkgs.netcat
+      pkgs.nix-info
       config.programs.ssh.package
       pkgs.perl
       pkgs.procps
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 0fa9e417785f..14c184c3d685 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -581,6 +581,7 @@ in {
         mkdir -p ${cfg.statePath}/{log,uploads}
         ln -sf ${cfg.statePath}/log /run/gitlab/log
         ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
+        ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp
         chown -R ${cfg.user}:${cfg.group} /run/gitlab
 
         # Prepare home directory
@@ -639,10 +640,10 @@ in {
         chmod -R ug+rwX,o-rwx ${cfg.statePath}/repositories
         chmod -R ug-s ${cfg.statePath}/repositories
         find ${cfg.statePath}/repositories -type d -print0 | xargs -0 chmod g+s
-        chmod 700 ${cfg.statePath}/uploads
+        chmod 770 ${cfg.statePath}/uploads
         chown -R git ${cfg.statePath}/uploads
         find ${cfg.statePath}/uploads -type f -exec chmod 0644 {} \;
-        find ${cfg.statePath}/uploads -type d -not -path ${cfg.statePath}/uploads -exec chmod 0700 {} \;
+        find ${cfg.statePath}/uploads -type d -not -path ${cfg.statePath}/uploads -exec chmod 0770 {} \;
       '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix
index 0216c9771c96..77a3f6b51e80 100644
--- a/nixos/modules/services/scheduling/atd.nix
+++ b/nixos/modules/services/scheduling/atd.nix
@@ -42,6 +42,8 @@ in
 
   config = mkIf cfg.enable {
 
+    # Not wrapping "batch" because it's a shell script (kernel drops perms
+    # anyway) and it's patched to invoke the "at" setuid wrapper.
     security.wrappers = builtins.listToAttrs (
       map (program: { name = "${program}"; value = {
       source = "${at}/bin/${program}";
@@ -49,7 +51,7 @@ in
       group = "atd";
       setuid = true;
       setgid = true;
-    };}) [ "at" "atq" "atrm" "batch" ]);
+    };}) [ "at" "atq" "atrm" ]);
 
     environment.systemPackages = [ at ];
 
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index a3fb733c289d..2147d43c4f19 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -31,8 +31,15 @@ in
       example = [ "example.com" ];
       type = types.listOf types.str;
       description = ''
-        A list of domains. These domains are used as search suffixes when resolving single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified domain names (FQDNs).
-        For compatibility reasons, if this setting is not specified, the search domains listed in /etc/resolv.conf are used instead, if that file exists and any domains are configured in it.
+        A list of domains. These domains are used as search suffixes
+        when resolving single-label host names (domain names which
+        contain no dot), in order to qualify them into fully-qualified
+        domain names (FQDNs).
+        </para><para>
+        For compatibility reasons, if this setting is not specified,
+        the search domains listed in
+        <filename>/etc/resolv.conf</filename> are used instead, if
+        that file exists and any domains are configured in it.
       '';
     };
 
@@ -41,10 +48,30 @@ in
       example = "false";
       type = types.enum [ "true" "resolve" "false" ];
       description = ''
-        Controls Link-Local Multicast Name Resolution support (RFC 4794) on the local host.
-        If true, enables full LLMNR responder and resolver support.
-        If false, disables both.
-        If set to "resolve", only resolution support is enabled, but responding is disabled.
+        Controls Link-Local Multicast Name Resolution support
+        (RFC 4795) on the local host.
+        </para><para>
+        If set to
+        <variablelist>
+        <varlistentry>
+          <term><literal>"true"</literal></term>
+          <listitem><para>
+            Enables full LLMNR responder and resolver support.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"false"</literal></term>
+          <listitem><para>
+            Disables both.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"resolve"</literal></term>
+          <listitem><para>
+            Only resolution support is enabled, but responding is disabled.
+          </para></listitem>
+        </varlistentry>
+        </variablelist>
       '';
     };
 
@@ -53,9 +80,36 @@ in
       example = "true";
       type = types.enum [ "true" "allow-downgrade" "false" ];
       description = ''
-        If true all DNS lookups are DNSSEC-validated locally (excluding LLMNR and Multicast DNS). Note that this mode requires a DNS server that supports DNSSEC. If the DNS server does not properly support DNSSEC all validations will fail.
-        If set to "allow-downgrade" DNSSEC validation is attempted, but if the server does not support DNSSEC properly, DNSSEC mode is automatically disabled. Note that this mode makes DNSSEC validation vulnerable to "downgrade" attacks, where an attacker might be able to trigger a downgrade to non-DNSSEC mode by synthesizing a DNS response that suggests DNSSEC was not supported.
-        If set to false, DNS lookups are not DNSSEC validated.
+        If set to
+        <variablelist>
+        <varlistentry>
+          <term><literal>"true"</literal></term>
+          <listitem><para>
+            all DNS lookups are DNSSEC-validated locally (excluding
+            LLMNR and Multicast DNS). Note that this mode requires a
+            DNS server that supports DNSSEC. If the DNS server does
+            not properly support DNSSEC all validations will fail.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"allow-downgrade"</literal></term>
+          <listitem><para>
+            DNSSEC validation is attempted, but if the server does not
+            support DNSSEC properly, DNSSEC mode is automatically
+            disabled. Note that this mode makes DNSSEC validation
+            vulnerable to "downgrade" attacks, where an attacker might
+            be able to trigger a downgrade to non-DNSSEC mode by
+            synthesizing a DNS response that suggests DNSSEC was not
+            supported.
+          </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><literal>"false"</literal></term>
+          <listitem><para>
+            DNS lookups are not DNSSEC validated.
+          </para></listitem>
+        </varlistentry>
+        </variablelist>
       '';
     };
 
diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix
index 6bbf335e7db7..da0c9408d891 100644
--- a/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixos/modules/tasks/encrypted-devices.nix
@@ -36,7 +36,7 @@ let
 
       keyFile = mkOption {
         default = null;
-        example = "/root/.swapkey";
+        example = "/mnt-root/root/.swapkey";
         type = types.nullOr types.str;
         description = "File system location of keyfile. This unlocks the drive after the root has been mounted to <literal>/mnt-root</literal>.";
       };
@@ -67,7 +67,6 @@ in
       luks = {
         devices =
           map (dev: { name = dev.encrypted.label; device = dev.encrypted.blkDev; } ) keylessEncDevs;
-        cryptoModules = [ "aes" "sha256" "sha1" "xts" ];
         forceLuksSupportInInitrd = true;
       };
       postMountCommands =
diff --git a/nixos/release.nix b/nixos/release.nix
index 4060e5df4ec1..63f739e8e896 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -214,6 +214,7 @@ in rec {
   # Run the tests for each platform.  You can run a test by doing
   # e.g. ‘nix-build -A tests.login.x86_64-linux’, or equivalently,
   # ‘nix-build tests/login.nix -A result’.
+  tests.atd = callTest tests/atd.nix {};
   tests.acme = callTest tests/acme.nix {};
   tests.avahi = callTest tests/avahi.nix {};
   tests.bittorrent = callTest tests/bittorrent.nix {};
@@ -249,6 +250,7 @@ in rec {
   tests.firewall = callTest tests/firewall.nix {};
   tests.fleet = hydraJob (import tests/fleet.nix { system = "x86_64-linux"; });
   #tests.gitlab = callTest tests/gitlab.nix {};
+  tests.gitolite = callTest tests/gitolite.nix {};
   tests.glance = callTest tests/glance.nix {};
   tests.gocd-agent = callTest tests/gocd-agent.nix {};
   tests.gocd-server = callTest tests/gocd-server.nix {};
@@ -306,6 +308,7 @@ in rec {
   tests.postgis = callTest tests/postgis.nix {};
   #tests.pgjwt = callTest tests/pgjwt.nix {};
   tests.printing = callTest tests/printing.nix {};
+  tests.prometheus = callTest tests/prometheus.nix {};
   tests.proxy = callTest tests/proxy.nix {};
   tests.pumpio = callTest tests/pump.io.nix {};
   # tests.quagga = callTest tests/quagga.nix {};
diff --git a/nixos/tests/atd.nix b/nixos/tests/atd.nix
new file mode 100644
index 000000000000..c2c0a716e0de
--- /dev/null
+++ b/nixos/tests/atd.nix
@@ -0,0 +1,36 @@
+import ./make-test.nix ({ pkgs, lib, ... }:
+
+{
+  name = "atd";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ bjornfor ];
+  };
+
+  machine =
+    { config, pkgs, ... }:
+    { services.atd.enable = true;
+      users.extraUsers.alice = { isNormalUser = true; };
+    };
+
+  # "at" has a resolution of 1 minute
+  testScript = ''
+    startAll;
+
+    $machine->fail("test -f ~root/at-1");
+    $machine->fail("test -f ~root/batch-1");
+    $machine->fail("test -f ~alice/at-1");
+    $machine->fail("test -f ~alice/batch-1");
+
+    $machine->succeed("echo 'touch ~root/at-1' | at now+1min");
+    $machine->succeed("echo 'touch ~root/batch-1' | batch");
+    $machine->succeed("su - alice -c \"echo 'touch at-1' | at now+1min\"");
+    $machine->succeed("su - alice -c \"echo 'touch batch-1' | batch\"");
+
+    $machine->succeed("sleep 1.5m");
+
+    $machine->succeed("test -f ~root/at-1");
+    $machine->succeed("test -f ~root/batch-1");
+    $machine->succeed("test -f ~alice/at-1");
+    $machine->succeed("test -f ~alice/batch-1");
+  '';
+})
diff --git a/nixos/tests/gitolite.nix b/nixos/tests/gitolite.nix
new file mode 100644
index 000000000000..643ea4ff03ef
--- /dev/null
+++ b/nixos/tests/gitolite.nix
@@ -0,0 +1,139 @@
+import ./make-test.nix ({ pkgs, ...}:
+
+let
+  adminPrivateKey = pkgs.writeText "id_ed25519" ''
+    -----BEGIN OPENSSH PRIVATE KEY-----
+    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+    QyNTUxOQAAACDu7qxYQAPdAU6RrhB3llk2N1v4PTwcVzcX1oX265uC3gAAAJBJiYxDSYmM
+    QwAAAAtzc2gtZWQyNTUxOQAAACDu7qxYQAPdAU6RrhB3llk2N1v4PTwcVzcX1oX265uC3g
+    AAAEDE1W6vMwSEUcF1r7Hyypm/+sCOoDmKZgPxi3WOa1mD2u7urFhAA90BTpGuEHeWWTY3
+    W/g9PBxXNxfWhfbrm4LeAAAACGJmb0BtaW5pAQIDBAU=
+    -----END OPENSSH PRIVATE KEY-----
+  '';
+
+  adminPublicKey = pkgs.writeText "id_ed25519.pub" ''
+    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO7urFhAA90BTpGuEHeWWTY3W/g9PBxXNxfWhfbrm4Le root@client
+  '';
+
+  alicePrivateKey = pkgs.writeText "id_ed25519" ''
+    -----BEGIN OPENSSH PRIVATE KEY-----
+    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+    QyNTUxOQAAACBbeWvHh/AWGWI6EIc1xlSihyXtacNQ9KeztlW/VUy8wQAAAJAwVQ5VMFUO
+    VQAAAAtzc2gtZWQyNTUxOQAAACBbeWvHh/AWGWI6EIc1xlSihyXtacNQ9KeztlW/VUy8wQ
+    AAAEB7lbfkkdkJoE+4TKHPdPQWBKLSx+J54Eg8DaTr+3KoSlt5a8eH8BYZYjoQhzXGVKKH
+    Je1pw1D0p7O2Vb9VTLzBAAAACGJmb0BtaW5pAQIDBAU=
+    -----END OPENSSH PRIVATE KEY-----
+  '';
+
+  alicePublicKey = pkgs.writeText "id_ed25519.pub" ''
+    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFt5a8eH8BYZYjoQhzXGVKKHJe1pw1D0p7O2Vb9VTLzB alice@client
+  '';
+
+  bobPrivateKey = pkgs.writeText "id_ed25519" ''
+    -----BEGIN OPENSSH PRIVATE KEY-----
+    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+    QyNTUxOQAAACCWTaJ1D9Xjxy6759FvQ9oXTes1lmWBciXPkEeqTikBMAAAAJDQBmNV0AZj
+    VQAAAAtzc2gtZWQyNTUxOQAAACCWTaJ1D9Xjxy6759FvQ9oXTes1lmWBciXPkEeqTikBMA
+    AAAEDM1IYYFUwk/IVxauha9kuR6bbRtT3gZ6ZA0GLb9txb/pZNonUP1ePHLrvn0W9D2hdN
+    6zWWZYFyJc+QR6pOKQEwAAAACGJmb0BtaW5pAQIDBAU=
+    -----END OPENSSH PRIVATE KEY-----
+  '';
+
+  bobPublicKey = pkgs.writeText "id_ed25519.pub" ''
+    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZNonUP1ePHLrvn0W9D2hdN6zWWZYFyJc+QR6pOKQEw bob@client
+  '';
+
+  gitoliteAdminConfSnippet = ''
+    repo alice-project
+        RW+     =   alice
+  '';
+in
+{
+  name = "gitolite";
+
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ bjornfor ];
+  };
+
+  nodes = {
+
+    server =
+      { config, pkgs, lib, ... }:
+      {
+        services.gitolite = {
+          enable = true;
+          adminPubkey = builtins.readFile adminPublicKey;
+        };
+        services.openssh.enable = true;
+      };
+
+    client =
+      { config, pkgs, lib, ... }:
+      {
+        environment.systemPackages = [ pkgs.git ];
+        programs.ssh.extraConfig = ''
+          Host *
+            UserKnownHostsFile /dev/null
+            StrictHostKeyChecking no
+            # there's nobody around that can input password
+            PreferredAuthentications publickey
+        '';
+        users.extraUsers.alice = { isNormalUser = true; };
+        users.extraUsers.bob = { isNormalUser = true; };
+      };
+
+  };
+
+  testScript = ''
+    startAll;
+
+    subtest "can setup ssh keys on system", sub {
+      $client->mustSucceed("mkdir -p ~root/.ssh");
+      $client->mustSucceed("cp ${adminPrivateKey} ~root/.ssh/id_ed25519");
+      $client->mustSucceed("chmod 600 ~root/.ssh/id_ed25519");
+
+      $client->mustSucceed("sudo -u alice mkdir -p ~alice/.ssh");
+      $client->mustSucceed("sudo -u alice cp ${alicePrivateKey} ~alice/.ssh/id_ed25519");
+      $client->mustSucceed("sudo -u alice chmod 600 ~alice/.ssh/id_ed25519");
+
+      $client->mustSucceed("sudo -u bob mkdir -p ~bob/.ssh");
+      $client->mustSucceed("sudo -u bob cp ${bobPrivateKey} ~bob/.ssh/id_ed25519");
+      $client->mustSucceed("sudo -u bob chmod 600 ~bob/.ssh/id_ed25519");
+    };
+
+    subtest "gitolite server starts", sub {
+      $server->waitForUnit("gitolite-init.service");
+      $server->waitForUnit("sshd.service");
+      $client->mustSucceed('ssh gitolite@server info');
+    };
+
+    subtest "admin can clone and configure gitolite-admin.git", sub {
+      $client->mustSucceed('git clone gitolite@server:gitolite-admin.git');
+      $client->mustSucceed("git config --global user.name 'System Administrator'");
+      $client->mustSucceed("git config --global user.email root\@domain.example");
+      $client->mustSucceed("cp ${alicePublicKey} gitolite-admin/keydir/alice.pub");
+      $client->mustSucceed("cp ${bobPublicKey} gitolite-admin/keydir/bob.pub");
+      $client->mustSucceed('(cd gitolite-admin && git add . && git commit -m "Add keys for alice, bob" && git push)');
+      $client->mustSucceed("printf '${gitoliteAdminConfSnippet}' >> gitolite-admin/conf/gitolite.conf");
+      $client->mustSucceed('(cd gitolite-admin && git add . && git commit -m "Add repo for alice" && git push)');
+    };
+
+    subtest "non-admins cannot clone gitolite-admin.git", sub {
+      $client->mustFail('sudo -i -u alice git clone gitolite@server:gitolite-admin.git');
+      $client->mustFail('sudo -i -u bob git clone gitolite@server:gitolite-admin.git');
+    };
+
+    subtest "non-admins can clone testing.git", sub {
+      $client->mustSucceed('sudo -i -u alice git clone gitolite@server:testing.git');
+      $client->mustSucceed('sudo -i -u bob git clone gitolite@server:testing.git');
+    };
+
+    subtest "alice can clone alice-project.git", sub {
+      $client->mustSucceed('sudo -i -u alice git clone gitolite@server:alice-project.git');
+    };
+
+    subtest "bob cannot clone alice-project.git", sub {
+      $client->mustFail('sudo -i -u bob git clone gitolite@server:alice-project.git');
+    };
+  '';
+})
diff --git a/nixos/tests/prometheus.nix b/nixos/tests/prometheus.nix
index ade097597bb8..374fb2d634b4 100644
--- a/nixos/tests/prometheus.nix
+++ b/nixos/tests/prometheus.nix
@@ -5,9 +5,6 @@ import ./make-test.nix {
     one = { config, pkgs, ... }: {
       services.prometheus = {
         enable = true;
-        globalConfig = {
-          labels = { foo = "bar"; };
-        };
         scrapeConfigs = [{
           job_name = "prometheus";
           static_configs = [{