Group shared system settings

This commit is contained in:
ItsDrike 2024-04-13 19:05:42 +02:00
parent 31221a5d19
commit fca6296841
Signed by: ItsDrike
GPG key ID: FA2745890B7048C0
35 changed files with 16 additions and 11 deletions

View file

@ -0,0 +1,9 @@
_: {
imports = [
./loaders
./generic.nix
./secure-boot.nix
./initrd.nix
./plymouth.nix
];
}

View file

@ -0,0 +1,58 @@
{ config, lib, ... }: let
inherit (lib) mkDefault optionals;
cfg = config.myOptions.system.boot;
in {
boot = {
# kernel console loglevel
consoleLogLevel = 3;
# The NixOS default is to use an lts kernel, which can be quite old.
# My configuration defaults to the latest kernel instead
kernelPackages = cfg.kernel;
loader = {
# if set to 0, space needs to be held to get the boot menu to appear
timeout = 2;
# whether to copy the necessary boot files into /boot
# so that /nix/store is not needed by the boot loader.
generationsDir.copyKernels = true;
# allow installation to modify EFI variables
efi.canTouchEfiVariables = true;
};
tmp = {
# /tmp on tmpfs, lets it live on your ram
# it defaults to false, which means you will use disk space instead of ram
# enable tmpfs tmp on anything where you have ram to spare
useTmpfs = cfg.tmpOnTmpfs;
# if not using tmpfs, which is naturally purged on reboot, we must clean
# /tmp ourselves. /tmp should be volatile storage!
cleanOnBoot = mkDefault (!cfg.tmpOnTmpfs);
# The size of the tmpfs, in percentage form
# this defaults to 50% of your ram, which is a good default
# but should be tweaked based on your systems capabilities
tmpfsSize = mkDefault "50%";
};
kernelParams = (optionals cfg.silentBoot [
# tell the kernel to not be verbose
"quiet"
"loglevel=3" # 1: system is unusable | 3: error condition | 7: very verbose
# udev log message level
# rd prefix means systemd-udev will be used instead of initrd
"udev.log_level=3"
"rd.udev.log_level=3"
# disable systemd status messages
"systemd.show_status=auto"
"rd.systemd.show_status=auto"
]);
};
}

View file

@ -0,0 +1,28 @@
{pkgs, ...}: {
boot.initrd = {
# Verbosity of initrd.
# Disabling verbosity removes only the mandantory messages generated by NixOS
verbose = false;
systemd = {
# Enable systemd in initrd
# I prefe to use systemd in initrd, because it is more powerful than busybox
# however, it can result in slightly slower boot times.
enable = true;
# Strip copied binaries and libraries from initrd
# saves 30~ MB of space, according to the nix derivation
strip = true;
# Packages to include in the initrd
# This is useful for debugging, if the host provides
# emergency mode
storePaths = with pkgs; [util-linux pciutils];
extraBin = {
fdisk = "${pkgs.util-linux}/bin/fdisk";
lsblk = "${pkgs.util-linux}/bin/lsblk";
lspci = "${pkgs.pciutils}/bin/lspci";
};
};
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
./systemd-boot.nix
];
}

View file

@ -0,0 +1,18 @@
{ config, lib, ... }: let
cfg = config.myOptions.system.boot;
in {
boot.loader.systemd-boot = {
enable = true;
memtest86.enable = true;
# Enabling the editor will allow anyone to change the kernel params.
# This can be useful for debugging, however it is a potential security hole
# as this allows setting init=/bin/bash, which will boot directly into bash
# as root, bypassing any need for authentication.
#
# If you're using an encrypted setup, and you can't get into the system without
# entering a decryption password (or have TPM release it conditionally, only if
# the kernel parameters remain the same), this can safely be enabled.
editor = lib.mkDefault false;
};
}

View file

