From 1a6f73119f74bc21146212f361e87be05fad79d0 Mon Sep 17 00:00:00 2001
From: adisbladis <adisbladis@gmail.com>
Date: Sun, 11 Aug 2019 19:53:02 +0100
Subject: [PATCH] Modularise setup, add hardening config

---
 build01/configuration.nix | 17 ++++++-------
 profiles/common.nix       | 52 +++++++++++++++++++++++++++++++++++++++
 profiles/docker.nix       | 15 +++++++++++
 profiles/security.nix     | 24 ++++++++++++++++++
 users/adisbladis.nix      | 22 +++++++++++++++++
 users/lib.nix             | 17 +++++++++++++
 6 files changed, 137 insertions(+), 10 deletions(-)
 create mode 100644 profiles/common.nix
 create mode 100644 profiles/docker.nix
 create mode 100644 profiles/security.nix
 create mode 100644 users/adisbladis.nix
 create mode 100644 users/lib.nix

diff --git a/build01/configuration.nix b/build01/configuration.nix
index b0277b0..5b589c6 100644
--- a/build01/configuration.nix
+++ b/build01/configuration.nix
@@ -1,9 +1,14 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
 {
   imports = [
     ./hardware-configuration.nix
     ./buildkite.nix
+
+    ../profiles/common.nix
+    ../profiles/docker.nix
+
+    ../users/adisbladis.nix
   ];
 
   # /boot is a mirror raid
@@ -29,17 +34,9 @@
     '';
   };
 
-  services.openssh.enable = true;
-
-  users.users.root.openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtr+rcxCZBAAqt8ocvhEEdBWfnRBCljjQPtC6Np24Y3H/HMe3rugsu3OhPscRV1k5hT+UlA2bpN8clMFAfK085orYY7DMUrgKQzFB7GDnOvuS1CqE1PRw7/OHLcWxDwf3YLpa8+ZIwMHFxR2gxsldCLGZV/VukNwhEvWs50SbXwVrjNkwA9LHy3Or0i6sAzU711V3B2heB83BnbT8lr3CKytF3uyoTEJvDE7XMmRdbvZK+c48bj6wDaqSmBEDrdNncsqnReDjScdNzXgP1849kMfIUwzXdhEF8QRVfU8n2A2kB0WRXiGgiL4ba5M+N9v1zLdzSHcmB0veWGgRyX8tN cardno:000607203159" ];
   boot.kernelPackages = pkgs.linuxPackages_latest;
   boot.supportedFilesystems = [ "zfs" ];
 
-  networking.firewall.enable = true;
-  networking.firewall.allowedTCPPorts = [
-    22
-  ];
-
-  system.stateVersion = "18.03"; # Did you read the comment?
+  system.stateVersion = "19.09";
 
 }
