# SPDX-FileCopyrightText: 2020 Luke Granger-Brown # # SPDX-License-Identifier: Apache-2.0 { pkgs, config, depot, lib, rebuilder, ... }@args: let inherit (depot.ops) secrets; switch-prebuilt = import ./switch-prebuilt.nix args; # Default default priority is 1000; we use 900 here so we're higher priority, # but lower priority than user-specified things. This is particularly # important for our timezone setting, which otherwise conflicts with the one # set by the Clickhouse module, which is used by e.g. bvm-logger. mkDefault = lib.mkOverride 900; in { imports = [ ../../../third_party/home-manager/nixos ./vault-agent.nix ./vault-agent-secrets.nix ./secretsmgr.nix ./secretsmgr-acme.nix ./ssh-ca-vault.nix ]; options.my.specialisationName = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; options.my.rundeck.hostname = lib.mkOption { type = lib.types.str; default = config.networking.fqdn; }; options.my.rundeck.expectedOnline = lib.mkOption { type = lib.types.bool; default = true; }; options.my.rundeck.tags = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "nixos" ]; }; options.my.home-manager.imports = lib.mkOption { type = lib.types.listOf lib.types.path; default = [ ./home-manager/common.nix ]; }; options.my.home-manager.system = lib.mkOption { type = lib.types.nullOr lib.types.anything; default = null; }; options.my.prometheus.additionalExporterPorts = lib.mkOption { type = lib.types.attrsOf lib.types.port; default = {}; }; options.my.ip.tailscale = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; options.my.deploy.enable = lib.mkOption { type = lib.types.bool; default = true; }; options.my.deploy.args = lib.mkOption { type = lib.types.str; default = ""; }; options.my.scrapeJournal.enable = lib.mkOption { type = lib.types.bool; default = config.my.scrapeJournal.addr != null; }; options.my.scrapeJournal.addr = lib.mkOption { type = lib.types.nullOr lib.types.str; default = if config.my.ip.tailscale == null then null else "${config.my.ip.tailscale}:19531"; }; config = { hardware.enableRedistributableFirmware = true; networking.search = [ "int.as205479.net" "as205479.net" ]; services.resolved = { enable = true; llmnr = "false"; # LLMNR breaks search domains. dnssec = "false"; # DNSSEC support in systemd-resolved is just broken. domains = config.networking.search; extraConfig = '' # For global search domains to work, we also need global DNS servers. DNS=8.8.8.8#dns.google [2001:4860:4860::8888]#dns.google 1.1.1.1#cloudflare-dns.com [2606:4700:4700::1111]#cloudflare-dns.com ''; fallbackDns = [ "8.8.8.8" "2001:4860:4860::8888" "1.1.1.1" "2606:4700:4700::1111" ]; }; my.rundeck.tags = [ "nixos" ]; nix = { package = pkgs.nix_2_3; # Use a working nix. nixPath = [ "depot=/home/lukegb/depot/" "nixpkgs=/home/lukegb/depot/third_party/nixpkgs/" ]; settings = { trusted-users = [ "root" "@wheel" "deployer" ]; substituters = lib.mkForce [ "https://cache.nixos.org/" "s3://lukegb-nix-cache?endpoint=storage.googleapis.com&trusted=1" ]; trusted-substituters = lib.mkForce [ "https://cache.nixos.org/" "s3://lukegb-nix-cache?endpoint=storage.googleapis.com&trusted=1" ]; }; }; nixpkgs.config = depot.third_party.nixpkgsConfig; documentation.nixos.enable = false; # I just use the website. i18n.defaultLocale = "en_GB.UTF-8"; console.keyMap = "us"; time.timeZone = mkDefault "Etc/UTC"; zramSwap = { enable = true; memoryMax = 4 * 1024 * 1024 * 1024; }; environment.systemPackages = with pkgs; [ vim rxvt_unicode.terminfo tmux rebuilder tailscale rsync libarchive tcpdump restic alacritty.terminfo kitty.terminfo iftop htop jq depot.nix.pkgs.mercurial switch-prebuilt ]; networking.useDHCP = false; networking.firewall = { allowPing = true; logRefusedConnections = false; }; environment.homeBinInPath = true; security.pam.enableSSHAgentAuth = true; users.mutableUsers = false; users.users = let secrets = depot.ops.secrets; in { root.hashedPassword = secrets.passwordHashes.root; lukegb = { isNormalUser = true; uid = 1000; extraGroups = [ "wheel" "audio" ]; hashedPassword = secrets.passwordHashes.lukegb; openssh.authorizedKeys.keyFiles = [ ../../secrets/lukegb_totoro.pub ../../secrets/lukegb_termius.pub ../../secrets/lukegb_porcorosso_win.pub ../../secrets/lukegb_porcorosso_wsl.pub ../../secrets/lukegb_porcorosso_linux.pub ../../secrets/lukegb_red_solo.pub ]; }; deployer = { isSystemUser = true; uid = 1001; group = "deployer"; hashedPassword = "!"; useDefaultShell = true; home = "/var/lib/deployer"; createHome = true; openssh.authorizedKeys.keyFiles = [ ../../secrets/deployer_ed25519.pub ../../secrets/rundeck_deployer_rsa.pub ]; }; }; users.groups.deployer = {}; security.sudo.extraRules = [{ users = [ "deployer" ]; commands = [{ command = "${rebuilder}/bin/rebuilder"; options = [ "NOPASSWD" ]; } { command = "${switch-prebuilt}/bin/switch-prebuilt"; options = [ "NOPASSWD" ]; }]; }]; security.sudo.extraConfig = '' Defaults:deployer !requiretty ''; programs.mtr.enable = true; services.openssh.enable = true; services.tailscale.enable = true; networking.firewall.interfaces.tailscale0 = { # Just allow anything in on tailscale0. allowedTCPPortRanges = [{ from = 0; to = 65535; }]; allowedUDPPortRanges = [{ from = 0; to = 65535; }]; }; boot = { kernelModules = [ "tcp_bbr" ]; kernel.sysctl."net.ipv4.tcp_congestion_control" = "bbr"; kernel.sysctl."net.core.default_qdisc" = "fq_codel"; }; # Clean up daily. nix.gc = { automatic = mkDefault true; dates = "*-*-* 05:00:00"; options = "--delete-older-than 7d"; }; home-manager.useUserPackages = true; home-manager.useGlobalPkgs = true; systemd.services."home-manager-lukegb" = { before = [ "display-manager.service" ]; wantedBy = [ "multi-user.target" ]; }; home-manager.users.lukegb = { pkgs, ... }: ({ imports = [ ({ _module.args = args // { configName = null; }; })] ++ config.my.home-manager.imports ++ ( lib.optional (config.my.home-manager.system != null) config.my.home-manager.system ); }); services.prometheus.exporters.node = { enable = true; enabledCollectors = [ "systemd" "textfile" ]; extraFlags = [ "--collector.textfile.directory=/run/prometheus-textfile-exports" ]; }; system.activationScripts.node-exporter = { text = '' test -d /run/prometheus-textfile-exports || mkdir /run/prometheus-textfile-exports my_version_string="$(cat "$systemConfig/nixos-version")" my_hash_string="$(readlink -f "$systemConfig" | ${pkgs.gnugrep}/bin/grep -Eo '\b[0-9a-df-np-sv-z]{32}\b')" my_specialisation="$(cat "$systemConfig/specialisation-name" 2>/dev/null || true)" echo "nixos_running_system{version=\"$my_version_string\", hash=\"$my_hash_string\", specialisation=\"$my_specialisation\"} 1" > /run/prometheus-textfile-exports/running_system.prom my_version_string="$(cat "/run/booted-system/nixos-version")" my_hash_string="$(readlink -f "/run/booted-system" | ${pkgs.gnugrep}/bin/grep -Eo '\b[0-9a-df-np-sv-z]{32}\b')" my_specialisation="$(cat "/run/booted-system/specialisation-name" 2>/dev/null || true)" echo "nixos_booted_system{version=\"$my_version_string\", hash=\"$my_hash_string\", specialisation=\"$my_specialisation\"} 1" > /run/prometheus-textfile-exports/booted_system.prom ''; }; boot.postBootCommands = lib.mkAfter '' test -d /run/prometheus-textfile-exports || mkdir /run/prometheus-textfile-exports my_version_string="$(cat "/run/booted-system/nixos-version")" my_hash_string="$(readlink -f "/run/booted-system" | ${pkgs.gnugrep}/bin/grep -Eo '\b[0-9a-df-np-sv-z]{32}\b')" my_specialisation="$(cat "/run/booted-system/specialisation-name" 2>/dev/null || true)" echo "nixos_booted_system{version=\"$my_version_string\", hash=\"$my_hash_string\", specialisation=\"$my_specialisation\"} 1" > /run/prometheus-textfile-exports/booted_system.prom ''; system.extraSystemBuilderCmds = lib.mkAfter '' echo "${if config.my.specialisationName == null then "" else config.my.specialisationName}" > $out/specialisation-name ''; system.nixos.tags = lib.mkBefore ([ depot.version ] ++ lib.optional (config.my.specialisationName != null) "specialisation-${config.my.specialisationName}"); services.nginx = { recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; recommendedProxySettings = true; }; my.vault.secrets.nix-daemon = { template = '' {{ with secret "kv/apps/nix-daemon" }} AWS_ACCESS_KEY_ID={{ .Data.data.cacheAccessKeyID }} AWS_SECRET_ACCESS_KEY={{ .Data.data.cacheSecretAccessKey }} {{ end }} ''; group = "root"; reloadOrRestartUnits = [ "nix-daemon.service" ]; }; # - prefix to make the file existing optional. systemd.services.nix-daemon.serviceConfig.EnvironmentFile = "-${config.my.vault.secrets.nix-daemon.path}"; services.fwupd.enable = true; # This is enabled independently of my.scrapeJournal.enable. services.journald.enableHttpGateway = config.my.ip.tailscale != null; systemd.sockets.systemd-journal-gatewayd.socketConfig = lib.optionalAttrs (config.my.ip.tailscale != null) { ListenStream = [ "" "${config.my.ip.tailscale}:19531" ]; FreeBind = true; }; }; }