common/fs: reduce the servo ftp mounts to just one ftp mount, plus a collection of bind mounts
simpler, more reliable, and less resource intensive!
This commit is contained in:
@@ -2,36 +2,58 @@
|
|||||||
let
|
let
|
||||||
fsOpts = import ./fs-opts.nix;
|
fsOpts = import ./fs-opts.nix;
|
||||||
commonOptions = fsOpts.ftp ++ fsOpts.noauto;
|
commonOptions = fsOpts.ftp ++ fsOpts.noauto;
|
||||||
|
mountpoint = "/mnt/.servo_ftp";
|
||||||
|
systemdName = utils.escapeSystemdPath mountpoint;
|
||||||
|
device = "curlftpfs#ftp://servo-hn:/";
|
||||||
|
fsType = "fuse3";
|
||||||
|
options = commonOptions ++ [
|
||||||
|
# systemd (or maybe fuse?) swallows stderr of mount units with no obvious fix.
|
||||||
|
# instead, use this flag to log the mount output to disk
|
||||||
|
"stderr_path=/var/log/curlftpfs/servo-hn.stderr"
|
||||||
|
];
|
||||||
|
|
||||||
remoteServo = subdir: let
|
remoteServo = subdir: let
|
||||||
mountpoint = "/mnt/servo/${subdir}";
|
systemdBindName = utils.escapeSystemdPath "/mnt/servo/${subdir}";
|
||||||
systemdName = utils.escapeSystemdPath mountpoint;
|
|
||||||
device = "curlftpfs#ftp://servo-hn:/${subdir}";
|
|
||||||
fsType = "fuse3";
|
|
||||||
options = commonOptions ++ [
|
|
||||||
# systemd (or maybe fuse?) swallows stderr of mount units with no obvious fix.
|
|
||||||
# instead, use this flag to log the mount output to disk
|
|
||||||
"stderr_path=/var/log/curlftpfs/${builtins.replaceStrings [ "/" ] [ "-" ] subdir}.stderr"
|
|
||||||
];
|
|
||||||
in {
|
in {
|
||||||
fileSystems."${mountpoint}" = {
|
# sane.fs."/mnt/servo/${subdir}".mount.bind = "/mnt/.servo_ftp/${subdir}";
|
||||||
|
systemd.mounts = [{
|
||||||
|
where = "/mnt/servo/${subdir}";
|
||||||
|
what = "/mnt/.servo_ftp/${subdir}";
|
||||||
|
options = "bind,nofail";
|
||||||
|
type = "auto";
|
||||||
|
|
||||||
|
after = [ "${systemdName}.mount" ];
|
||||||
|
upheldBy = [ "${systemdName}.mount" ]; #< start this mount whenever the underlying becomes available
|
||||||
|
bindsTo = [ "${systemdName}.mount" ]; #< stop this mount whenever the underlying disappears
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
sane.programs.curlftpfs.enableFor.system = true;
|
||||||
|
system.fsPackages = [
|
||||||
|
config.sane.programs.curlftpfs.package
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.fs."/var/log/curlftpfs".dir.acl.mode = "0777";
|
||||||
|
|
||||||
|
fileSystems."/mnt/.servo_ftp" = {
|
||||||
inherit device fsType options;
|
inherit device fsType options;
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
};
|
};
|
||||||
systemd.services.servo-ftp-reachable.unitConfig.BindsTo = [ "${systemdName}.mount" ];
|
|
||||||
systemd.mounts = [{
|
systemd.mounts = [{
|
||||||
where = mountpoint;
|
where = mountpoint;
|
||||||
what = device;
|
what = device;
|
||||||
type = fsType;
|
type = fsType;
|
||||||
options = lib.concatStringsSep "," options;
|
options = lib.concatStringsSep "," options;
|
||||||
wantedBy = [ "servo-ftp-reachable.service" ];
|
wantedBy = [ "default.target" ];
|
||||||
after = [ "servo-ftp-reachable.service" ];
|
after = [ "network-online.target" ];
|
||||||
requires = [ "servo-ftp-reachable.service" ];
|
requires = [ "network-online.target" ];
|
||||||
bindsTo = [ "servo-ftp-reachable.service" ];
|
|
||||||
|
|
||||||
#VVV patch so that when the mount fails, we start a timer to remount it.
|
#VVV patch so that when the mount fails, we start a timer to remount it.
|
||||||
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
||||||
# unitConfig.OnFailure = [ "${systemdName}.timer" ];
|
unitConfig.OnFailure = [ "${systemdName}.timer" ];
|
||||||
# unitConfig.OnSuccess = [ "${systemdName}-restart-timer.target" ];
|
unitConfig.OnSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||||
|
|
||||||
mountConfig.TimeoutSec = "10s";
|
mountConfig.TimeoutSec = "10s";
|
||||||
mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
@@ -68,106 +90,37 @@ let
|
|||||||
# mountConfig.RestrictNamespaces = true;
|
# mountConfig.RestrictNamespaces = true;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
};
|
systemd.targets."${systemdName}-restart-timer" = {
|
||||||
in
|
# hack unit which, when started, stops the timer (if running), and then starts it again.
|
||||||
lib.mkMerge [
|
after = [ "${systemdName}.timer" ];
|
||||||
{
|
conflicts = [ "${systemdName}.timer" ];
|
||||||
sane.programs.curlftpfs.enableFor.system = true;
|
upholds = [ "${systemdName}.timer" ];
|
||||||
system.fsPackages = [
|
unitConfig.StopWhenUnneeded = true;
|
||||||
config.sane.programs.curlftpfs.package
|
};
|
||||||
];
|
systemd.timers."${systemdName}" = {
|
||||||
|
timerConfig.Unit = "${systemdName}.mount";
|
||||||
sane.fs."/var/log/curlftpfs".dir.acl.mode = "0777";
|
timerConfig.AccuracySec = "2s";
|
||||||
|
timerConfig.OnActiveSec = [
|
||||||
systemd.services.servo-ftp-reachable = {
|
# try to remount at these timestamps, backing off gradually
|
||||||
wantedBy = [ "default.target" ];
|
# there seems to be an implicit mount attempt at t=0.
|
||||||
after = [ "network-online.target" ];
|
"10s"
|
||||||
serviceConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
"30s"
|
||||||
serviceConfig.ExecStart = lib.escapeShellArgs [
|
"60s"
|
||||||
"curlftpfs"
|
"120s"
|
||||||
"ftp://servo-hn:/"
|
];
|
||||||
"/dev/null"
|
# cap the backoff to a fixed interval.
|
||||||
"-o"
|
timerConfig.OnUnitActiveSec = [ "120s" ];
|
||||||
(lib.concatStringsSep "," ([
|
|
||||||
"exit_after_connect"
|
|
||||||
] ++ commonOptions))
|
|
||||||
];
|
|
||||||
serviceConfig.RemainAfterExit = true;
|
|
||||||
serviceConfig.Type = "oneshot";
|
|
||||||
|
|
||||||
serviceConfig.RestartOn = "always";
|
|
||||||
serviceConfig.RestartSec = "10s";
|
|
||||||
serviceConfig.RestartMaxDelaySec = "120s";
|
|
||||||
serviceConfig.RestartSteps = 3;
|
|
||||||
|
|
||||||
# hardening (systemd-analyze security mnt-servo-playground-reachable.service)
|
|
||||||
serviceConfig.AmbientCapabilities = "";
|
|
||||||
serviceConfig.CapabilityBoundingSet = "";
|
|
||||||
serviceConfig.DynamicUser = true;
|
|
||||||
serviceConfig.LockPersonality = true;
|
|
||||||
serviceConfig.MemoryDenyWriteExecute = true;
|
|
||||||
serviceConfig.NoNewPrivileges = true;
|
|
||||||
serviceConfig.PrivateDevices = true;
|
|
||||||
serviceConfig.PrivateMounts = true;
|
|
||||||
serviceConfig.PrivateTmp = true;
|
|
||||||
serviceConfig.PrivateUsers = true;
|
|
||||||
serviceConfig.ProcSubset = "all";
|
|
||||||
serviceConfig.ProtectClock = true;
|
|
||||||
serviceConfig.ProtectControlGroups = true;
|
|
||||||
serviceConfig.ProtectHome = true;
|
|
||||||
serviceConfig.ProtectKernelModules = true;
|
|
||||||
serviceConfig.ProtectProc = "invisible";
|
|
||||||
serviceConfig.ProtectSystem = "strict";
|
|
||||||
serviceConfig.RemoveIPC = true;
|
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
|
||||||
# serviceConfig.RestrictFileSystems = "@common-block @basic-api"; #< NOPE
|
|
||||||
serviceConfig.RestrictRealtime = true;
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
|
||||||
serviceConfig.SystemCallFilter = [
|
|
||||||
"@system-service"
|
|
||||||
"@mount"
|
|
||||||
"~@chown"
|
|
||||||
"~@cpu-emulation"
|
|
||||||
"~@keyring"
|
|
||||||
# "~@privileged" #< NOPE
|
|
||||||
"~@resources"
|
|
||||||
# could remove some more probably
|
|
||||||
];
|
|
||||||
serviceConfig.IPAddressDeny = "any";
|
|
||||||
serviceConfig.IPAddressAllow = "10.0.10.5";
|
|
||||||
serviceConfig.DevicePolicy = "closed";
|
|
||||||
# exceptions
|
|
||||||
serviceConfig.ProtectHostname = false;
|
|
||||||
serviceConfig.ProtectKernelLogs = false;
|
|
||||||
serviceConfig.ProtectKernelTunables = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# systemd.targets."${systemdName}-restart-timer" = {
|
|
||||||
# # hack unit which, when started, stops the timer (if running), and then starts it again.
|
|
||||||
# after = [ "${systemdName}.timer" ];
|
|
||||||
# conflicts = [ "${systemdName}.timer" ];
|
|
||||||
# upholds = [ "${systemdName}.timer" ];
|
|
||||||
# unitConfig.StopWhenUnneeded = true;
|
|
||||||
# };
|
|
||||||
# systemd.timers."${systemdName}" = {
|
|
||||||
# timerConfig.Unit = "${systemdName}.mount";
|
|
||||||
# timerConfig.AccuracySec = "2s";
|
|
||||||
# timerConfig.OnActiveSec = [
|
|
||||||
# # try to remount at these timestamps, backing off gradually
|
|
||||||
# # there seems to be an implicit mount attempt at t=0.
|
|
||||||
# "10s"
|
|
||||||
# "30s"
|
|
||||||
# "60s"
|
|
||||||
# "120s"
|
|
||||||
# ];
|
|
||||||
# # cap the backoff to a fixed interval.
|
|
||||||
# timerConfig.OnUnitActiveSec = [ "120s" ];
|
|
||||||
# };
|
|
||||||
}
|
}
|
||||||
# this granularity of servo media mounts is necessary to support sandboxing:
|
|
||||||
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
# this granularity of servo media mounts is necessary to support sandboxing. consider:
|
||||||
# so it's either this or unconditionally bind all of media/.
|
# 1. servo offline
|
||||||
|
# 2. launch a long-running app
|
||||||
|
# 3. servo comes online
|
||||||
|
# in order for the servo mount to be propagated into the app's namespace, we need to bind
|
||||||
|
# the root mountpoint into the app namespace. if we wish to only grant the app selective access
|
||||||
|
# to servo, we must create *multiple* mountpoints: /mnt/servo/FOO directories which always exist,
|
||||||
|
# and are individually bound to /mnt/.servo_ftp/FOO as the latter becomes available.
|
||||||
(remoteServo "media/archive")
|
(remoteServo "media/archive")
|
||||||
(remoteServo "media/Books")
|
(remoteServo "media/Books")
|
||||||
(remoteServo "media/collections")
|
(remoteServo "media/collections")
|
||||||
|
Reference in New Issue
Block a user