temmie/userweb: run passwd sync in different unit

This commit is contained in:
h7x4
2026-06-17 11:23:36 +09:00
parent b910cf9563
commit 75f87ffab8
4 changed files with 160 additions and 66 deletions
@@ -5,5 +5,6 @@
./mail.nix ./mail.nix
./module.nix ./module.nix
./packages.nix ./packages.nix
./passwd-sync.nix
]; ];
} }
@@ -3,11 +3,6 @@ let
mcfg = config.services.pvv-userweb; mcfg = config.services.pvv-userweb;
in in
{ {
sops.secrets = {
"httpd/passwd-ssh-key" = { };
"httpd/ssh-known-hosts" = { };
};
systemd.targets.sockets.wants = [ systemd.targets.sockets.wants = [
"httpd-log-processor@access.socket" "httpd-log-processor@access.socket"
"httpd-log-processor@error.socket" "httpd-log-processor@error.socket"
@@ -27,6 +22,9 @@ in
systemd.services."httpd-log-processor@" = lib.mkIf config.services.httpd.enable { systemd.services."httpd-log-processor@" = lib.mkIf config.services.httpd.enable {
requiredBy = [ "userweb.target" ]; requiredBy = [ "userweb.target" ];
after = [ "httpd-passwd-sync.service" ];
requires = [ "httpd-passwd-sync.service" ];
serviceConfig = { serviceConfig = {
User = "wwwrun"; User = "wwwrun";
Group = "wwwrun"; Group = "wwwrun";
@@ -37,55 +35,16 @@ in
StandardOutput = "journal"; StandardOutput = "journal";
StandardError = "journal"; StandardError = "journal";
LoadCredential = [
"sshkey:${config.sops.secrets."httpd/passwd-ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."httpd/ssh-known-hosts".path}"
];
ExecStartPre = let
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
archive = true;
verbose = true;
compress = true;
rsh = "${lib.getExe' pkgs.openssh "ssh"} -o BatchMode=yes -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
inputDir = "/run/httpd-log-processor-%i/pamunix-in";
outputDir = "/run/httpd-log-processor-%i/pamunix-out";
in lib.mkForce [
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/passwd ${inputDir}/"
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/group ${inputDir}/"
(let
args = lib.cli.toCommandLineShellGNU { } {
passwd-file = "${inputDir}/passwd";
group-file = "${inputDir}/group";
output-dir = outputDir;
shadow-file = pkgs.emptyFile;
output-passwd = true;
ignore-user-file = toString ./ignore_user_file.txt;
ignore-group-file = toString ./ignore_group_file.txt;
};
in ''${lib.getExe pkgs.passwd2systemd-users} ${args}'')
"${lib.getExe' pkgs.coreutils "shred"} -u ${inputDir}/passwd ${inputDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash' ${outputDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:54:Apache httpd user:/var/empty:/run/current-system/sw/bin/bash' ${outputDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:' ${outputDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:' ${outputDir}/group"
"+${lib.getExe' pkgs.coreutils "chown"} root:root ${outputDir}/passwd ${outputDir}/group"
"+${lib.getExe' pkgs.coreutils "chmod"} 0644 ${outputDir}/passwd ${outputDir}/group"
"+${lib.getExe pkgs.mount} --bind ${outputDir}/passwd /etc/passwd"
"+${lib.getExe pkgs.mount} --bind ${outputDir}/group /etc/group"
];
ExecStart = "${lib.getExe mcfg.apacheLogProcessorPackage} %i"; ExecStart = "${lib.getExe mcfg.apacheLogProcessorPackage} %i";
AmbientCapabilities = [ "CAP_SETUID" "CAP_SETGID" ]; AmbientCapabilities = [ "CAP_SETUID" "CAP_SETGID" ];
CapabilityBoundingSet = [ "CAP_SETUID" "CAP_SETGID" ]; CapabilityBoundingSet = [ "CAP_SETUID" "CAP_SETGID" ];
DeviceAllow = [ "" ]; DeviceAllow = [ "" ];
IPAddressDeny = "any";
LockPersonality = true; LockPersonality = true;
MemoryDenyWriteExecute = true; MemoryDenyWriteExecute = true;
PrivateDevices = true; PrivateDevices = true;
PrivateNetwork = true;
PrivateIPC = true; PrivateIPC = true;
PrivateTmp = true; PrivateTmp = true;
# PrivateUsers = true; # PrivateUsers = true;
@@ -100,10 +59,7 @@ in
ProtectSystem = "strict"; ProtectSystem = "strict";
ProtectKernelTunables = true; ProtectKernelTunables = true;
RemoveIPC = true; RemoveIPC = true;
RestrictAddressFamilies = [ RestrictAddressFamilies = [ "" ];
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true; RestrictNamespaces = true;
RestrictRealtime = true; RestrictRealtime = true;
RestrictSUIDSGID = true; RestrictSUIDSGID = true;
@@ -115,29 +71,17 @@ in
]; ];
UMask = "0077"; UMask = "0077";
IPAddressAllow = [
"127.0.0.53" # systemd-resolved
values.hosts.microbel.ipv4
values.hosts.microbel.ipv6
];
IPAddressDeny = "any";
RootDirectory = "/run/httpd-log-processor-%i/root-mnt"; RootDirectory = "/run/httpd-log-processor-%i/root-mnt";
MountAPIVFS = true; MountAPIVFS = true;
RuntimeDirectoryMode = "0750"; RuntimeDirectoryMode = "0750";
RuntimeDirectory = [ RuntimeDirectory = [ "httpd-log-processor-%i/root-mnt" ];
"httpd-log-processor-%i/root-mnt"
"httpd-log-processor-%i/pamunix-in"
"httpd-log-processor-%i/pamunix-out"
];
BindReadOnlyPaths = [ BindReadOnlyPaths = [
builtins.storeDir builtins.storeDir
"/etc" "/etc"
"/etc/resolv.conf"
"-/run/httpd-log-processor-%i/pamunix-out/passwd:/etc/passwd" "/var/lib/httpd-passwd-sync/passwd:/etc/passwd"
"-/run/httpd-log-processor-%i/pamunix-out/group:/etc/group" "/var/lib/httpd-passwd-sync/group:/etc/group"
"${pkgs.writeText "userweb-fake-nsswitch.conf" '' "${pkgs.writeText "userweb-fake-nsswitch.conf" ''
passwd: files passwd: files
+3 -1
View File
@@ -4,7 +4,9 @@ let
in in
{ {
options.services.pvv-userweb = { options.services.pvv-userweb = {
enable = lib.mkEnableOption ""; enable = lib.mkEnableOption "" // {
default = true;
};
debugMode = lib.mkEnableOption ""; debugMode = lib.mkEnableOption "";
@@ -0,0 +1,147 @@
{ config, lib, pkgs, values, ... }:
let
mcfg = config.services.pvv-userweb;
in
{
config = lib.mkIf mcfg.enable {
sops.secrets = {
"httpd/passwd-ssh-key" = { };
"httpd/ssh-known-hosts" = { };
};
# NOTE: because we are running as `DynamicUser` and we want the result files to be available to
# other services, this directory needs to be created via systemd-tmpfiles
systemd.tmpfiles.settings."10-httpd-passwd-sync"."/var/lib/httpd-passwd-sync".d = {
user = "root";
group = "root";
mode = "0700";
};
systemd.timers.httpd-passwd-sync = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
Unit = "httpd-passwd-sync.service";
};
};
systemd.services."httpd-passwd-sync" = {
requiredBy = [ "userweb.target" ];
after = [
"systemd-tmpfiles-setup.service"
"systemd-tmpfiles-resetup.service"
];
serviceConfig = {
Type = "oneshot";
Slice = "system-userweb.slice";
Restart = "on-failure";
RestartSec = "3s";
DynamicUser = true;
LoadCredential = [
"sshkey:${config.sops.secrets."httpd/passwd-ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."httpd/ssh-known-hosts".path}"
];
ExecStart = let
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
verbose = true;
compress = true;
rsh = "${lib.getExe' pkgs.openssh "ssh"} -o BatchMode=yes -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
inputDir = "/run/httpd-passwd-sync/in";
wipDir = "/run/httpd-passwd-sync/wip";
outputDir = "/var/lib/httpd-passwd-sync";
in [
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/passwd ${inputDir}/"
"${lib.getExe pkgs.rsync} ${rsyncArgs} pvv@smtp.pvv.ntnu.no:/etc/group ${inputDir}/"
(let
args = lib.cli.toCommandLineShellGNU { } {
passwd-file = "${inputDir}/passwd";
group-file = "${inputDir}/group";
output-dir = wipDir;
shadow-file = pkgs.emptyFile;
output-passwd = true;
ignore-user-file = toString ./ignore_user_file.txt;
ignore-group-file = toString ./ignore_group_file.txt;
};
in ''${lib.getExe pkgs.passwd2systemd-users} ${args}'')
"${lib.getExe' pkgs.coreutils "shred"} -u ${inputDir}/passwd ${inputDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash' ${wipDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:54:Apache httpd user:/var/empty:/run/current-system/sw/bin/bash' ${wipDir}/passwd"
":${lib.getExe pkgs.gnused} -i '$ a\\\\root:x:0:' ${wipDir}/group"
":${lib.getExe pkgs.gnused} -i '$ a\\\\wwwrun:x:54:' ${wipDir}/group"
"+${lib.getExe' pkgs.coreutils "install"} -m644 -o root -g root -t '${outputDir}' ${wipDir}/passwd ${wipDir}/group"
"${lib.getExe' pkgs.coreutils "shred"} -u ${wipDir}/passwd ${wipDir}/group"
];
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
ProtectKernelTunables = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
];
UMask = "0077";
IPAddressAllow = [
values.hosts.microbel.ipv4
values.hosts.microbel.ipv6
];
IPAddressDeny = "any";
RootDirectory = "/run/httpd-passwd-sync/root-mnt";
MountAPIVFS = true;
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [
"httpd-passwd-sync/root-mnt"
"httpd-passwd-sync/in"
"httpd-passwd-sync/wip"
];
BindPaths = [
"/var/lib/httpd-passwd-sync"
];
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/var/run/nscd"
];
};
};
};
}