@ -0,0 +1,32 @@
{ config, lib, pkgs, ...}: let
inherit (lib) mkIf;
cfg = config.myOptions.system.boot.plymouth;
in {
config = mkIf cfg.enable {
boot = {
plymouth = {
enable = true;
theme = cfg.selectedTheme;
}
// lib.optionalAttrs cfg.withThemes {
themePackages = [
(pkgs.adi1090x-plymouth-themes.override {
selected_themes = [ cfg.selectedTheme ];
})
];
};
kernelParams = ["splash"];
};
# Make polymouth work with sleep
powerManagement = {
powerDownCommands = ''
${pkgs.plymouth} --show-splash
'';
resumeCommands = ''
${pkgs.plymouth} --quit
'';
};
};
}

View file

@ -0,0 +1,23 @@
{ config, pkgs, lib, ... }: let
inherit (lib) mkIf;
cfg = config.myOptions.system.boot.secure-boot;
in {
config = mkIf cfg.enable {
# Secure Boot Key Manager
environment.systemPackages = [ pkgs.sbctl ];
# Persist the secure boot keys (for impermanence)
myOptions.system.impermanence.root.extraDirectories = [
"/etc/secureboot"
];
# Lanzaboote replaces systemd-boot
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.lanzaboote = {
enable = true;
pkiBundle = "/etc/secureboot";
};
};
}

14
system/shared/default.nix Normal file
View file

@ -0,0 +1,14 @@
_: {
imports = [
./hardware
./boot
./services
./nix
./environment
./impermanence
./programs.nix
./system.nix
./network.nix
./localisation.nix
];
}

View file

@ -0,0 +1,7 @@
{
imports = [
./packages.nix
./paths.nix
./variables.nix
];
}

View file

@ -0,0 +1,11 @@
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [
curl
wget
pciutils
lshw
man-pages
rsync
bind.dnsutils
];
}

View file

@ -0,0 +1,9 @@
{
# enable completions for system packages
# and other stuff
environment.pathsToLink = [
"/share/zsh" # zsh completions
"/share/bash-completion" # bash completions
"/share/nix-direnv" # direnv completions
];
}

View file

@ -0,0 +1,15 @@
{
# variables that I want to set globally on all systems
environment.variables = {
# editors
EDITOR = "nvim";
VISUAL = "nvim";
SUDO_EDITOR = "nvim";
# pager stuff
SYSTEMD_PAGERSECURE = "true";
PAGER = "less -FR";
MANPAGER = "nvim +Man!";
};
}

View file

@ -0,0 +1,9 @@
{ config, lib, ... }:
let
dev = config.myOptions.device;
in
{
config = lib.mkIf (dev.cpu.type == "amd") {
hardware.cpu.amd.updateMicrocode = true;
};
}

View file

@ -0,0 +1,6 @@
_: {
imports = [
./amd.nix
./intel.nix
];
}

View file

@ -0,0 +1,9 @@
{ config, lib, ... }:
let
dev = config.myOptions.device;
in
{
config = lib.mkIf (dev.cpu.type == "intel") {
hardware.cpu.intel.updateMicrocode = true;
};
}

View file

@ -0,0 +1,7 @@
_: {
imports = [
./cpu
./tpm.nix
./generic.nix
];
}

View file

@ -0,0 +1,9 @@
{lib, ...}: {
# This enables non-free firmware on devices not recognized by `nixos-generate-config`.
# Disabling this option will make the system unbootable if such devices are critical
# in your boot chain - therefore this should remain true until you are running a device
# with mostly libre firmware. Which there is not many of.
# Without this, it defaults to `config.hardware.enableAllFirmware`.
hardware.enableRedistributableFirmware = lib.mkDefault true;
}

View file

@ -0,0 +1,26 @@
{ config, lib, pkgs, ... }: let
inherit (lib) mkIf mkDefault;
enabled = config.myOptions.device.hasTPM;
in {
config = mkIf enabled {
security.tpm2 = {
# enable Trusted Platform Module 2 support
enable = true;
# enable Trusted Platform 2 userspace resource manager daemon
abrmd.enable = mkDefault false;
# The TCTI is the "Transmission Interface" that is used to communicate with a
# TPM. this option sets TCTI environment variables to the specified values if enabled
# - TPM2TOOLS_TCTI
# - TPM2_PKCS11_TCTI
tctiEnvironment.enable = mkDefault true;
# enable TPM2 PKCS#11 tool and shared library in system path
pkcs11.enable = mkDefault false;
};
environment.systemPackages = with pkgs; [ tpm2-tss tpm2-tools ];
};
}

