colin
b658b93c64
this approach lets me persist the password. persisting /etc/shadow directly wasn't so feasible. populating /etc/shadow at activation time is something nix already does and is easy to plug into. so we store the passwd hash in this repo, but encrypt it to the destination machine's ssh pubkey to add enough entropy that it's not brute-forceable through the public git repo.
110 lines
4.8 KiB
Nix
110 lines
4.8 KiB
Nix
# borrows from:
|
|
# https://xeiaso.net/blog/paranoid-nixos-2021-07-18
|
|
# https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/
|
|
# https://github.com/nix-community/impermanence
|
|
{ lib, config, impermanence, ... }:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.sane.impermanence;
|
|
# taken from sops-nix code: checks if any secrets are needed to create /etc/shadow
|
|
secretsForUsers = (lib.filterAttrs (_: v: v.neededForUsers) config.sops.secrets) != {};
|
|
in
|
|
{
|
|
options = {
|
|
sane.impermanence.enable = mkOption {
|
|
default = false;
|
|
type = types.bool;
|
|
};
|
|
sane.impermanence.home-dirs = mkOption {
|
|
default = [];
|
|
type = types.listOf (types.either types.str (types.attrsOf types.str));
|
|
};
|
|
sane.impermanence.service-dirs = mkOption {
|
|
default = [];
|
|
type = types.listOf (types.either types.str (types.attrsOf types.str));
|
|
};
|
|
};
|
|
|
|
config = let
|
|
map-dir = defaults: dir: if isString dir then
|
|
map-dir defaults { directory = "${defaults.directory}${dir}"; }
|
|
else
|
|
defaults // dir
|
|
;
|
|
map-dirs = defaults: dirs: builtins.map (map-dir defaults) dirs;
|
|
|
|
map-home-dirs = map-dirs { user = "colin"; group = "users"; mode = "0755"; directory = "/home/colin/"; };
|
|
map-sys-dirs = map-dirs { user = "root"; group = "root"; mode = "0755"; directory = ""; };
|
|
|
|
in mkIf cfg.enable {
|
|
sane.image.extraDirectories = [ "/nix/persist/var/log" ];
|
|
environment.persistence."/nix/persist" = {
|
|
directories = (map-home-dirs cfg.home-dirs) ++ (map-sys-dirs [
|
|
# TODO: this `0700` here clobbers the perms for /persist/etc, breaking boot on freshly-deployed devices
|
|
# { mode = "0700"; directory = "/etc/NetworkManager/system-connections"; }
|
|
# "/etc/nixos"
|
|
# "/etc/ssh" # persist only the specific files we want, instead
|
|
"/var/log"
|
|
"/var/backup" # for e.g. postgres dumps
|
|
# "/var/lib/AccountsService" # not sure what this is, but it's empty
|
|
"/var/lib/alsa" # preserve output levels, default devices
|
|
# "/var/lib/blueman" # files aren't human readable
|
|
"/var/lib/bluetooth" # preserve bluetooth handshakes
|
|
"/var/lib/colord" # preserve color calibrations (?)
|
|
# "/var/lib/dhclient" # empty on lappy; dunno about desko
|
|
# "/var/lib/fwupd" # not sure why this would need persistent state
|
|
# "/var/lib/geoclue" # empty on lappy
|
|
# "/var/lib/lockdown" # empty on desko; might store secrets after iOS handshake?
|
|
# "/var/lib/logrotate.status" # seems redundant with what's in /var/log?
|
|
"/var/lib/machines" # maybe not needed, but would be painful to add a VM and forget.
|
|
# "/var/lib/misc" # empty on lappy
|
|
# "/var/lib/NetworkManager" # looks to be mostly impermanent state?
|
|
# "/var/lib/NetworkManager-fortisslvpn" # empty on lappy
|
|
# "/var/lib/nixos" # has some uid/gid maps, but we enforce these to be deterministic.
|
|
# "/var/lib/PackageKit" # wtf is this?
|
|
# "/var/lib/power-profiles-daemon" # redundant with nixos declarations
|
|
# "/var/lib/private" # empty on lappy
|
|
# "/var/lib/systemd" # nothing obviously necessary
|
|
# "/var/lib/udisks2" # empty on lappy
|
|
# "/var/lib/upower" # historic charge data. unnecessary, but maybe used somewhere?
|
|
#
|
|
# servo additions:
|
|
] ++ cfg.service-dirs);
|
|
files = [
|
|
"/etc/machine-id"
|
|
"/etc/ssh/ssh_host_ed25519_key"
|
|
"/etc/ssh/ssh_host_ed25519_key.pub"
|
|
"/etc/ssh/ssh_host_rsa_key"
|
|
"/etc/ssh/ssh_host_rsa_key.pub"
|
|
# # XXX these only need persistence because i have mutableUsers = true, i think
|
|
# "/etc/group"
|
|
# "/etc/passwd"
|
|
# "/etc/shadow"
|
|
];
|
|
};
|
|
|
|
# secret decoding depends on /etc/ssh keys, which are persisted
|
|
system.activationScripts.setupSecrets.deps = [ "persist-files" ];
|
|
# `setupSecretsForUsers` should depend on `persist-files`,
|
|
# but `persist-files` itself depends on `users`, to this would be circular.
|
|
# we work around that by manually mounting the ssh host key.
|
|
# strictly speaking, this makes the `setupSecrets -> persist-files` dep extraneous,
|
|
# but it's a decent safety net in case something goes wrong.
|
|
# system.activationScripts.setupSecretsForUsers.deps = [ "persist-files" ];
|
|
system.activationScripts.setupSecretsForUsers= lib.mkIf secretsForUsers {
|
|
deps = [ "persist-ssh-host-key" ];
|
|
};
|
|
system.activationScripts.persist-ssh-host-key = lib.mkIf secretsForUsers (
|
|
let
|
|
key = "/etc/ssh/ssh_host_ed25519_key";
|
|
in ''
|
|
mkdir -p /etc/ssh
|
|
touch ${key}
|
|
mount -o bind /nix/persist${key} ${key}
|
|
''
|
|
);
|
|
};
|
|
}
|
|
|