In the process of moving to secure systemd services. kdc currently broken.
This commit is contained in:
parent
9c3d00c7d3
commit
8ba00ed209
@ -86,6 +86,13 @@ in {
|
|||||||
timing = "weekly";
|
timing = "weekly";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auth.kdc = {
|
||||||
|
enable = true;
|
||||||
|
realm = "SELBY.CA";
|
||||||
|
acl-file = "/var/heimdal/access.acl";
|
||||||
|
bind-addresses = [ "10.0.0.1" "127.0.0.1" "::1" ];
|
||||||
|
};
|
||||||
|
|
||||||
secure-dns-proxy = {
|
secure-dns-proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
listen-port = dns-proxy-port;
|
listen-port = dns-proxy-port;
|
||||||
|
@ -38,6 +38,8 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fail2ban.enable = true;
|
||||||
|
|
||||||
xserver = {
|
xserver = {
|
||||||
layout = "us";
|
layout = "us";
|
||||||
xkbVariant = "dvp";
|
xkbVariant = "dvp";
|
||||||
|
@ -3,5 +3,4 @@
|
|||||||
{
|
{
|
||||||
ip = import ./ip.nix { inherit lib; };
|
ip = import ./ip.nix { inherit lib; };
|
||||||
dns = import ./dns.nix { inherit lib; };
|
dns = import ./dns.nix { inherit lib; };
|
||||||
system = import ./system.nix { inherit lib; };
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
{ pkgs, lib, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let cfg = config.fudo.chat;
|
||||||
cfg = config.fudo.chat;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.chat = {
|
options.fudo.chat = {
|
||||||
@ -33,7 +32,8 @@ in {
|
|||||||
|
|
||||||
smtp-password-file = mkOption {
|
smtp-password-file = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Path to a file containing the password to use while connecting to the SMTP server.";
|
description =
|
||||||
|
"Path to a file containing the password to use while connecting to the SMTP server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
@ -97,10 +97,12 @@ in {
|
|||||||
};
|
};
|
||||||
EnableEmailInvitations = true;
|
EnableEmailInvitations = true;
|
||||||
SqlSettings.DriverName = "postgres";
|
SqlSettings.DriverName = "postgres";
|
||||||
SqlSettings.DataSource =
|
SqlSettings.DataSource = "postgres://${cfg.database.user}:${
|
||||||
"postgres://${cfg.database.user}:${fileContents cfg.database.password-file}@${cfg.database.hostname}:5432/${cfg.database.name}";
|
fileContents cfg.database.password-file
|
||||||
|
}@${cfg.database.hostname}:5432/${cfg.database.name}";
|
||||||
};
|
};
|
||||||
mattermost-config-file = pkgs.writeText "mattermost-config.json" (builtins.toJSON modified-config);
|
mattermost-config-file =
|
||||||
|
pkgs.writeText "mattermost-config.json" (builtins.toJSON modified-config);
|
||||||
mattermost-user = "mattermost";
|
mattermost-user = "mattermost";
|
||||||
mattermost-group = "mattermost";
|
mattermost-group = "mattermost";
|
||||||
|
|
||||||
@ -113,11 +115,7 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
groups = {
|
groups = { ${mattermost-group} = { members = [ mattermost-user ]; }; };
|
||||||
${mattermost-group} = {
|
|
||||||
members = [ mattermost-user ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
system.activationScripts.mattermost = ''
|
system.activationScripts.mattermost = ''
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let cfg = config.fudo.garbage-collector;
|
||||||
cfg = config.fudo.garbage-collector;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
@ -12,7 +11,8 @@ in {
|
|||||||
timing = mkOption {
|
timing = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "weekly";
|
default = "weekly";
|
||||||
description = "Period (systemd format) at which to run garbage collector.";
|
description =
|
||||||
|
"Period (systemd format) at which to run garbage collector.";
|
||||||
};
|
};
|
||||||
|
|
||||||
age = mkOption {
|
age = mkOption {
|
||||||
@ -23,27 +23,13 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
systemd = {
|
fudo.system.services.fudo-garbage-collector = {
|
||||||
timers.fudo-garbage-collector = {
|
description = "Collect NixOS garbage older than ${cfg.age}.";
|
||||||
enable = true;
|
onCalendar = cfg.timing;
|
||||||
description = "Collect NixOS garbage older than ${cfg.age}";
|
type = "oneshot";
|
||||||
partOf = [ "fudo-garbage-collector.service" ];
|
script =
|
||||||
wantedBy = [ "timers.target" ];
|
"${pkgs.nix}/bin/nix-collect-garbage --delete-older-than ${cfg.age}";
|
||||||
timerConfig = {
|
addressFamilies = [ ];
|
||||||
OnCalendar = cfg.timing;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.fudo-garbage-collector = {
|
|
||||||
enable = true;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
StandardOutput = "journal";
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
${pkgs.nix}/bin/nix-collect-garbage --delete-older-than ${cfg.age}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
143
lib/fudo/kdc.nix
143
lib/fudo/kdc.nix
@ -2,73 +2,90 @@
|
|||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.fudo.auth.kdc;
|
cfg = config.fudo.auth.kdc;
|
||||||
|
|
||||||
stringJoin = joiner: attrList:
|
initialize-db = realm: key-file:
|
||||||
if (length attrList) == 0 then
|
pkgs.writeShellScript "initialize-heimdal-db.sh" ''
|
||||||
""
|
if [ ! -e ${key-file} ]; then
|
||||||
else
|
${pkgs.heimdalFull}/bin/kadmin -l init --realm=${realm} --realm-max-ticket-life=1d --realm-max-renewable-life=2w ${realm}
|
||||||
foldr(lAttr: rAttr: "${lAttr}${joiner}${rAttr}") (last attrList) (init attrList);
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.auth.kdc = {
|
options.fudo.auth.kdc = with types; {
|
||||||
enable = mkEnableOption "Fudo KDC";
|
enable = mkEnableOption "Fudo KDC";
|
||||||
|
|
||||||
database-path = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The path at which to store the database files.
|
|
||||||
'';
|
|
||||||
default = "/var/heimdal/heimdal";
|
|
||||||
};
|
|
||||||
|
|
||||||
realm = mkOption {
|
realm = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = "The realm for which we are the acting KDC.";
|
||||||
The realm for which we are the acting KDC.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mkey-file = mkOption {
|
config-file = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = "Path to configuartion file.";
|
||||||
The path to the master key file.
|
default = "/etc/krb5.conf";
|
||||||
'';
|
};
|
||||||
|
|
||||||
|
master-key-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "The path to the master key file.";
|
||||||
|
default = "/var/heimdal/master.key";
|
||||||
};
|
};
|
||||||
|
|
||||||
acl-file = mkOption {
|
acl-file = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = "The path to the Access Control file.";
|
||||||
The path to the Access Control file.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bind-addresses = mkOption {
|
bind-addresses = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = ''
|
description = "A list of IP addresses on which to bind.";
|
||||||
A list of IP addresses on which to bind.
|
default = [ ];
|
||||||
'';
|
};
|
||||||
default = [];
|
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "User as which to run Heimdal servers.";
|
||||||
|
default = "kerberos";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Group as which to run Heimdal servers.";
|
||||||
|
default = "kerberos";
|
||||||
|
};
|
||||||
|
|
||||||
|
state-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path at which to store kerberos database.";
|
||||||
|
default = "/srv/kerberos";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
users = {
|
||||||
|
users.${cfg.user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
home = "/var/heimdal";
|
||||||
|
group = cfg.group;
|
||||||
|
};
|
||||||
|
|
||||||
|
groups.${cfg.group} = { members = [ cfg.user ]; };
|
||||||
|
};
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
systemPackages = [
|
systemPackages = [ pkgs.heimdalFull ];
|
||||||
pkgs.heimdalFull
|
|
||||||
];
|
|
||||||
|
|
||||||
etc."krb5.conf" = {
|
etc."krb5.conf" = {
|
||||||
text = mkAfter ''
|
text = mkAfter ''
|
||||||
[kdc]
|
[kdc]
|
||||||
database = {
|
database = {
|
||||||
realm = ${cfg.realm}
|
realm = ${cfg.realm}
|
||||||
mkey_file = ${cfg.mkey-file}
|
mkey_file = ${cfg.master-key-file}
|
||||||
acl_file = ${cfg.acl-file}
|
acl_file = ${cfg.acl-file}
|
||||||
}
|
}
|
||||||
addresses = ${stringJoin " " cfg.bind-addresses}
|
addresses = ${concatStringsSep " " cfg.bind-addresses}
|
||||||
|
|
||||||
# Binds to port 80!
|
# Binds to port 80!
|
||||||
enable-http = false
|
enable-http = false
|
||||||
@ -76,24 +93,44 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services = {
|
systemd = {
|
||||||
heimdal-kdc = {
|
tmpfiles.rules = [ "L /var/heimdal - - - - ${cfg.state-directory}" ];
|
||||||
enable = true;
|
};
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ];
|
fudo.system = {
|
||||||
description = "Heimdal Kerberos Key Distribution Center (ticket server)";
|
ensure-directories = {
|
||||||
serviceConfig = {
|
"${cfg.state-directory}" = {
|
||||||
ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kdc'';
|
user = cfg.user;
|
||||||
|
group = cfg.group;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
heimdal-admin-server = {
|
services = {
|
||||||
enable = true;
|
heimdal-kdc = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
description = "Heimdal Kerberos Remote Administration Server";
|
description =
|
||||||
serviceConfig = {
|
"Heimdal Kerberos Key Distribution Center (ticket server).";
|
||||||
ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kadmind'';
|
execStart =
|
||||||
|
"${pkgs.heimdalFull}/libexec/heimdal/kdc --config-file=${cfg.config-file}";
|
||||||
|
privateNetwork = false;
|
||||||
|
user = cfg.user;
|
||||||
|
group = cfg.group;
|
||||||
|
workingDirectory = cfg.state-directory;
|
||||||
|
preStart = "${initialize-db cfg.realm cfg.master-key-file}";
|
||||||
|
};
|
||||||
|
|
||||||
|
heimdal-admin-server = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
description = "Heimdal Kerberos Remote Administration Server.";
|
||||||
|
execStart =
|
||||||
|
"${pkgs.heimdalFull}/libexec/heimdal/kadmind --config-file=${cfg.config-file} --key-file=${cfg.master-key-file}";
|
||||||
|
privateNetwork = false;
|
||||||
|
user = cfg.user;
|
||||||
|
group = cfg.group;
|
||||||
|
workingDirectory = cfg.state-directory;
|
||||||
|
preStart = "${initialize-db cfg.realm cfg.master-key-file}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -51,10 +51,10 @@ in {
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
environment.systemPackages = with pkgs; [ dnsproxy ];
|
environment.systemPackages = with pkgs; [ dnsproxy ];
|
||||||
|
|
||||||
systemd.services.secure-dns-proxy = fudo-lib.system.default-service {
|
fudo.system.services.secure-dns-proxy = {
|
||||||
|
description = "DNS Proxy for secure DNS-over-HTTPS lookups.";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
description = "DNS Proxy for secure DNS-over-HTTPS lookups.";
|
|
||||||
privateNetwork = false;
|
privateNetwork = false;
|
||||||
requiredCapabilities = [ ];
|
requiredCapabilities = [ ];
|
||||||
restartWhen = "always";
|
restartWhen = "always";
|
||||||
|
@ -3,41 +3,439 @@
|
|||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.system;
|
cfg = config.fudo.system;
|
||||||
in {
|
|
||||||
options.fudo.system = {
|
|
||||||
disableTransparentHugePages = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
description = ''
|
|
||||||
Disable transparent huge pages (recommended for database loads, in
|
|
||||||
particular for Redis.
|
|
||||||
'';
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
postHugePageServices = mkOption {
|
mkDisableOption = description:
|
||||||
type = with types; listOf str;
|
mkOption {
|
||||||
description = "List of systemd services that should wait until after THP are disabled.";
|
|
||||||
default = [];
|
|
||||||
example = ["redis.service"];
|
|
||||||
};
|
|
||||||
|
|
||||||
tmpOnTmpfs = mkOption {
|
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = "Put tmp filesystem on tmpfs (needs enough RAM).";
|
|
||||||
default = true;
|
default = true;
|
||||||
|
description = description;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.disableTransparentHugePages {
|
isEmpty = lst: 0 == (length lst);
|
||||||
systemd.services.disableHugePages = {
|
|
||||||
description = "Turn off Transparent Huge Pages (https://www.kernel.org/doc/Documentation/vm/transhuge.txt)";
|
serviceOpts = { name, ... }:
|
||||||
after = [ "sysinit.target" "localfs-target" ];
|
with types; {
|
||||||
before = cfg.postHugePageServices;
|
options = {
|
||||||
enable = true;
|
after = mkOption {
|
||||||
serviceConfig = {
|
type = listOf str;
|
||||||
ExecStart = "/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null";
|
description = "List of services to start before this one.";
|
||||||
Type = "oneshot";
|
default = [ ];
|
||||||
|
};
|
||||||
|
script = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Simple shell script for the service to run.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
reloadScript = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Script to run whenever the service is restarted.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
before = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description =
|
||||||
|
"List of services before which this service should be started.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
requires = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description =
|
||||||
|
"List of services on which this service depends. If they fail to start, this service won't start.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
preStart = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Script to run prior to starting this service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
postStart = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Script to run after starting this service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
preStop = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Script to run prior to stopping this service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
postStop = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Script to run after stopping this service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
requiredBy = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description =
|
||||||
|
"List of services which require this service, and should fail without it.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
wantedBy = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [ ];
|
||||||
|
description =
|
||||||
|
"List of services before which this service should be started.";
|
||||||
|
};
|
||||||
|
environment = mkOption {
|
||||||
|
type = attrsOf str;
|
||||||
|
description = "Environment variables supplied to this service.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
environment-file = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description =
|
||||||
|
"File containing environment variables supplied to this service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
description = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Description of the service.";
|
||||||
|
};
|
||||||
|
path = mkOption {
|
||||||
|
type = listOf package;
|
||||||
|
description =
|
||||||
|
"A list of packages which should be in the service PATH.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
restartIfChanged =
|
||||||
|
mkDisableOption "Restart the service if the definition changes.";
|
||||||
|
dynamicUser = mkDisableOption "Create a new user for this service.";
|
||||||
|
privateNetwork = mkDisableOption "Only allow access to localhost.";
|
||||||
|
privateUsers =
|
||||||
|
mkDisableOption "Don't allow access to system user list.";
|
||||||
|
privateDevices = mkDisableOption
|
||||||
|
"Restrict access to system devices other than basics.";
|
||||||
|
privateTmp = mkDisableOption "Limit service to a private tmp dir.";
|
||||||
|
protectControlGroups =
|
||||||
|
mkDisableOption "Don't allow service to modify control groups.";
|
||||||
|
protectClock =
|
||||||
|
mkDisableOption "Don't allow service to modify system clock.";
|
||||||
|
restrictSuidSgid =
|
||||||
|
mkDisableOption "Don't allow service to suid or sgid binaries.";
|
||||||
|
protectKernelTunables =
|
||||||
|
mkDisableOption "Don't allow service to modify kernel tunables.";
|
||||||
|
privateMounts =
|
||||||
|
mkDisableOption "Don't allow service to access mounted devices.";
|
||||||
|
protectKernelModules = mkDisableOption
|
||||||
|
"Don't allow service to load or evict kernel modules.";
|
||||||
|
protectHome = mkDisableOption "Limit access to home directories.";
|
||||||
|
protectHostname =
|
||||||
|
mkDisableOption "Don't allow service to modify hostname.";
|
||||||
|
protectKernelLogs =
|
||||||
|
mkDisableOption "Don't allow access to kernel logs.";
|
||||||
|
lockPersonality = mkDisableOption "Lock service 'personality'.";
|
||||||
|
restrictRealtime =
|
||||||
|
mkDisableOption "Restrict service from using realtime functionality.";
|
||||||
|
restrictNamespaces =
|
||||||
|
mkDisableOption "Restrict service from using namespaces.";
|
||||||
|
memoryDenyWriteExecute = mkDisableOption
|
||||||
|
"Restrict process from executing from writable memory.";
|
||||||
|
keyringMode = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "private";
|
||||||
|
description = "Sharing state of process keyring.";
|
||||||
|
};
|
||||||
|
requiredCapabilities = mkOption {
|
||||||
|
type = listOf (enum capabilities);
|
||||||
|
default = [ ];
|
||||||
|
description = "List of capabilities granted to the service.";
|
||||||
|
};
|
||||||
|
restartWhen = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "on-failure";
|
||||||
|
description = "Conditions under which process should be restarted.";
|
||||||
|
};
|
||||||
|
restartSec = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 10;
|
||||||
|
description = "Number of seconds to wait before restarting service.";
|
||||||
|
};
|
||||||
|
execStart = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Command to run to launch the service.";
|
||||||
|
};
|
||||||
|
protectSystem = mkOption {
|
||||||
|
type = enum [ "true" "false" "full" "strict" ];
|
||||||
|
default = "full";
|
||||||
|
description =
|
||||||
|
"Level of protection to apply to the system for this service.";
|
||||||
|
};
|
||||||
|
addressFamilies = mkOption {
|
||||||
|
type = listOf (enum address-families);
|
||||||
|
default = [ ];
|
||||||
|
description = "List of address families which the service can use.";
|
||||||
|
};
|
||||||
|
workingDirectory = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = "Directory in which to launch the service.";
|
||||||
|
};
|
||||||
|
user = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "User as which to launch this service.";
|
||||||
|
};
|
||||||
|
group = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Primary group as which to launch this service.";
|
||||||
|
};
|
||||||
|
type = mkOption {
|
||||||
|
type =
|
||||||
|
enum [ "simple" "exec" "forking" "oneshot" "dbus" "notify" "idle" ];
|
||||||
|
default = "simple";
|
||||||
|
description = "Systemd service type of this service.";
|
||||||
|
};
|
||||||
|
partOf = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [ ];
|
||||||
|
description =
|
||||||
|
"List of targets to which this service belongs (and with which it should be restarted).";
|
||||||
|
};
|
||||||
|
standardOutput = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "journal";
|
||||||
|
description = "Destination of standard output for this service.";
|
||||||
|
};
|
||||||
|
standardError = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "journal";
|
||||||
|
description = "Destination of standard error for this service.";
|
||||||
|
};
|
||||||
|
pidFile = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Service PID file.";
|
||||||
|
};
|
||||||
|
networkWhitelist = mkOption {
|
||||||
|
type = nullOr (listOf str);
|
||||||
|
default = null;
|
||||||
|
description =
|
||||||
|
"A list of networks with which this process may communicate.";
|
||||||
|
};
|
||||||
|
allowedSyscalls = mkOption {
|
||||||
|
type = listOf (enum syscalls);
|
||||||
|
default = [ ];
|
||||||
|
description = "System calls which the service is permitted to make.";
|
||||||
|
};
|
||||||
|
maximumUmask = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "0077";
|
||||||
|
description = "Umask to apply to files created by the service.";
|
||||||
|
};
|
||||||
|
startOnlyPerms = mkDisableOption "Disable perms after startup.";
|
||||||
|
onCalendar = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description =
|
||||||
|
"Schedule on which the job should be invoked. See: man systemd.time(7).";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# See: man capabilities(7)
|
||||||
|
capabilities = [
|
||||||
|
"CAP_AUDIT_CONTROL"
|
||||||
|
"CAP_AUDIT_READ"
|
||||||
|
"CAP_AUDIT_WRITE"
|
||||||
|
"CAP_BLOCK_SUSPEND"
|
||||||
|
"CAP_BPF"
|
||||||
|
"CAP_CHECKPOINT_RESTORE"
|
||||||
|
"CAP_CHOWN"
|
||||||
|
"CAP_DAC_OVERRIDE"
|
||||||
|
"CAP_DAC_READ_SEARCH"
|
||||||
|
"CAP_FOWNER"
|
||||||
|
"CAP_FSETID"
|
||||||
|
"CAP_IPC_LOCK"
|
||||||
|
"CAP_IPC_OWNER"
|
||||||
|
"CAP_KILL"
|
||||||
|
"CAP_LEASE"
|
||||||
|
"CAP_LINUX_IMMUTABLE"
|
||||||
|
"CAP_MAC_ADMIN"
|
||||||
|
"CAP_MAC_OVERRIDE"
|
||||||
|
"CAP_MKNOD"
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
"CAP_NET_BROADCAST"
|
||||||
|
"CAP_NET_RAW"
|
||||||
|
"CAP_PERFMON"
|
||||||
|
"CAP_SETGID"
|
||||||
|
"CAP_SETFCAP"
|
||||||
|
"CAP_SETPCAP"
|
||||||
|
"CAP_SETUID"
|
||||||
|
"CAP_SYS_ADMIN"
|
||||||
|
"CAP_SYS_BOOT"
|
||||||
|
"CAP_SYS_CHROOT"
|
||||||
|
"CAP_SYS_MODULE"
|
||||||
|
"CAP_SYS_NICE"
|
||||||
|
"CAP_SYS_PACCT"
|
||||||
|
"CAP_SYS_PTRACE"
|
||||||
|
"CAP_SYS_RAWIO"
|
||||||
|
"CAP_SYS_RESOURCE"
|
||||||
|
"CAP_SYS_TIME"
|
||||||
|
"CAP_SYS_TTY_CONFIG"
|
||||||
|
"CAP_SYSLOG"
|
||||||
|
"CAP_WAKE_ALARM"
|
||||||
|
];
|
||||||
|
|
||||||
|
syscalls = [
|
||||||
|
"@clock"
|
||||||
|
"@debug"
|
||||||
|
"@module"
|
||||||
|
"@mount"
|
||||||
|
"@raw-io"
|
||||||
|
"@reboot"
|
||||||
|
"@swap"
|
||||||
|
"@privileged"
|
||||||
|
"@resources"
|
||||||
|
"@cpu-emulation"
|
||||||
|
"@obsolete"
|
||||||
|
];
|
||||||
|
|
||||||
|
address-families = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
||||||
|
|
||||||
|
restrict-capabilities = allowed:
|
||||||
|
if (allowed == [ ]) then
|
||||||
|
"~${concatStringsSep " " capabilities}"
|
||||||
|
else
|
||||||
|
concatStringsSep " " allowed;
|
||||||
|
|
||||||
|
restrict-syscalls = allowed:
|
||||||
|
if (allowed == [ ]) then
|
||||||
|
"~${concatStringsSep " " syscalls}"
|
||||||
|
else
|
||||||
|
concatStringsSep " " allowed;
|
||||||
|
|
||||||
|
restrict-address-families = allowed:
|
||||||
|
if (allowed == [ ]) then
|
||||||
|
"~${concatStringsSep " " address-families}"
|
||||||
|
else
|
||||||
|
concatStringsSep " " allowed;
|
||||||
|
|
||||||
|
dirOpts = { path, ... }: {
|
||||||
|
options = with types; {
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "User by whom the directory will be owned.";
|
||||||
|
default = "nobody";
|
||||||
|
};
|
||||||
|
group = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Group by which the directory will be owned.";
|
||||||
|
default = "nogroup";
|
||||||
|
};
|
||||||
|
perms = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Permission bits to apply to the directory.";
|
||||||
|
default = "0770";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.system = with types; {
|
||||||
|
services = mkOption {
|
||||||
|
type = attrsOf (submodule serviceOpts);
|
||||||
|
description = "Fudo system service definitions, with secure defaults.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
tmpOnTmpfs = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Put tmp filesystem on tmpfs (needs enough RAM).";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ensure-directories = mkOption {
|
||||||
|
type = attrsOf (submodule dirOpts);
|
||||||
|
description = "A map of required directories to directory properties.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# systemd.slices = mapAttrs (name: opts: {
|
||||||
|
# sliceConfig = {
|
||||||
|
# IpAddressAllow = opts.networkWhitelist;
|
||||||
|
# IpAddressDeny = "any";
|
||||||
|
# };
|
||||||
|
# }) (filterAttrs (name: opts: opts.networkWhitelist != null) cfg.services);
|
||||||
|
|
||||||
|
systemd.timers = mapAttrs (name: opts: {
|
||||||
|
enable = true;
|
||||||
|
description = opts.description;
|
||||||
|
partOf = [ "${name}.timer" ];
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = { OnCalendar = opts.onCalendar; };
|
||||||
|
}) (filterAttrs (name: opts: opts.onCalendar != null) cfg.services);
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = mapAttrsToList
|
||||||
|
(path: opts: "d ${path} ${opts.perms} ${opts.user} ${opts.group} - -")
|
||||||
|
cfg.ensure-directories;
|
||||||
|
|
||||||
|
systemd.targets.fudo-init = { wantedBy = [ "multi-user.target" ]; };
|
||||||
|
|
||||||
|
systemd.services = mapAttrs (name: opts: {
|
||||||
|
enable = true;
|
||||||
|
script = mkIf (opts.script != null) opts.script;
|
||||||
|
reload = mkIf (opts.reloadScript != null) opts.reloadScript;
|
||||||
|
after = opts.after ++ [ "fudo-init.target" ];
|
||||||
|
before = opts.before;
|
||||||
|
requires = opts.requires;
|
||||||
|
wantedBy = opts.wantedBy;
|
||||||
|
preStart = mkIf (opts.preStart != null) opts.preStart;
|
||||||
|
postStart = mkIf (opts.postStart != null) opts.postStart;
|
||||||
|
postStop = mkIf (opts.postStop != null) opts.postStop;
|
||||||
|
preStop = mkIf (opts.preStop != null) opts.preStop;
|
||||||
|
partOf = opts.partOf;
|
||||||
|
requiredBy = opts.requiredBy;
|
||||||
|
environment = opts.environment;
|
||||||
|
description = opts.description;
|
||||||
|
restartIfChanged = opts.restartIfChanged;
|
||||||
|
path = opts.path;
|
||||||
|
serviceConfig = {
|
||||||
|
PrivateNetwork = opts.privateNetwork;
|
||||||
|
PrivateUsers = opts.privateUsers;
|
||||||
|
PrivateDevices = opts.privateDevices;
|
||||||
|
PrivateTmp = opts.privateTmp;
|
||||||
|
PrivateMounts = opts.privateMounts;
|
||||||
|
ProtectControlGroups = opts.protectControlGroups;
|
||||||
|
ProtectKernelTunables = opts.protectKernelTunables;
|
||||||
|
ProtectKernelModules = opts.protectKernelModules;
|
||||||
|
ProtectSystem = opts.protectSystem;
|
||||||
|
ProtectHostname = opts.protectHostname;
|
||||||
|
ProtectHome = opts.protectHome;
|
||||||
|
ProtectClock = opts.protectClock;
|
||||||
|
ProtectKernelLogs = opts.protectKernelLogs;
|
||||||
|
KeyringMode = opts.keyringMode;
|
||||||
|
EnvironmentFile = opts.environment-file;
|
||||||
|
# This is more complicated than it looks...
|
||||||
|
CapabilityBoundingSet = restrict-capabilities opts.requiredCapabilities;
|
||||||
|
DynamicUser = opts.dynamicUser;
|
||||||
|
Restart = opts.restartWhen;
|
||||||
|
WorkingDirectory =
|
||||||
|
mkIf (opts.workingDirectory != null) opts.workingDirectory;
|
||||||
|
RestrictAddressFamilies =
|
||||||
|
restrict-address-families opts.addressFamilies;
|
||||||
|
RestrictNamespaces = opts.restrictNamespaces;
|
||||||
|
User = mkIf (opts.user != null) opts.user;
|
||||||
|
Group = mkIf (opts.group != null) opts.group;
|
||||||
|
Type = opts.type;
|
||||||
|
StandardOutput = opts.standardOutput;
|
||||||
|
PIDFile = mkIf (opts.pidFile != null) opts.pidFile;
|
||||||
|
LockPersonality = opts.lockPersonality;
|
||||||
|
RestrictRealtime = opts.restrictRealtime;
|
||||||
|
ExecStart = mkIf (opts.execStart != null) opts.execStart;
|
||||||
|
MemoryDenyWriteExecute = opts.memoryDenyWriteExecute;
|
||||||
|
SystemCallFilter = restrict-syscalls opts.allowedSyscalls;
|
||||||
|
UMask = opts.maximumUmask;
|
||||||
|
|
||||||
|
IpAddressAllow =
|
||||||
|
mkIf (opts.networkWhitelist != null) opts.networkWhitelist;
|
||||||
|
IpAddressDeny = mkIf (opts.networkWhitelist != null) "any";
|
||||||
|
LimitNOFILE = "49152";
|
||||||
|
PermissionsStartOnly = opts.startOnlyPerms;
|
||||||
|
};
|
||||||
|
}) config.fudo.system.services;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
ip = import ./lib/ip.nix { };
|
|
||||||
dns = import ./lib/dns.nix { };
|
|
||||||
}
|
|
125
lib/system.nix
125
lib/system.nix
@ -1,125 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
# See: man capabilities(7)
|
|
||||||
capabilities = [
|
|
||||||
"CAP_AUDIT_CONTROL"
|
|
||||||
"CAP_AUDIT_READ"
|
|
||||||
"CAP_AUDIT_WRITE"
|
|
||||||
"CAP_BLOCK_SUSPEND"
|
|
||||||
"CAP_BPF"
|
|
||||||
"CAP_CHECKPOINT_RESTORE"
|
|
||||||
"CAP_CHOWN"
|
|
||||||
"CAP_DAC_OVERRIDE"
|
|
||||||
"CAP_DAC_READ_SEARCH"
|
|
||||||
"CAP_FOWNER"
|
|
||||||
"CAP_FSETID"
|
|
||||||
"CAP_IPC_LOCK"
|
|
||||||
"CAP_IPC_OWNER"
|
|
||||||
"CAP_KILL"
|
|
||||||
"CAP_LEASE"
|
|
||||||
"CAP_LINUX_IMMUTABLE"
|
|
||||||
"CAP_MAC_ADMIN"
|
|
||||||
"CAP_MAC_OVERRIDE"
|
|
||||||
"CAP_MKNOD"
|
|
||||||
"CAP_NET_ADMIN"
|
|
||||||
"CAP_NET_BIND_SERVICE"
|
|
||||||
"CAP_NET_BROADCAST"
|
|
||||||
"CAP_NET_RAW"
|
|
||||||
"CAP_PERFMON"
|
|
||||||
"CAP_SETGID"
|
|
||||||
"CAP_SETFCAP"
|
|
||||||
"CAP_SETPCAP"
|
|
||||||
"CAP_SETUID"
|
|
||||||
"CAP_SYS_ADMIN"
|
|
||||||
"CAP_SYS_BOOT"
|
|
||||||
"CAP_SYS_CHROOT"
|
|
||||||
"CAP_SYS_MODULE"
|
|
||||||
"CAP_SYS_NICE"
|
|
||||||
"CAP_SYS_PACCT"
|
|
||||||
"CAP_SYS_PTRACE"
|
|
||||||
"CAP_SYS_RAWIO"
|
|
||||||
"CAP_SYS_RESOURCE"
|
|
||||||
"CAP_SYS_TIME"
|
|
||||||
"CAP_SYS_TTY_CONFIG"
|
|
||||||
"CAP_SYSLOG"
|
|
||||||
"CAP_WAKE_ALARM"
|
|
||||||
];
|
|
||||||
|
|
||||||
restrict-capabilities = allowed:
|
|
||||||
if (allowed == [ ]) then
|
|
||||||
"~${concatStringsSep " " capabilities}"
|
|
||||||
else
|
|
||||||
concatStringsSep " " allowed;
|
|
||||||
|
|
||||||
in {
|
|
||||||
timed-service = { ... }: false;
|
|
||||||
|
|
||||||
default-service = { after ? [ ], script ? null, reloadScript ? null
|
|
||||||
, before ? [ ], requires ? [ ], preStart ? null, postStop ? null
|
|
||||||
, preStop ? null, postStart ? null, requiredBy ? [ ], environment ? { }
|
|
||||||
, description, restartIfChanged ? true, confine ? false, path ? [ ]
|
|
||||||
, privateNetwork ? true, dynamicUser ? true, privateUsers ? true
|
|
||||||
, privateDevices ? true, privateTmp ? true, protectControlGroups ? true
|
|
||||||
, restrictSuidSgid ? true, protectKernelTunables ? true
|
|
||||||
, privateMounts ? true, protectKernelModules ? true, protectHome ? true
|
|
||||||
, protectHostname ? true, keyringMode ? "private"
|
|
||||||
, requiredCapabilities ? [ ], restartWhen ? "on-failure", restartSec ? "10"
|
|
||||||
, execStart ? null, protectSystem ? "full", addressFamilies ? null
|
|
||||||
, wantedBy ? [ ], workingDirectory ? null, user ? null, group ? null
|
|
||||||
, type ? "simple", partOf ? [ ], standardOutput ? "journal", pidFile ? null
|
|
||||||
, lockPersonality ? true, restrictRealtime ? true, networkWhitelist ? null
|
|
||||||
, memoryDenyWriteExecute ? true, ... }: {
|
|
||||||
enable = true;
|
|
||||||
script = mkIf (script != null) script;
|
|
||||||
reload = mkIf (reloadScript != null) reloadScript;
|
|
||||||
after = after;
|
|
||||||
before = before;
|
|
||||||
requires = requires;
|
|
||||||
wantedBy = wantedBy;
|
|
||||||
preStart = mkIf (preStart != null) preStart;
|
|
||||||
postStart = mkIf (postStart != null) postStart;
|
|
||||||
postStop = mkIf (postStop != null) postStop;
|
|
||||||
preStop = mkIf (preStop != null) preStop;
|
|
||||||
partOf = partOf;
|
|
||||||
requiredBy = requiredBy;
|
|
||||||
environment = environment;
|
|
||||||
description = description;
|
|
||||||
restartIfChanged = restartIfChanged;
|
|
||||||
confinement = mkIf confine { enable = true; };
|
|
||||||
path = path;
|
|
||||||
serviceConfig = {
|
|
||||||
PrivateNetwork = privateNetwork;
|
|
||||||
PrivateUsers = privateUsers;
|
|
||||||
PrivateDevices = privateDevices;
|
|
||||||
PrivateTmp = privateTmp;
|
|
||||||
PrivateMounts = privateMounts;
|
|
||||||
ProtectControlGroups = protectControlGroups;
|
|
||||||
ProtectKernelTunables = protectKernelTunables;
|
|
||||||
ProtectKernelModules = protectKernelModules;
|
|
||||||
ProtectSystem = protectSystem;
|
|
||||||
ProtectHostname = protectHostname;
|
|
||||||
ProtectHome = protectHome;
|
|
||||||
KeyringMode = keyringMode;
|
|
||||||
# This is more complicated than it looks...
|
|
||||||
CapabilityBoundingSet = restrict-capabilities requiredCapabilities;
|
|
||||||
DynamicUser = dynamicUser;
|
|
||||||
Restart = restartWhen;
|
|
||||||
WorkingDirectory = mkIf (workingDirectory != null) workingDirectory;
|
|
||||||
RestrictAddressFamilies =
|
|
||||||
mkIf (addressFamilies != null) (concatStringsSep " " addressFamilies);
|
|
||||||
User = mkIf (user != null) user;
|
|
||||||
Group = mkIf (group != null) group;
|
|
||||||
Type = type;
|
|
||||||
StandardOutput = standardOutput;
|
|
||||||
PIDFile = mkIf (pidFile != null) pidFile;
|
|
||||||
LockPersonality = lockPersonality;
|
|
||||||
RestrictRealtime = restrictRealtime;
|
|
||||||
IpAddressAllow = mkIf (networkWhitelist != null) networkWhitelist;
|
|
||||||
IpAddressDeny = mkIf (networkWhitelist != null) "any";
|
|
||||||
ExecStart = mkIf (execStart != null) execStart;
|
|
||||||
MemoryDenyWriteExecute = memoryDenyWriteExecute;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user