View file

@ -0,0 +1,72 @@
{ config, lib, ... }: let
inherit (lib) mkIf concatStringsSep flatten mapAttrsToList;
cfg = config.myOptions.system.impermanence.autoWipeBtrfs;
in
{
config = mkIf cfg.enable {
boot.initrd.systemd = {
enable = true; # This enables systemd support in stage 1 - required for below setup
services.rollback = {
description = "Rollback BTRFS subvolumes to a pristine state";
enable = true;
wantedBy = [ "initrd.target" ];
# Make sure it's done after decryption (i.e. LUKS/TPM process)
after = [ "systemd-cryptsetup@cryptfs.service" ];
# mount the root fs before clearing
before = [ "sysroot.mount" ];
unitConfig.DefaultDependencies = "no";
serviceConfig.Type = "oneshot";
script = let
# TODO: Consider adding support for moving the subvolume to something like old-roots
# instead of deleting it. This would allow for easier recovery in case of a mistake.
# The subvolume can live here for a certain amount of time, before it's deleted, or there
# can be a certain amount of total roots kept. See the example configuration here:
# <https://github.com/nix-community/impermanence> which demonstrates keepping 30 days
# worth of old roots.
wipeScript = devicePath: subvolumes: ''
# Mount the BTRFS device root to a temporary mount point
echo "Mounting BTRFS root from ${devicePath} to /mnt"
mount --mkdir "${devicePath}" /mnt
# Recreate each specified subvolume
${concatStringsSep "\n" (map (subvolume: ''
delete_subvolume_recursively "/mnt/${subvolume}"
btrfs subvolume create "/mnt/${subvolume}"
'') subvolumes)}
# Cleanup: unmount the device
echo "Unmounting BTRFS root from ${devicePath}"
umount /mnt
'';
in ''
# Simply deleting a subvolume with btrfs subvolume delete will not work,
# if that subvolume contains other btrfs subvolumes. Because of that, we
# instead use this function to delete subvolumes, whihc will first perform
# a recursive deletion of any nested subvolumes.
#
# This is necessary, because the root subvolume will actually usually contain
# other subvolumes, even if the user haven't created those explicitly. It seems
# that NixOS creates these automatically. Namely, I observed these in root subvol:
# - root/srv
# - root/var/lib/portables
# - root/var/lib/machines
# - root/var/tmp
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/mnt/$i"
done
echo "Deleting subvolume $1"
btrfs subvolume delete "$1"
}
${concatStringsSep "\n" (mapAttrsToList (devicePath: deviceOpts:
wipeScript devicePath deviceOpts.subvolumes
) cfg.devices)}
'';
};
};
};
}

View file

@ -0,0 +1,7 @@
{ inputs, ... }:
{
imports = [
./root.nix
./autowipe.nix
];
}

View file

