{ config, pkgs, lib, ... }: with lib; let cfg = config.krebs.sync-containers; paths = cname: { plain = "/var/lib/containers/${cname}/var/state"; ecryptfs = "${cfg.dataLocation}/${cname}/ecryptfs"; securefs = "${cfg.dataLocation}/${cname}/securefs"; luksfile = "${cfg.dataLocation}/${cname}/luksfile"; }; init = cname: { plain = '' echo 'no need for init' ''; ecryptfs = '' ${pkgs.ecrypt}/bin/ecrypt init ${cfg.dataLocation}/${cname}/ecryptfs /var/lib/containers/${cname}/var/state ''; securefs = '' ${pkgs.securefs}/bin/securefs create --format 3 ${cfg.dataLocation}/${cname}/securefs ''; luksfile = '' ${pkgs.coreutils}/bin/truncate -s 10G '${(paths cname).luksfile}/fs.luks' ${pkgs.cryptsetup}/bin/cryptsetup luksFormat '${(paths cname).luksfile}/fs.luks' ${pkgs.cryptsetup}/bin/cryptsetup luksOpen '${(paths cname).luksfile}/fs.luks' 'luksfile-${cname}' ${pkgs.xfsprogs}/bin/mkfs.xfs '/dev/mapper/luksfile-${cname}' ''; }; start = cname: { plain = '' : ''; ecryptfs = '' if [ -e ${cfg.dataLocation}/${cname}/ecryptfs/.cfg.json ]; then if ! mount | grep -q '${cfg.dataLocation}/${cname}/ecryptfs on /var/lib/containers/${cname}/var/state type ecryptfs'; then ${pkgs.ecrypt}/bin/ecrypt mount ${cfg.dataLocation}/${cname}/ecryptfs /var/lib/containers/${cname}/var/state fi else echo 'please run init-${cname} first' exit 1 fi ''; securefs = '' ## check if FS was initialized first if ! ${pkgs.mount}/bin/mount | grep -q '^securefs on /var/lib/containers/${cname}/var/state type fuse.securefs'; then ${pkgs.securefs}/bin/securefs mount ${cfg.dataLocation}/${cname}/securefs /var/lib/containers/${cname}/var/state -b -o allow_other -o default_permissions fi ''; luksfile = '' mkdir -p /var/lib/containers/${cname}/var/state if ! test -e /dev/mapper/luksfile-${cname}; then ${pkgs.cryptsetup}/bin/cryptsetup luksOpen '${(paths cname).luksfile}/fs.luks' 'luksfile-${cname}' fi if ! ${pkgs.mount}/bin/mount | grep -q '^/dev/mapper/luksfile-${cname} on /var/lib/containers/${cname}/var/state'; then mount '/dev/mapper/luksfile-${cname}' '/var/lib/containers/${cname}/var/state' fi ''; }; stop = cname: { plain = '' : ''; ecryptfs = '' ${pkgs.ecrypt}/bin/ecrypt unmount ${cfg.dataLocation}/${cname}/ecryptfs /var/lib/containers/${cname}/var/state ''; securefs = '' umount /var/lib/containers/${cname}/var/state ''; luksfile = '' umount /var/lib/containers/${cname}/var/state ${pkgs.cryptsetup}/bin/cryptsetup luksClose luksfile-${cname} ''; }; in { options.krebs.sync-containers = { dataLocation = mkOption { description = '' location where the encrypted sync-containers lie around ''; default = "/var/lib/sync-containers"; type = types.absolute-pathname; }; containers = mkOption { type = types.attrsOf (types.submodule ({ config, ... }: { options = { name = mkOption { description = '' name of the container ''; default = config._module.args.name; type = types.str; }; peers = mkOption { description = '' syncthing peers to share this container with ''; default = []; type = types.listOf types.str; }; format = mkOption { description = '' file system encrption format of the container ''; type = types.enum [ "plain" "ecryptfs" "securefs" "luksfile" ]; }; }; })); default = {}; }; }; config = mkIf (cfg.containers != {}) { programs.fuse.userAllowOther = true; # allow syncthing to enter /var/lib/containers system.activationScripts.containers-enter = mkDefault '' ${pkgs.coreutils}/bin/chmod a+x /var/lib/containers || : ''; services.syncthing.folders = (mapAttrs' (_: ctr: nameValuePair "${(paths ctr.name).${ctr.format}}" ({ devices = ctr.peers; ignorePerms = false; })) cfg.containers); krebs.acl = mapAttrs' (_: ctr: nameValuePair "${(paths ctr.name).${ctr.format}}" { "u:syncthing:rX".parents = true; "u:syncthing:rwX" = {}; }) cfg.containers; systemd.services = mapAttrs' (n: ctr: nameValuePair "containers@${ctr.name}" ({ reloadIfChanged = mkForce false; })) cfg.containers; containers = mapAttrs' (n: ctr: nameValuePair ctr.name ({ config = { ... }: { environment.systemPackages = [ pkgs.dhcpcd pkgs.git pkgs.jq ]; networking.useDHCP = mkForce true; system.activationScripts.fuse = { text = '' ${pkgs.coreutils}/bin/mknod /dev/fuse c 10 229 ''; deps = []; }; }; allowedDevices = [ { modifier = "rwm"; node = "/dev/fuse"; } ]; autoStart = false; enableTun = true; privateNetwork = true; hostBridge = "ctr0"; })) cfg.containers; networking.networkmanager.unmanaged = [ "ctr0" ]; networking.bridges.ctr0.interfaces = []; networking.interfaces.ctr0.ipv4.addresses = [{ address = "10.233.0.1"; prefixLength = 24; }]; # networking.nat = { # enable = true; # externalInterface = lib.mkDefault "et0"; # internalInterfaces = [ "ctr0" ]; # }; services.dhcpd4 = { enable = true; interfaces = [ "ctr0" ]; extraConfig = '' option subnet-mask 255.255.255.0; option routers 10.233.0.1; # option domain-name-servers 8.8.8.8; # TODO configure dns server subnet 10.233.0.0 netmask 255.255.255.0 { range 10.233.0.10 10.233.0.250; } ''; }; users.users.root.packages = flatten (mapAttrsToList (n: ctr: [ (pkgs.writeDashBin "init-${ctr.name}" '' set -euf set -x mkdir -p /var/lib/containers/${ctr.name}/var/state STATE=$(/run/current-system/sw/bin/nixos-container status ${ctr.name}) if [ "$STATE" = 'up' ]; then /run/current-system/sw/bin/nixos-container stop ${ctr.name} fi ${(init ctr.name).${ctr.format}} ${(start ctr.name).${ctr.format}} /run/current-system/sw/bin/nixos-container start ${ctr.name} /run/current-system/sw/bin/nixos-container run ${ctr.name} -- ${pkgs.writeDash "deploy-${ctr.name}" '' set -x mkdir -p /var/state/var_src ln -sfTr /var/state/var_src /var/src touch /etc/NIXOS ''} target_ip=$(/run/current-system/sw/bin/nixos-container run ${ctr.name} -- ip -j a s eth0 | jq -r '.[].addr_info[] | select(.family=="inet") | .local') echo "deploy to $target_ip" '') (pkgs.writeDashBin "start-${ctr.name}" '' set -euf set -x mkdir -p /var/lib/containers/${ctr.name}/var/state ${(start ctr.name).${ctr.format}} STATE=$(/run/current-system/sw/bin/nixos-container status ${ctr.name}) if [ "$STATE" = 'down' ]; then /run/current-system/sw/bin/nixos-container start ${ctr.name} fi /run/current-system/sw/bin/nixos-container run ${ctr.name} -- ${pkgs.writeDash "deploy-${ctr.name}" '' set -x mkdir -p /var/state/var_src ln -sfTr /var/state/var_src /var/src touch /etc/NIXOS ''} if [ -h /var/lib/containers/${ctr.name}/var/src/nixos-config ] && (! ping -c1 -q -w5 ${ctr.name}.r); then /run/current-system/sw/bin/nixos-container run ${ctr.name} -- nixos-rebuild -I /var/src switch else echo 'no nixos config, or target already online, bailing out' ${(stop ctr.name).${ctr.format}} /run/current-system/sw/bin/nixos-container stop ${ctr.name} fi '') (pkgs.writeDashBin "stop-${ctr.name}" '' set -euf /run/current-system/sw/bin/nixos-container stop ${ctr.name} ${(stop ctr.name).${ctr.format}} '') ]) cfg.containers); }; }