diff --git a/cluster/services/storage/default.nix b/cluster/services/storage/default.nix new file mode 100644 index 0000000..923f75c --- /dev/null +++ b/cluster/services/storage/default.nix @@ -0,0 +1,8 @@ +{ + services.storage = { + nodes.heresy = [ "VEGAS" ]; + nixos.heresy = [ + ./heresy.nix + ]; + }; +} diff --git a/cluster/services/storage/heresy.nix b/cluster/services/storage/heresy.nix new file mode 100644 index 0000000..fbd73cc --- /dev/null +++ b/cluster/services/storage/heresy.nix @@ -0,0 +1,101 @@ +{ config, lib, pkgs, ... }: + +let + s3qlWithSystemd = pkgs.s3ql.overrideAttrs (old: { + propagatedBuildInputs = old.propagatedBuildInputs ++ [ + pkgs.python3Packages.systemd + ]; + }); + + dirs = { + cache = "/srv/storage/private/s3ql-cache"; + underlay = "/mnt/heresy"; + mount = "/srv/heresy"; + }; +in + +{ + age.secrets = { + storageBoxCredentials.file = ./secrets/storage-box-credentials.age; + heresyEncryptionKey.file = ./secrets/heresy-encryption-key.age; + }; + + boot.supportedFilesystems = [ "cifs" ]; + + fileSystems."${dirs.underlay}" = { + fsType = "cifs"; + device = "//u357754.your-storagebox.de/u357754-sub1/fs/heresy"; + options = [ + "credentials=${config.age.secrets.storageBoxCredentials.path}" + "dir_mode=0700" + "file_mode=0600" + "_netdev" + "x-systemd.automount" + ]; + }; + + systemd = { + tmpfiles.rules = [ + "d '${dirs.cache}' 0700 root root - -" + ]; + services.heresy = { + description = "Heresy Filesystem"; + wantedBy = [ "multi-user.target" ]; + requires = [ "mnt-heresy.mount" ]; + wants = [ "remote-fs.target" ]; + after = [ "mnt-heresy.mount" ]; + before = [ "remote-fs.target" ]; + + # used by umount.s3ql + path = with pkgs; [ + psmisc + util-linux + ]; + + serviceConfig = let + commonOptions = [ + "--compress" "none" + "--cachedir" dirs.cache + "--authfile" config.age.secrets.heresyEncryptionKey.path + ]; + in { + Type = "notify"; + + ExecStartPre = map lib.escapeShellArgs [ + [ + "${pkgs.coreutils}/bin/install" "-dm755" dirs.mount + ] + ([ + "${s3qlWithSystemd}/bin/fsck.s3ql" + "local://${dirs.underlay}" + ] ++ commonOptions) + ]; + ExecStart = lib.escapeShellArgs ([ + "${s3qlWithSystemd}/bin/mount.s3ql" + "local://${dirs.underlay}" + dirs.mount + "--fs-name" "heresy" + "--allow-other" + "--systemd" "--fg" + "--log" "none" + ] ++ commonOptions); + + ExecStop = lib.escapeShellArgs [ + "${s3qlWithSystemd}/bin/umount.s3ql" + "--log" "none" + dirs.mount + ]; + + # fsck and unmounting might take a while + TimeoutStartSec = "600s"; + TimeoutStopSec = "600s"; + + # s3ql only handles SIGINT + KillSignal = "SIGINT"; + + Restart = "on-failure"; + RestartSec = "10s"; + }; + }; + }; +} diff --git a/cluster/services/storage/secrets/heresy-encryption-key.age b/cluster/services/storage/secrets/heresy-encryption-key.age new file mode 100644 index 0000000..d12d5dd Binary files /dev/null and b/cluster/services/storage/secrets/heresy-encryption-key.age differ diff --git a/cluster/services/storage/secrets/storage-box-credentials.age b/cluster/services/storage/secrets/storage-box-credentials.age new file mode 100644 index 0000000..487217d --- /dev/null +++ b/cluster/services/storage/secrets/storage-box-credentials.age @@ -0,0 +1,11 @@ +age-encryption.org/v1 +-> ssh-ed25519 NO562A tJRraicHm1ZsU4yrvK3R1xAiIX+0w1WL+maBEcfbZk0 +1IvOLKJVvt3lj44lIyDdHbnGzBiQQhfYh92HZYPz36Q +-> ssh-ed25519 5/zT0w a/LO69ZwMzoNUrr8fLR1lKDuYve6KXUZaQKN6ctwSjs +E1OKbXuvynYwf0D9/APjFm3z+l8Y/l8TRkj+CeB04kI +-> ssh-ed25519 d3WGuA fUdpFXP5JDQwpk81dMR9agx8XgeJTP0sTESDadr9Zxk +gPr4DnmX1CqpEnLvObCPuyiTIBJOT0cvoQize7Oe7U4 +-> &-grease r 8mj:pc~r +DdZaL+KpxVOKEAQ0MZnpftL1hbOUffIaCsu4zMcafW+cnNzD1R0 +--- jV/6H0YdytV3ik3wwoSurOWdugvJus1gbSCtJDJFJMw +Ž¾|à><^~n"iyD|¤I‰šD:Z”XݧVÃvOðàÄ£r‹z•¿j…Sþà‰·©x7c¹ÕÔ»½š «Ni©·È`”¿¿ð‚ \ No newline at end of file diff --git a/secrets.nix b/secrets.nix index d29e9c6..f93dd0d 100644 --- a/secrets.nix +++ b/secrets.nix @@ -36,6 +36,8 @@ in with hosts; "cluster/services/patroni/passwords/replication.age".publicKeys = max ++ map systemKeys [ thunderskin VEGAS prophet ]; "cluster/services/patroni/passwords/rewind.age".publicKeys = max ++ map systemKeys [ thunderskin VEGAS prophet ]; "cluster/services/patroni/passwords/superuser.age".publicKeys = max ++ map systemKeys [ thunderskin VEGAS prophet ]; + "cluster/services/storage/secrets/heresy-encryption-key.age".publicKeys = max ++ map systemKeys [ VEGAS ]; + "cluster/services/storage/secrets/storage-box-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS ]; "cluster/services/wireguard/mesh-keys/checkmate.age".publicKeys = max ++ map systemKeys [ checkmate ]; "cluster/services/wireguard/mesh-keys/thunderskin.age".publicKeys = max ++ map systemKeys [ thunderskin ]; "cluster/services/wireguard/mesh-keys/VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];