Skip to content

Commit

Permalink
Hardened custom systemd services using sandboxing options
Browse files Browse the repository at this point in the history
  • Loading branch information
aftix committed May 20, 2024
1 parent 70d9fc5 commit c7144e6
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 58 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@ jobs:
run: ssh-keyscan -H 170.130.165.174 > ~/.ssh/known_hosts

- name: Deploy fermi
run: >
run: |
nix run 'github:serokell/deploy-rs' '.#fermi' -- --ssh-user aftix -- --impure
ssh [email protected] 'sh -ls' <<< "$SCRIPT"
env:
SCRIPT: >-
cd $HOME/cfg ;
git pull --rebase
64 changes: 36 additions & 28 deletions host/common/barcodebuddy.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
inputs,
...
}: let
inherit (lib) mkDefault mkIf;
inherit (lib) mkDefault mkIf mkForce;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.attrsets) filterAttrs;
cfg = config.services.barcodebuddy;
in {
options.services.barcodebuddy = {
Expand Down Expand Up @@ -35,6 +36,7 @@ in {
"php_admin_flag[log_errors]" = true;
"listen.owner" = cfg.user;
"listen.group" = cfg.group;
"listen.mode" = "0600";
"catch_workers_output" = true;
"pm.max_children" = "10";
"pm.start_servers" = "2";
Expand Down Expand Up @@ -120,34 +122,40 @@ in {
"d '${cfg.dataDir}' - '${cfg.user}' '${cfg.group}' - -"
];

services.barcodebuddy-wss = mkIf cfg.enableWebsockets {
wants = ["network.target"];
after = ["network.target"];
wantedBy = ["multi-user.target"];
unitConfig.Description = "Barcodebuddy for grocy - websocket server";

serviceConfig = {
User = cfg.user;
Group = cfg.group;
WorkingDirectory = pkgs.barcodebuddy;
ProtectSystem = "strict";
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = "read-only";
NoNewPrivileges = true;
ReadWritePaths = cfg.dataDir;
MemoryDenyWriteExecute = true;
services = {
phpfpm-barcodebuddy.serviceConfig = filterAttrs (n: v: !builtins.elem n ["IPAddressAllow" "IPAddressDeny"]) (config.my.hardenPHPFPM {
workdir = pkgs.barcodebuddy;
datadir = cfg.dataDir;
});

barcodebuddy-wss = mkIf cfg.enableWebsockets {
wants = ["network.target"];
after = ["network.target"];
wantedBy = ["multi-user.target"];
unitConfig.Description = "Barcodebuddy for grocy - websocket server";

serviceConfig =
(filterAttrs (n: v: !builtins.elem n ["IPAddressAllow" "IPAddressDeny"]) config.my.systemdHardening)
// {
User = cfg.user;
Group = cfg.group;
WorkingDirectory = pkgs.barcodebuddy;

PrivateTmp = true;
ReadWritePaths = cfg.dataDir;
MemoryDenyWriteExecute = false;
};

script = let
inherit (lib.strings) escapeShellArg;
in ''
export BBUDDY_CONFIG_PATH=${escapeShellArg cfg.dataDir}/config.php
export BBUDDY_LEGACY_DATABASE_PATH=${escapeShellArg cfg.dataDir}/barcodebuddy_legacy.db
export BBUDDY_DATABASE_PATH=${escapeShellArg cfg.dataDir}/barcodebuddy.db
export BBUDDY_AUTHDB_PATH=${escapeShellArg cfg.dataDir}/auth.db
${config.services.phpfpm.pools.barcodebuddy.phpPackage}/bin/php wsserver.php
'';
};

script = let
inherit (lib.strings) escapeShellArg;
in ''
export BBUDDY_CONFIG_PATH=${escapeShellArg cfg.dataDir}/config.php
export BBUDDY_LEGACY_DATABASE_PATH=${escapeShellArg cfg.dataDir}/barcodebuddy_legacy.db
export BBUDDY_DATABASE_PATH=${escapeShellArg cfg.dataDir}/barcodebuddy.db
export BBUDDY_AUTHDB_PATH=${escapeShellArg cfg.dataDir}/auth.db
${config.services.phpfpm.pools.barcodebuddy.phpPackage}/bin/php wsserver.php
'';
};
};

Expand Down
24 changes: 19 additions & 5 deletions host/common/coffeepaste.nix
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,27 @@ in {
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.dataDir;
ProtectSystem = "strict";
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = "read-only";
NoNewPrivileges = true;
ReadWritePaths = cfg.dataDir;

CapabilityBoundingSet = config.my.systemdCapabilities;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
UMask = "0027";
};
script = "${pkgs.coffeepaste}/bin/coffeepaste";
preStart = "cp -f ${pkgs.coffeepaste}/share/config.toml ${cfg.dataDir}/config.toml";
Expand Down
88 changes: 88 additions & 0 deletions host/common/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
lib,
...
}: let
inherit (lib) mkDefault mkForce;
inherit (lib.options) mkOption mkEnableOption;
in {
imports = [
Expand All @@ -25,6 +26,93 @@ in {
users.aftix.enable = mkEnableOption "aftix";

uefi = mkEnableOption "uefi";

systemdCapabilities = mkOption {
readOnly = false;
default = builtins.map (s: "~CAP_" + s) [
"SYS_TIME"
"SYS_PACCT"
"KILL"
"WAKE_ALARM"
"FOWNER"
"IPC_OWNER"
"BPF"
"LINUX_IMMUTABLE"
"IPC_LOCK"
"SYS_MODULE"
"SYS_TTY_CONFIG"
"SYS_BOOT"
"SYS_CHROOT"
"BLOCK_SUSPEND"
"LEASE"
"FSETID"
"SETFCAP"
"SETPCAP"
"SYS_PTRACE"
"SYS_NICE"
"SYS_RESOURCE"
"NET_ADMIN"
"CHOWN"
"SETUID"
"SETGID"
];
};

systemdHardening = mkOption {
readOnly = true;
default = {
CapabilityBoundingSet =
mkDefault config.my.systemdCapabilities;
IPAddressAllow = mkDefault "localhost";
IPAddressDeny = mkDefault "any";
LockPersonality = mkDefault true;
MemoryDenyWriteExecute = mkDefault true;
NoNewPrivileges = mkDefault true;
PrivateDevices = mkDefault true;
PrivateTmp = mkDefault true;
PrivateUsers = mkDefault true;
ProtectHome = mkDefault "read-only";
ProtectHostname = mkDefault true;
ProtectKernelModules = mkDefault true;
ProtectKernelTunables = mkDefault true;
ProtectProc = mkDefault "invisible";
ProtectSystem = mkDefault "strict";
RemoveIPC = mkDefault true;
RestrictNamespaces = mkDefault "";
RestrictRealtime = mkDefault true;
RestrictSUIDSGID = mkDefault true;
SystemCallArchitectures = mkDefault "native";
UMask = mkDefault "0027";
};
};

hardenPHPFPM = mkOption {
readOnly = true;
default = {
workdir,
datadir,
}: {
WorkingDirectory = workdir;
MemoryDenyWriteExecute = false;
ReadWritePaths = [datadir "/run/phpfpm"];

IPAddressAllow = mkDefault "localhost";
IPAddressDeny = mkDefault "any";
LockPersonality = mkDefault true;
NoNewPrivileges = mkDefault true;
ProcSubset = mkDefault "pid";
ProtectHostname = mkDefault true;
ProtectKernelModules = mkDefault true;
ProtectKernelTunables = mkDefault true;
ProtectProc = mkDefault "invisible";
RemoveIPC = mkDefault true;
RestrictNamespaces = mkDefault true;
RestrictRealtime = mkDefault true;
RestrictSUIDSGID = mkDefault true;
SystemCallArchitectures = mkDefault "native";
UMask = mkForce "0027";
};
};
};

config = {
Expand Down
32 changes: 25 additions & 7 deletions host/opt/www/grocy.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
pkgs,
...
}: let
inherit (lib) mkDefault mkIf;
inherit (lib) mkDefault mkIf mkForce;
inherit (lib.options) mkOption mkEnableOption;
wwwCfg = config.my.www;
cfg = wwwCfg.grocy;
Expand Down Expand Up @@ -33,6 +33,7 @@ in {
"php_admin_flag[log_errors]" = true;
"listen.owner" = cfg.user;
"listen.group" = cfg.group;
"listen.mode" = "0600";
"catch_workers_output" = true;
"pm.max_children" = "32";
"pm.start_servers" = "2";
Expand Down Expand Up @@ -134,12 +135,29 @@ in {
"storage"
]);

services.grocy-setup = {
wantedBy = ["multi-user.target"];
before = ["phpfpm-grocy.service"];
script = ''
rm -rf ${lib.strings.escapeShellArg cfg.dataDir}/viewcache/*
'';
services = {
grocy-setup = {
wantedBy = ["multi-user.target"];
before = ["phpfpm-grocy.service"];
serviceConfig =
config.my.systemdHardening
// {
User = mkForce cfg.user;
Group = mkForce cfg.group;
WorkingDirectory = cfg.dataDir;
ReadWritePaths = cfg.dataDir + "/viewcache";

PrivateNetwork = true;
};
script = ''
rm -rf ${lib.strings.escapeShellArg cfg.dataDir}/viewcache/*
'';
};

phpfpm-grocy.serviceConfig = config.my.hardenPHPFPM {
workdir = config.services.grocy.package;
datadir = cfg.dataDir;
};
};
};

Expand Down
17 changes: 14 additions & 3 deletions host/opt/www/rss.nix
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,20 @@ in {
"www.${cfg.rssSubdomain}.${cfg.hostname}"
];

systemd.services.freshrss-config.serviceConfig = {
User = mkForce cfg.user;
Group = mkForce cfg.group;
systemd.services = {
freshrss-config.serviceConfig = {
User = mkForce cfg.user;
Group = mkForce cfg.group;
WorkingDirectory = config.services.freshrss.package;

PrivateNetwork = true;
UMask = mkForce "0027";
};

phpfpm-freshrss.serviceConfig = config.my.hardenPHPFPM {
workdir = config.services.freshrss.package;
datadir = config.services.freshrss.dataDir;
};
};

services = {
Expand Down
28 changes: 14 additions & 14 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ arch := `uname -m`
default:
@just --list

build host=hostname:
@nix build ".#nixosConfigurations.{{host}}.config.system.build.toplevel"
build host=hostname *FLAGS="":
@nix build ".#nixosConfigurations.{{host}}.config.system.build.toplevel" {{FLAGS}}

switch:
@nh os switch
switch *FLAGS:
@nh os switch {{FLAGS}}

boot:
@nh os boot
boot *FLAGS:
@nh os boot {{FLAGS}}

test:
@nh os test
test *FLAGS:
@nh os test {{FLAGS}}

check:
@nix flake check
check *FLAGS:
@nix flake check {{FLAGS}}

deploy node="fermi":
@nix run 'github:serokell/deploy-rs' '.#{{node}}' -- -- --impure
Expand All @@ -28,9 +28,9 @@ rekey:
@sops updatekeys -y host/srv_secrets.yaml
@sops updatekeys -y home/secrets.yaml

iso variant="minimal" arch=arch:
@nix build ".#nixosConfigurations.iso-{{variant}}-{{arch}}-linux.config.system.build.isoImage"
iso variant="minimal" arch=arch *FLAGS="":
@nix build ".#nixosConfigurations.iso-{{variant}}-{{arch}}-linux.config.system.build.isoImage" {{FLAGS}}

vm variant="minimal" arch=arch:
vm variant="minimal" arch=arch *FLAGS="":
@just iso {{variant}} {{arch}}
@find result/iso -type f -name "*.iso" | head -n1 | xargs nix run 'nixpkgs#qemu_kvm' -- -boot d -smbios type=0,uefi=on -m 2G -cdrom
@find result/iso -type f -name "*.iso" | head -n1 | xargs -I% nix run 'nixpkgs#qemu_kvm' -- -boot d -smbios type=0,uefi=on -m 2G -cdrom % {{FLAGS}}

0 comments on commit c7144e6

Please sign in to comment.