@ -0,0 +1,66 @@
{ config, lib, ... }: let
inherit (lib) mkIf mkForce;
cfgSystem = config.myOptions.system;
cfg = config.myOptions.system.impermanence.root;
in
{
config = mkIf cfg.enable {
users = {
# This option makes it that users are not mutable outside of our configuration.
# If you're using root impermanence, this will actually be the case regardless
# of this setting, however, setting this explicitly is a good idea, because nix
# will warn us if our users don't have passwords set, preventing lock outs.
mutableUsers = false;
# Each existing user needs to have a password file defined here, otherwise
# they will not be available to login. These password files can be generated with:
# mkpasswd -m sha-512 > /persist/passwords/myuser
users = {
root = {
hashedPasswordFile = "${cfg.persistentMountPoint}/passwords/root";
};
${cfgSystem.username} = {
hashedPasswordFile = "${cfg.persistentMountPoint}/passwords/${cfgSystem.username}";
};
};
};
environment.persistence."${cfg.persistentMountPoint}/system" = {
hideMounts = true;
directories = [
"/etc/nixos" # NixOS configuration source
"/etc/NetworkManager/system-connections" # saved network connections
"/var/db/sudo" # keeps track of who got the sudo lecture already
"/var/lib/systemd/coredump" # captured coredumps
] ++ cfg.extraDirectories;
files = [
"/etc/machine-id"
] ++ cfg.extraFiles;
};
# For some reason, NetworkManager needs this instead of the impermanence mode
# to not get screwed up
systemd.tmpfiles.rules = [
"L /var/lib/NetworkManager/secret_key - - - - ${cfg.persistentMountPoint}/system/var/lib/NetworkManager/secret_key"
"L /var/lib/NetworkManager/seen-bssids - - - - ${cfg.persistentMountPoint}/system/var/lib/NetworkManager/seen-bssids"
"L /var/lib/NetworkManager/timestamps - - - - ${cfg.persistentMountPoint}/system/var/lib/NetworkManager/timestamps"
];
# Define host key paths in the persistent mount point instead of using impermanence for these.
# This works better, because these keys also get auto-created if they don't already exist.
services.openssh.hostKeys = mkForce [
{
bits = 4096;
path = "${cfg.persistentMountPoint}/system/etc/ssh/ssh_host_rsa_key";
type = "rsa";
}
{
bits = 4096;
path = "${cfg.persistentMountPoint}/system/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
];
};
}

View file

@ -0,0 +1,4 @@
_: {
time.timeZone = "CET";
i18n.defaultLocale = "en_US.UTF-8";
}

19
system/shared/network.nix Normal file
View file

@ -0,0 +1,19 @@
{ lib, ... }:
{
networking = {
firewall.enable = false;
networkmanager = {
enable = true;
dns = "systemd-resolved";
};
};
services.resolved = {
enable = true;
fallbackDns = [
"9.9.9.9"
"2620:fe::fe"
];
};
}

View file

@ -0,0 +1,25 @@
_: {
nix.settings = {
# Set up various binary cache providers, compiling everything is too slow and annoying
# these will be used on all machines, but there's really no reason not to include all
# providers, even if we won't pull some of the packages these cache
substituters = [
"https://cache.nixos.org"
"https://nix-community.cachix.org" # nix-community flake
"https://nixpkgs-unfree.cachix.org" # unfree-package cache
"https://numtide.cachix.org" # another unfree package cache
"https://nixpkgs-wayland.cachix.org" # automated builds of *some* wayland packages
"https://hyprland.cachix.org" # hyprland
"https://ags.cachix.org" # ags
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"nixpkgs-unfree.cachix.org-1:hqvoInulhbV4nJ9yJOEr+4wxhDV4xq2d1DK7S6Nj6rs="
"numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE="
"nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA="
"hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="
"ags.cachix.org-1:naAvMrz0CuYqeyGNyLgE010iUiuf/qx6kYrUv3NwAJ8="
];
};
}

View file

@ -0,0 +1,43 @@
{ pkgs, ... }:
{
imports = [
./cachix.nix
./gc.nix
];
system.autoUpgrade.enable = false;
nix = {
settings = {
# enable flakes support
experimental-features = [ "nix-command" "flakes" ];
# Keep the built outputs of derivations in Nix store, even if the package is no longer needed
# - prevents the need to rebuild/redownload if it becomes a dependency again
# - helps with debugging or reverting to previous state
keep-outputs = true;
# Keep the derivations themselves too. A derivation describes how to build a package.
# - allows inspecting the build process of a package for debugging or educational purposes
# - allows rebuilding a package from its exact specification without having to fetch again
# - ensures we can reproduce a build even if the original online source goes down/changes
keep-derivations = true;
# Give these users/groups additional rights when connecting to the Nix daemon
# like specifying extra binary caches
trusted-users = [ "root" "@wheel" ];
# Tell nix to use xdg base directories
# If you're just setting this, you will need to move the directories
# manually, nix won't do it for you:
# - mv "$HOME/.nix-defexpr" "$XDG_STATE_HOME/nix/defexpr"
# - mv "$HOME/.nix-profile" "$XDG_STATE_HOME/nix/profile"
use-xdg-base-directories = true;
};
};
nixpkgs.config.allowUnfree = true;
# Git is needed for flakes
environment.systemPackages = [ pkgs.git ];
}

27
system/shared/nix/gc.nix Normal file
View file

@ -0,0 +1,27 @@
_: {
nix = {
settings = {
# nix often takes up a lot of space, with /nix/store growing beyond reasonable sizes
# this turns on automatic optimisation of the nix store that will run during every build
# (alternatively, you can do this manually with `nix-store --optimise`)
auto-optimise-store = true;
};
# Enable automatic garbage collection, deleting entries older than 7 days
# you can also run this manually with `nix-store --gc --delete-older-than 7d`.
# If a result still exists in the file system, all the dependencies used to build
# it will be kept.
gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
# Also run garbage colleciton whenever there is not enough space left,
# freeing up to 1 GiB whenever there is less than 512MiB left.
extraOptions = ''
min-free = ${toString (512 * 1024 * 1024)}
max-free = ${toString (1024 * 1024 * 1024)}
'';
};
}

View file

@ -0,0 +1,10 @@
{
# Install an actually usable system-wide editor
programs.neovim = {
enable = true;
defaultEditor = true;
vimAlias = true;
viAlias = true;
};
}

View file

@ -0,0 +1,9 @@
_: {
imports = [
./ssh.nix
./fwupd.nix
./logrotate.nix
./oomd.nix
./thermald.nix
];
}

View file

@ -0,0 +1,7 @@
{config, ...}: {
# firmware updater for machine hardware
services.fwupd = {
enable = true;
daemonSettings.EspLocation = config.boot.loader.efi.efiSysMountPoint;
};
}

View file

@ -0,0 +1,24 @@
{ pkgs, lib, ... }: {
services.logrotate.settings.header = {
# general
global = true;
dateext = true;
dateformat = "-%Y-%m-%d";
nomail = true;
missingok = true;
copytruncate = true;
# rotation frequency
priority = 1;
frequency = "weekly";
rotate = 7; # special value, means 7 days
minage = 7; # avoid rotating files that are less than 7 days old
# compression
compress = true; # compress logs to save space
compresscmd = "${lib.getExe' pkgs.zstd "zstd"}";
compressoptions = " -Xcompression-level 10";
compressext = "zst";
uncompresscmd = "${lib.getExe' pkgs.zstd "unzstd"}";
};
}

View file

@ -0,0 +1,20 @@
{ lib, ... }: {
systemd = {
# OOMd: Out Of Memory daemon
# By default, this will only kill cgroups. So either systemd services
# marked for killing uder OOM or (non-default, but enabled here) the entire user slice.
oomd = {
enable = true;
enableSystemSlice = true;
enableRootSlice = true;
enableUserSlices = true;
extraConfig = {
"DefaultMemoryPressureDurationSec" = "20s";
};
};
# Make nix builds more likely to get killed than other important services.
# The default for user slices is 100, and systemd-coredumpd is 500
services.nix-daemon.serviceConfig.OOMScoreAdjust = lib.mkDefault 350;
};
}

View file

@ -0,0 +1,12 @@
{ ... }: {
# TODO: This really shouldn't be a default service in system/
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
X11Forwarding = false;
};
};
}

View file

@ -0,0 +1,4 @@
{
# monitor and control temperature
services.thermald.enable = true;
}

24
system/shared/system.nix Normal file
View file

@ -0,0 +1,24 @@
{ config, lib, pkgs, ... }: with lib; let
cfg = config.myOptions.system;
in
{
networking.hostName = cfg.hostname;
# Default shell for the user
programs.zsh.enable = true;
users = {
# Prevent mutating users outside of our configurations.
# TODO: Solve this, currentry it fails with no password
# specified for root account nor any whell user accounts
# and wants us to set pw manually with passwd, which needs
# mutableUsers
#mutableUsers = false;
users.${cfg.username} = {
isNormalUser = true;
extraGroups = [ "wheel" ];
shell = pkgs.zsh;
};
};
}