diff --git a/profiles/common.nix b/profiles/common.nix
new file mode 100644
index 0000000..e9eb80d
--- /dev/null
+++ b/profiles/common.nix
@@ -0,0 +1,52 @@
+{ pkgs, lib, config, ... }:
+
+{
+
+  imports = [ ./security.nix ];
+
+  # Nicer interactive shell
+  programs.fish.enable = true;
+  # And for the zsh peeps
+  programs.zsh.enable = true;
+
+  # Entropy gathering daemon
+  services.haveged.enable = true;
+
+  nix = let
+    asGB = size: toString (size * 1024 * 1024);
+  in {
+    extraOptions = ''
+      # auto-free the /nix/store
+      min-free = ${asGB 10}
+      max-free = ${asGB 200}
+    '';
+    # Hard-link duplicated files
+    autoOptimiseStore = true;
+  };
+
+  # No mutable users
+  users.mutableUsers = false;
+
+  services.openssh.enable = true;
+  networking.firewall.allowedTCPPorts = [
+    22
+  ];
+
+  # Make debugging failed units easier
+  systemd.extraConfig = ''
+    DefaultStandardOutput=journal
+    DefaultStandardError=journal
+  '';
+
+  # The nix-community is global :)
+  time.timeZone = "UTC";
+
+  # Assign keys from all users in wheel group
+  # This is only done because nixops cant be deployed from any other account
+  users.extraUsers.root.openssh.authorizedKeys.keys = lib.unique (lib.flatten (
+    builtins.map (u: u.openssh.authorizedKeys.keys)
+      (lib.attrValues (lib.filterAttrs (_: u: lib.elem "wheel" u.extraGroups)
+        config.users.extraUsers))));
+
+
+}
diff --git a/profiles/docker.nix b/profiles/docker.nix
new file mode 100644
index 0000000..e36b1e1
--- /dev/null
+++ b/profiles/docker.nix
@@ -0,0 +1,15 @@
+{...}:
+
+{
+
+  virtualisation.docker = {
+    enable = true;
+    # Clean docker images periodically
+    autoPrune = {
+      enable = true;
+      # Do not only remove "dangling" images (orphaned layers), also remove unused
+      flags = [ "--all" ];
+    };
+  };
+
+}
diff --git a/profiles/security.nix b/profiles/security.nix
new file mode 100644
index 0000000..1f766a9
--- /dev/null
+++ b/profiles/security.nix
@@ -0,0 +1,24 @@
+{ config, pkgs, lib, ... }:
+
+{
+
+  # Allow sudo from SSH authenticated users
+  # This requires users in the wheel group to log in
+  # over ssh with an agent and enable forwarding
+  security.pam.services.sudo.sshAgentAuth = true;
+  security.pam.enableSSHAgentAuth = true;
+
+  # Dont let users create their own authorized keys files
+  services.openssh.authorizedKeysFiles = lib.mkForce [
+    "/etc/ssh/authorized_keys.d/%u"
+  ];
+
+  networking.firewall.enable = true;
+
+  services.openssh.challengeResponseAuthentication = false;
+  services.openssh.passwordAuthentication = false;
+
+  # Ban brute force SSH
+  services.fail2ban.enable = true;
+
+}
diff --git a/users/adisbladis.nix b/users/adisbladis.nix
new file mode 100644
index 0000000..d33d263
--- /dev/null
+++ b/users/adisbladis.nix
@@ -0,0 +1,22 @@
+{ config, pkgs, lib, ... }:
+
+let
+  userLib = import ./lib.nix { inherit lib; };
+  keys = [
+    "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtr+rcxCZBAAqt8ocvhEEdBWfnRBCljjQPtC6Np24Y3H/HMe3rugsu3OhPscRV1k5hT+UlA2bpN8clMFAfK085orYY7DMUrgKQzFB7GDnOvuS1CqE1PRw7/OHLcWxDwf3YLpa8+ZIwMHFxR2gxsldCLGZV/VukNwhEvWs50SbXwVrjNkwA9LHy3Or0i6sAzU711V3B2heB83BnbT8lr3CKytF3uyoTEJvDE7XMmRdbvZK+c48bj6wDaqSmBEDrdNncsqnReDjScdNzXgP1849kMfIUwzXdhEF8QRVfU8n2A2kB0WRXiGgiL4ba5M+N9v1zLdzSHcmB0veWGgRyX8tN cardno:000607203159"
+  ];
+
+in {
+  users.users.adisbladis = {
+    openssh.authorizedKeys.keys = keys;
+    useDefaultShell = true;
+    isNormalUser = true;
+    extraGroups = [
+      "wheel"
+    ];
+    uid = userLib.mkUid "adis";
+  };
+
+  nix.trustedUsers = [ "adisbladis" ];
+
+}
diff --git a/users/lib.nix b/users/lib.nix
new file mode 100644
index 0000000..d915fc9
--- /dev/null
+++ b/users/lib.nix
@@ -0,0 +1,17 @@
+{ lib }:
+
+let
+  chrs = lib.listToAttrs (lib.imap (i: v: {name=v; value=i + 96;}) lib.lowerChars);
+  ord = c: builtins.getAttr c chrs;
+
+in {
+  # Make a unique UID from a 4-char identifier
+  mkUid = id: let  # TODO: Assert length
+    chars = lib.stringToCharacters id;
+    n = builtins.map (c: lib.mod (ord c) 10) chars;
+    s = builtins.concatStringsSep "" (builtins.map (i: builtins.toString i) n);
+
+  in
+    assert lib.length chars == 4;
+    1000 + lib.toInt s;
+}