Compare commits

..

3 Commits

Author SHA1 Message Date
felixalb c357448c94 WIP: Move krb5 realm to pvv.local, make sane ldap structure
Eval nix flake / evals (push) Failing after 1m51s
2026-05-25 12:24:31 +09:00
oysteikt 5d6f21c450 WIP: set up heimdal-openldap-sasl stack 2026-05-25 12:24:31 +09:00
oysteikt b91f6016f5 hosts/dagali: init 2026-05-25 12:24:30 +09:00
108 changed files with 1357 additions and 4523 deletions
-14
View File
@@ -20,7 +20,6 @@ keys:
- &host_lupine-4 age1ml48zztcmnrdrhrdsjrlyxf09jtmjgz46u8td4zm59wn3fm4g57qs4wg0l
- &host_lupine-5 age12gws5nws69vxryd3kt7q0ayngch90efmhqcrfhnnsmj00lkgxd4qsdkvqn
- &host_skrot age1hzkvnktkr8t5gvtq0ccw69e44z5z6wf00n3xhk3hj24emf07je5s6q2evr
- &host_temmie age10avsdvqger25z0lyzlq8v7xfzcmypkmjsswswaxwqnpnl6x9wcjq0uv2n7
- &host_gluttony age12czfkvuw9pjk5qny5c6m2hjhd634cj9r4dsa3ss5zkux5h4vvc7s7k4urq
creation_rules:
@@ -122,19 +121,6 @@ creation_rules:
pgp:
- *user_oysteikt
- path_regex: secrets/temmie/[^/]+\.yaml$
key_groups:
- age:
- *host_temmie
- *user_danio
- *user_felixalb
- *user_pederbs_sopp
- *user_pederbs_nord
- *user_pederbs_bjarte
- *user_vegardbm
pgp:
- *user_oysteikt
- path_regex: secrets/gluttony/[^/]+\.yaml$
key_groups:
- age:
+2 -21
View File
@@ -1,8 +1,6 @@
{
config,
pkgs,
lib,
inputs,
fp,
...
}:
@@ -14,6 +12,7 @@
./mitigations.nix
./flake-input-exporter.nix
./hardening.nix
./networking.nix
./nix.nix
@@ -30,37 +29,25 @@
./services/journald-upload.nix
./services/logrotate.nix
./services/nginx.nix
./services/nullmailer.nix
./services/openssh.nix
./services/polkit.nix
./services/prometheus-flake-input-exporter.nix
./services/postfix.nix
./services/prometheus-node-exporter.nix
./services/prometheus-systemd-exporter.nix
./services/roowho2.nix
./services/rsyslogd.nix
./services/scrutiny-collector.nix
./services/smartd.nix
./services/thermald.nix
./services/timesyncd.nix
./services/uptimed.nix
./services/userborn.nix
./services/userdbd.nix
];
system.nixos.tags = lib.optionals (inputs.self.sourceInfo ? dirtyRev) [ "dirty" ];
specialisation."auto-upgrade".configuration = {
system.nixos.tags = [ "auto" ];
};
boot.tmp.cleanOnBoot = lib.mkDefault true;
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
boot.loader.systemd-boot.enable = lib.mkDefault true;
boot.loader.efi.canTouchEfiVariables = lib.mkDefault true;
services.btrfs.autoScrub.enable = lib.mkDefault (lib.any ({ fsType, ... }: fsType == "btrfs") (lib.attrValues config.fileSystems));
time.timeZone = "Europe/Oslo";
i18n.defaultLocale = "en_US.UTF-8";
@@ -95,14 +82,8 @@
AllowHibernation = lib.mkDefault false;
};
systemd.slices."system-monitoring" = {
description = "Monitoring related services";
};
# users.mutableUsers = lib.mkDefault false;
users.users.root.initialHashedPassword = "$y$j9T$ahP6GAdttD17OMBo7Yqeh.$Ad7qBcFvTL7HrJ9uTtrQzksN3220Nj9t/CrP6DwgK34"; # generated using mkpasswd, see huttiheita root on vaultwarden
users.groups."drift".name = "drift";
# Trusted users on the nix builder machines
+55
View File
@@ -0,0 +1,55 @@
{
config,
inputs,
lib,
pkgs,
values,
...
}:
let
data = lib.flip lib.mapAttrs inputs (
name: input: {
inherit (input)
lastModified
;
}
);
folder = pkgs.writeTextDir "share/flake-inputs" (
lib.concatMapStringsSep "\n" (
{ name, value }: ''nixos_last_modified_input{flake="${name}"} ${toString value.lastModified}''
) (lib.attrsToList data)
);
port = 9102;
in
{
services.nginx.virtualHosts."${config.networking.fqdn}-nixos-metrics" = {
serverName = config.networking.fqdn;
serverAliases = [
"${config.networking.hostName}.pvv.org"
];
locations."/metrics" = {
root = "${folder}/share";
tryFiles = "/flake-inputs =404";
extraConfig = ''
default_type text/plain;
'';
};
listen = [
{
inherit port;
addr = "0.0.0.0";
}
];
extraConfig = ''
allow ${values.hosts.ildkule.ipv4}/32;
allow ${values.hosts.ildkule.ipv6}/128;
allow 127.0.0.1/32;
allow ::1/128;
allow ${values.ipv4-space};
allow ${values.ipv6-space};
deny all;
'';
};
networking.firewall.allowedTCPPorts = [ port ];
}
+4
View File
@@ -3,6 +3,10 @@
systemd.network.enable = true;
networking.domain = "pvv.ntnu.no";
networking.useDHCP = false;
# networking.search = [ "pvv.ntnu.no" "pvv.org" ];
# networking.nameservers = lib.mkDefault [ "129.241.0.200" "129.241.0.201" ];
# networking.tempAddresses = lib.mkDefault "disabled";
# networking.defaultGateway = values.hosts.gateway;
# The rest of the networking configuration is usually sourced from /values.nix
+1
View File
@@ -8,5 +8,6 @@
# Let's not spam LetsEncrypt in `nixos-rebuild build-vm` mode:
virtualisation.vmVariant = {
security.acme.defaults.server = "https://127.0.0.1";
users.users.root.initialPassword = "root";
};
}
-1
View File
@@ -13,7 +13,6 @@ in
"--refresh"
"--no-write-lock-file"
"--specialisation auto-upgrade"
# --update-input is deprecated since nix 2.22, and removed in lix 2.90
# as such we instead use --override-input combined with --refresh
# https://git.lix.systems/lix-project/lix/issues/400
+2 -5
View File
@@ -62,10 +62,8 @@ in
name = "loki";
match = "*";
host = "loki.pvv.ntnu.no";
port = 443;
tls = "on";
"tls.verify" = "on";
host = "ildkule.pvv.ntnu.no";
port = 3100;
uri = "/loki/api/v1/push";
compress = "gzip";
@@ -90,7 +88,6 @@ in
systemd.services.fluent-bit = lib.mkIf cfg.enable {
serviceConfig = {
Slice = "system-monitoring.slice";
StateDirectory = "fluent-bit";
# NOTE: This hardening might be way too strong for general purpose use, don't upstream this.
+2 -20
View File
@@ -1,22 +1,4 @@
{ config, pkgs, lib, ... }:
let
cfg = config.services.irqbalance;
in
{ ... }:
{
services.irqbalance.enable = true;
# irqbalance only has meaningful work to do on multi-socket machines, so
# skip starting it pointlessly everywhere else.
systemd.services.irqbalance.serviceConfig.ExecCondition = let
isMultiSocket = pkgs.writeShellApplication {
name = "irqbalance-is-multi-socket";
runtimeInputs = [ pkgs.coreutils ];
text = ''
sockets=$(cat /sys/devices/system/cpu/cpu*/topology/physical_package_id | sort -u | wc -l)
[ "$sockets" -gt 1 ]
'';
};
in lib.mkIf cfg.enable [
(lib.getExe isMultiSocket)
];
}
}
-1
View File
@@ -14,7 +14,6 @@ in
};
systemd.services."systemd-journal-upload".serviceConfig = lib.mkIf cfg.enable {
Slice = "system-monitoring.slice";
IPAddressDeny = "any";
IPAddressAllow = [
values.hosts.ildkule.ipv4
+24 -2
View File
@@ -1,5 +1,18 @@
{ config, lib, ... }:
{
# nginx return 444 for all nonexistent virtualhosts
systemd.services.nginx.after = [ "generate-snakeoil-certs.service" ];
environment.snakeoil-certs = lib.mkIf config.services.nginx.enable {
"/etc/certs/nginx" = {
owner = "nginx";
group = "nginx";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
services.nginx = {
recommendedTlsSettings = true;
recommendedProxySettings = true;
@@ -47,8 +60,17 @@
];
}
];
sslCertificate = "/etc/certs/nginx.crt";
sslCertificateKey = "/etc/certs/nginx.key";
addSSL = true;
extraConfig = "return 444;";
};
${config.networking.fqdn} = {
sslCertificate = lib.mkDefault "/etc/certs/nginx.crt";
sslCertificateKey = lib.mkDefault "/etc/certs/nginx.key";
addSSL = lib.mkDefault true;
extraConfig = lib.mkDefault "return 444;";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ 80 443 ];
}
-15
View File
@@ -1,15 +0,0 @@
{ config, lib, ... }:
{
services.nullmailer = {
enable = true;
config = {
adminaddr = "root@pvv.ntnu.no";
defaultdomain = "pvv.ntnu.no";
defaulthost = "pvv.ntnu.no";
me = lib.mkDefault config.networking.fqdn;
remotes = lib.mkDefault "smtp.pvv.ntnu.no smtp port=465 tls";
};
};
}
+5 -11
View File
@@ -10,18 +10,12 @@
Match All
'';
settings.PermitRootLogin = "yes";
settings.AcceptEnv = [
"LANG"
"LC_*"
"COLORTERM"
"GIT_PROTOCOL"
];
};
users.users."root".openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqVt4LCe0YIttr9swFxjkjn37ZDY9JxwVC+2gvfSINDJorOCtqPjDOTD2fTS1Gz08QCwpnLWq2kyvRchu6WgriAbSACpbZZBgxRaF/FVh3oiMVFGnNKGnv6/fdo/vZtu8mUVuqtmTrgLYpZdbR4oD3XiBlDKs7Cv5hPqt95lnP6MNFvE8mICCfd1PwhsABd2IQ5laz3u77/RXhNFJL0Kf2/+6gk9awcLuwHrPdvq7c3BxRHbc9UMRQENyjyQPa7aLe+uJBFLKP51I8VBuDpDacuibQx7nMt6N2UJ2KWI0JxRMHuJNq4S5jidR82aOw9gzGbTv30SKNLMqsZ0xj4LtdqCXDiZF6Lr09PsJYsvnBUFWa14HGcThKDtgwQwBryNViYmfv//0h9+RLZiU0ab+NEwSs7Zh5iAD+vhx64QqNX3tR7Le4SWXh8W0eShU9N78qYdSkiC3Ui7htxeqOocXM/P4AwbnHsLELIvkHdvgchCPvl8ygZa4WJTEWv16+ICskJcAKWGuqjvXAFuwjJJmPp9xLW9O0DFfQhMELiGamQR9wK07yYQVr34iah6qZO7cwhSKyEPFrVPIaNtfDhsjED639F7vmktf26SWNJHWfW0wOHILjI6TgqUvy0JDd8W8w0CHlAfz6Fs2l99NNgNF8dB3vBASbxS0hu/y0PVu/xQ== openstack-sleipner"
users.users."root".openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqVt4LCe0YIttr9swFxjkjn37ZDY9JxwVC+2gvfSINDJorOCtqPjDOTD2fTS1Gz08QCwpnLWq2kyvRchu6WgriAbSACpbZZBgxRaF/FVh3oiMVFGnNKGnv6/fdo/vZtu8mUVuqtmTrgLYpZdbR4oD3XiBlDKs7Cv5hPqt95lnP6MNFvE8mICCfd1PwhsABd2IQ5laz3u77/RXhNFJL0Kf2/+6gk9awcLuwHrPdvq7c3BxRHbc9UMRQENyjyQPa7aLe+uJBFLKP51I8VBuDpDacuibQx7nMt6N2UJ2KWI0JxRMHuJNq4S5jidR82aOw9gzGbTv30SKNLMqsZ0xj4LtdqCXDiZF6Lr09PsJYsvnBUFWa14HGcThKDtgwQwBryNViYmfv//0h9+RLZiU0ab+NEwSs7Zh5iAD+vhx64QqNX3tR7Le4SWXh8W0eShU9N78qYdSkiC3Ui7htxeqOocXM/P4AwbnHsLELIvkHdvgchCPvl8ygZa4WJTEWv16+ICskJcAKWGuqjvXAFuwjJJmPp9xLW9O0DFfQhMELiGamQR9wK07yYQVr34iah6qZO7cwhSKyEPFrVPIaNtfDhsjED639F7vmktf26SWNJHWfW0wOHILjI6TgqUvy0JDd8W8w0CHlAfz6Fs2l99NNgNF8dB3vBASbxS0hu/y0PVu/xQ== openstack-sleipner"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICCbgJ0Uwh9VSVhfId7l9i5/jk4CvAK5rbkiab8R+moF root@sleipner"
];
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICCbgJ0Uwh9VSVhfId7l9i5/jk4CvAK5rbkiab8R+moF root@sleipner"
];
}
+5 -8
View File
@@ -6,13 +6,10 @@ in
security.polkit.enable = true;
environment.etc."polkit-1/rules.d/9-nixos-overrides.rules".text = lib.mkIf cfg.enable ''
polkit.addRule(function(action, subject) {
if (
action.id.startsWith("org.freedesktop.systemd1.") &&
subject.isInGroup("wheel")
) {
return polkit.Result.AUTH_SELF_KEEP;
}
});
polkit.addAdminRule(function(action, subject) {
if(subject.isInGroup("wheel")) {
return ["unix-user:"+subject.user];
}
});
'';
}
+22
View File
@@ -0,0 +1,22 @@
{ config, pkgs, lib, ... }:
let
cfg = config.services.postfix;
in
{
services.postfix = {
enable = true;
settings.main = {
myhostname = "${config.networking.hostName}.pvv.ntnu.no";
mydomain = "pvv.ntnu.no";
# Nothing should be delivered to this machine
mydestination = [ ];
relayhost = [ "smtp.pvv.ntnu.no:465" ];
smtp_tls_wrappermode = "yes";
smtp_tls_security_level = "encrypt";
};
};
}
@@ -1,47 +0,0 @@
{
config,
inputs,
lib,
pkgs,
values,
...
}:
let
data = lib.flip lib.mapAttrs inputs (
name: input: {
inherit (input)
lastModified
;
}
);
folder = pkgs.writeTextDir "share/flake-inputs" (
lib.concatMapStringsSep "\n" (
{ name, value }: ''nixos_last_modified_input{flake="${name}"} ${toString value.lastModified}''
) (lib.attrsToList data)
);
in
{
services.nginx = {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-nixos-flake-input-exporter/metrics" = {
root = "${folder}/share";
tryFiles = "/flake-inputs =404";
extraConfig = ''
default_type text/plain;
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
};
}
+9 -24
View File
@@ -5,34 +5,19 @@ in
{
services.prometheus.exporters.node = {
enable = lib.mkDefault true;
listenAddress = "127.0.0.1";
port = 9100;
enabledCollectors = [ "systemd" ];
};
services.nginx = lib.mkIf cfg.enable {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-node-exporter/metrics" = {
proxyPass = "http://localhost:${toString cfg.port}/metrics";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
systemd.services.prometheus-node-exporter.serviceConfig = lib.mkIf cfg.enable {
IPAddressDeny = "any";
IPAddressAllow = [
"127.0.0.1"
"::1"
values.hosts.ildkule.ipv4
values.hosts.ildkule.ipv6
];
};
systemd.services = lib.mkIf cfg.enable {
"prometheus-node-exporter".serviceConfig.Slice = "system-monitoring.slice";
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ cfg.port ];
}
+9 -24
View File
@@ -5,7 +5,6 @@ in
{
services.prometheus.exporters.systemd = {
enable = lib.mkDefault true;
listenAddress = "127.0.0.1";
port = 9101;
extraFlags = [
"--systemd.collector.enable-restart-count"
@@ -13,29 +12,15 @@ in
];
};
services.nginx = lib.mkIf cfg.enable {
enable = lib.mkDefault true;
virtualHosts.${config.networking.fqdn} = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-systemd-exporter/metrics" = {
proxyPass = "http://localhost:${toString cfg.port}/metrics";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
systemd.services.prometheus-systemd-exporter.serviceConfig = {
IPAddressDeny = "any";
IPAddressAllow = [
"127.0.0.1"
"::1"
values.hosts.ildkule.ipv4
values.hosts.ildkule.ipv6
];
};
systemd.services = lib.mkIf cfg.enable {
"prometheus-systemd-exporter".serviceConfig.Slice = "system-monitoring.slice";
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ cfg.port ];
}
-20
View File
@@ -1,20 +0,0 @@
{ config, lib, ... }:
let
cfg = config.services.rsyslogd;
in
{
services.rsyslogd = {
enable = lib.mkDefault true;
defaultConfig = ''
*.* @loghost.pvv.ntnu.no
'';
};
services.journald.extraConfig = lib.mkIf cfg.enable ''
ForwardToSyslog=yes
'';
systemd.services = lib.mkIf cfg.enable {
"syslog".serviceConfig.Slice = "system-monitoring.slice";
};
}
-11
View File
@@ -1,11 +0,0 @@
{ config, ... }:
{
services.scrutiny.collector = {
enable = !config.services.qemuGuest.enable;
settings = {
version = 1;
host.id = config.networking.hostName;
api.endpoint = "https://scrutiny.pvv.ntnu.no/";
};
};
}
-12
View File
@@ -1,12 +0,0 @@
{ ... }:
{
services.timesyncd = {
servers = [ "ntp.ntnu.no" ];
fallbackServers = [
"0.pool.ntp.org"
"1.pool.ntp.org"
"0.no.pool.ntp.org"
];
};
}
+1 -3
View File
@@ -23,7 +23,7 @@ in
};
};
systemd.services.uptimed = lib.mkIf cfg.enable {
systemd.services.uptimed = lib.mkIf (cfg.enable) {
serviceConfig = let
uptimed = pkgs.uptimed.overrideAttrs (prev: {
postPatch = ''
@@ -35,8 +35,6 @@ in
});
in {
Slice = "system-monitoring.slice";
Type = "notify";
ExecStart = lib.mkForce "${uptimed}/sbin/uptimed -f";
Generated
+69 -179
View File
@@ -1,34 +1,12 @@
{
"nodes": {
"bro": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1779629827,
"narHash": "sha256-nrlB50/oelB8oFx9DhOoXI5z0VoTZGEA6XxYvkvpqDA=",
"ref": "main",
"rev": "7d0f35e12e4dec39f981c08fc33515589f41f4a5",
"revCount": 3,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/bro.git"
},
"original": {
"ref": "main",
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/bro.git"
}
},
"crane": {
"locked": {
"lastModified": 1784407669,
"narHash": "sha256-gcFMcRjw0ZSn380Rx2QLlU1goUQeSrKX/DF12omI6+o=",
"lastModified": 1776635034,
"narHash": "sha256-OEOJrT3ZfwbChzODfIH4GzlNTtOFuZFWPtW7jIeR8xU=",
"owner": "ipetkov",
"repo": "crane",
"rev": "1316b7d278ad77a16aec024b71d971366e123bec",
"rev": "dc7496d8ea6e526b1254b55d09b966e94673750f",
"type": "github"
},
"original": {
@@ -44,11 +22,11 @@
]
},
"locked": {
"lastModified": 1784367836,
"narHash": "sha256-yeWTb3KNvHY/InqbVmIjQRH5BI4d2HFbQqWi2eRKiv0=",
"lastModified": 1771267058,
"narHash": "sha256-EEL4SmD1b3BPJPsSJJ4wDTXWMumJqbR+BLzhJJG0skE=",
"ref": "main",
"rev": "422f383fd8736d60cd2fe818168b93d07f013865",
"revCount": 259,
"rev": "e3962d02c78b9c7b4d18148d931a9a4bf22e7902",
"revCount": 254,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/dibbler.git"
},
@@ -104,11 +82,11 @@
]
},
"locked": {
"lastModified": 1784553797,
"narHash": "sha256-buGdmnsKNRDUNsb+aXGeUc/UjGGsMbH1KWy3xnheInA=",
"lastModified": 1777067150,
"narHash": "sha256-vqPz8jCS1zTQlvmgctUFpvnr6f9ISR5h7CPG/HgQvf0=",
"ref": "main",
"rev": "c3101eb7424d4b15665bd00624220ec411187797",
"revCount": 36,
"rev": "b452a854fb78d6df9fe062b45e23a968657d115d",
"revCount": 35,
"type": "git",
"url": "https://git.pvv.ntnu.no/Grzegorz/gergle.git"
},
@@ -123,14 +101,14 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"rust-overlay": "rust-overlay_2"
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1784553736,
"narHash": "sha256-W1pPlTHmp+EvONwf8Qa5NvCiuyV4LC/yNDdc27RSpuA=",
"lastModified": 1777019032,
"narHash": "sha256-29lw7THThWb5DW01rVRj1b816Apwz/P4m2wVWaSIadU=",
"ref": "main",
"rev": "e06daaef1f48160254c202c59b060ac6f1da9f38",
"revCount": 62,
"rev": "55262afca46c96f75a834d4e00e30d5fb20affb6",
"revCount": 61,
"type": "git",
"url": "https://git.pvv.ntnu.no/Grzegorz/greg-ng.git"
},
@@ -161,27 +139,6 @@
"url": "https://git.pvv.ntnu.no/Grzegorz/grzegorz-clients.git"
}
},
"libdib": {
"inputs": {
"nixpkgs": [
"worblehat",
"nixpkgs"
]
},
"locked": {
"lastModified": 1780178524,
"narHash": "sha256-2PcNyNqbGCWBpAMdCU1HxSQmhQiG6evdjxVnPA7w5bQ=",
"ref": "refs/heads/main",
"rev": "2406de41ce9d0a1404cbf4e55537e3f720f37f23",
"revCount": 15,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/libdib.git"
},
"original": {
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/libdib.git"
}
},
"matrix-next": {
"inputs": {
"nixpkgs": [
@@ -189,16 +146,16 @@
]
},
"locked": {
"lastModified": 1782122067,
"narHash": "sha256-95q3DiYOTHjQGbqR0I1w4ETrH+smtddqW0bBxaB/Egg=",
"lastModified": 1764844095,
"narHash": "sha256-Drf1orxsmFDzO+UbPo85gHjXW7QzAM+6oTPvI7vOSik=",
"owner": "dali99",
"repo": "nixos-matrix-modules",
"rev": "0e0fd9f6a407b08dd5e180a2ff6c3808461e2c47",
"rev": "25b9f31ef1dbc3987b4c716de716239f2b283701",
"type": "github"
},
"original": {
"owner": "dali99",
"ref": "master",
"ref": "v0.8.0",
"repo": "nixos-matrix-modules",
"type": "github"
}
@@ -208,14 +165,14 @@
"nixpkgs": [
"nixpkgs"
],
"rust-overlay": "rust-overlay_3"
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1784554105,
"narHash": "sha256-lgtCXgYCf0ljf14H7K7ngxnUc30FwcHMJlDZx+7Nt8s=",
"lastModified": 1767906976,
"narHash": "sha256-igCg8I83eO+noF00raXVJqDxzLS2SrZN8fK5bnvO+xI=",
"ref": "main",
"rev": "cbd5b7318239303e19e8a7a407699ed85cc25d94",
"revCount": 18,
"rev": "626bc9b6bae6a997b347cdbe84080240884f2955",
"revCount": 17,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/minecraft-heatmap.git"
},
@@ -232,11 +189,11 @@
]
},
"locked": {
"lastModified": 1784554069,
"narHash": "sha256-5UNUBVAAMEvLanAyOgm6yGZgKJoTAZ2gXavKbMH+6OA=",
"lastModified": 1769500363,
"narHash": "sha256-vFxmdsLBPdTy5j2bf54gbTQi1XnWbZDmeR/BBh8MFrw=",
"ref": "main",
"rev": "62ffa4f7de826ced2c2a8ad787695118589450bb",
"revCount": 48,
"rev": "2618e434e40e109eaab6a0693313c7e0de7324a3",
"revCount": 47,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/minecraft-kartverket.git"
},
@@ -275,11 +232,11 @@
]
},
"locked": {
"lastModified": 1782153600,
"narHash": "sha256-Vbkgl7/x8+Gg0gMe94EStfIfNC4bHQIbaZrIAxpuQ/w=",
"lastModified": 1778407980,
"narHash": "sha256-r980BhsReZQe6FkmyNZkwCZpvzARo5jZgTl8HxjAssY=",
"owner": "oddlama",
"repo": "nix-topology",
"rev": "e61876f548e4f301d63640d30ecc1305c05c3986",
"rev": "ca0a602f650306d00d6f3e3c76d0f4c48a5c5adc",
"type": "github"
},
"original": {
@@ -291,11 +248,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1784526640,
"narHash": "sha256-UDnuu3uM64qjfVvsGSislJgP1j15FiFiDiKOjbGTv9Q=",
"rev": "036c2421db75172aeef4bb83921988891d4773c9",
"lastModified": 1779622335,
"narHash": "sha256-06G98ieM6l+OI7EMhlvchgDBDn+DvIWCNj40LDhKpmc=",
"rev": "705e9929918b43bd7b715dc0a878ac870449bb03",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/26.05-small/nixos-26.05.5692.036c2421db75/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/26.05-small/nixos-26.05beta1.705e9929918b/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
@@ -319,38 +276,17 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1784536202,
"narHash": "sha256-7CmHmK10lEXBgymS0DeYj4/4STLpzRWCc/5BfoIxHQo=",
"rev": "94f12be79cb7f961726a0157b4168bc722befeac",
"lastModified": 1778586796,
"narHash": "sha256-XmDljcG4x8slQDlsWOc77pCA1YVuYn8JGumkYlhfTxI=",
"rev": "b25e938b89759b5f9466fc53c4a970244f84dc39",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-26.11pre1037880.94f12be79cb7/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-26.05pre996582.b25e938b8975/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://nixos.org/channels/nixos-unstable-small/nixexprs.tar.xz"
}
},
"passwd2systemd-users": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1780764154,
"narHash": "sha256-Xvf9aBNLYDnbDKdtFjp5GEA/rZwVczHZWbJ0hac8Vv4=",
"ref": "main",
"rev": "8b4541be73ee3bd6c60525b2f42605efe89398c9",
"revCount": 14,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/passwd2systemd-users.git"
},
"original": {
"ref": "main",
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/passwd2systemd-users.git"
}
},
"pvv-calendar-bot": {
"inputs": {
"nixpkgs": [
@@ -358,11 +294,11 @@
]
},
"locked": {
"lastModified": 1784554034,
"narHash": "sha256-NbL+1ju1j53MqsjUCAFWgpVp3IXo2lLET1OoDdxc18Q=",
"lastModified": 1764869785,
"narHash": "sha256-FGTIpC7gB4lbeL0bfYzn1Ge0PaCpd7VqWBLhJBx0i4A=",
"ref": "main",
"rev": "a7cbd30941ee0430f6a626e7dc38b5358dcc8a2a",
"revCount": 30,
"rev": "8ce7fb0b1918bdb3d1489a40d73895693955e8b2",
"revCount": 23,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/calendar-bot.git"
},
@@ -379,11 +315,11 @@
]
},
"locked": {
"lastModified": 1784979981,
"narHash": "sha256-OnvjEXYU/InjJYH2+iIrvHWIjHnc5J9f84qWhrgAWlY=",
"lastModified": 1778960428,
"narHash": "sha256-YAs3LbFGlBLJW3xHeoQfTq2GBBXTvuSKl2WXDtloczU=",
"ref": "main",
"rev": "ffb8ed0c9df2444727e49f16f7e43ea70184dc4b",
"revCount": 590,
"rev": "927748790b1f7159adfe32a3ad9ec01d22e9c5a2",
"revCount": 583,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/nettsiden.git"
},
@@ -416,7 +352,6 @@
},
"root": {
"inputs": {
"bro": "bro",
"dibbler": "dibbler",
"disko": "disko",
"gergle": "gergle",
@@ -429,13 +364,11 @@
"nix-topology": "nix-topology",
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable",
"passwd2systemd-users": "passwd2systemd-users",
"pvv-calendar-bot": "pvv-calendar-bot",
"pvv-nettsiden": "pvv-nettsiden",
"qotd": "qotd",
"roowho2": "roowho2",
"sops-nix": "sops-nix",
"worblehat": "worblehat"
"sops-nix": "sops-nix"
}
},
"roowho2": {
@@ -444,20 +377,20 @@
"nixpkgs": [
"nixpkgs"
],
"rust-overlay": "rust-overlay_4"
"rust-overlay": "rust-overlay_3"
},
"locked": {
"lastModified": 1784550731,
"narHash": "sha256-KDrBGT98fQWlnEBmTvIijPq4n4sVLcETBu8EuL486SM=",
"lastModified": 1778600367,
"narHash": "sha256-YB0b2xUf4D8792D5Ay//7C3AjHyv+9yoy8K1mTe+wvE=",
"ref": "main",
"rev": "c0c0e47c8a45673c62462cadf38a489b72fd39ec",
"revCount": 112,
"rev": "8e5f2849ff7c9616100fe928261512a7ad647939",
"revCount": 91,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/roowho2.git"
},
"original": {
"ref": "main",
"rev": "c0c0e47c8a45673c62462cadf38a489b72fd39ec",
"rev": "8e5f2849ff7c9616100fe928261512a7ad647939",
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/roowho2.git"
}
@@ -465,16 +398,16 @@
"rust-overlay": {
"inputs": {
"nixpkgs": [
"bro",
"greg-ng",
"nixpkgs"
]
},
"locked": {
"lastModified": 1779419951,
"narHash": "sha256-dMX0PUslUHPajP6o8FEoRdFv9afq/dec4POR0vVfjK4=",
"lastModified": 1777000482,
"narHash": "sha256-CZ5FKUSA8FCJf0h9GWdPJXoVVDL9H5yC74GkVc5ubIM=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "5b5c521d6cae9ef4aa32f888eb2c0ce595c9be52",
"rev": "403c09094a877e6c4816462d00b1a56ff8198e06",
"type": "github"
},
"original": {
@@ -486,16 +419,16 @@
"rust-overlay_2": {
"inputs": {
"nixpkgs": [
"greg-ng",
"minecraft-heatmap",
"nixpkgs"
]
},
"locked": {
"lastModified": 1784526465,
"narHash": "sha256-L37teKC6oINWG4PGZLIqbphMWvSQ0PEz+aWxAk+rIDw=",
"lastModified": 1766371695,
"narHash": "sha256-W7CX9vy7H2Jj3E8NI4djHyF8iHSxKpb2c/7uNQ/vGFU=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "58c6334db52d51fc5dd8877c90b01f00cf8a696b",
"rev": "d81285ba8199b00dc31847258cae3c655b605e8c",
"type": "github"
},
"original": {
@@ -505,27 +438,6 @@
}
},
"rust-overlay_3": {
"inputs": {
"nixpkgs": [
"minecraft-heatmap",
"nixpkgs"
]
},
"locked": {
"lastModified": 1784526465,
"narHash": "sha256-L37teKC6oINWG4PGZLIqbphMWvSQ0PEz+aWxAk+rIDw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "58c6334db52d51fc5dd8877c90b01f00cf8a696b",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"rust-overlay_4": {
"inputs": {
"nixpkgs": [
"roowho2",
@@ -533,11 +445,11 @@
]
},
"locked": {
"lastModified": 1784438913,
"narHash": "sha256-NYF7ZM5ip0u+w1pBFDpIGEbrbgN/wpnLFAmBkWkYMXw=",
"lastModified": 1776914043,
"narHash": "sha256-qug5r56yW1qOsjSI99l3Jm15JNT9CvS2otkXNRNtrPI=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "afacd6819d3765a05814ee8e3de74c77d42ac799",
"rev": "2d35c4358d7de3a0e606a6e8b27925d981c01cc3",
"type": "github"
},
"original": {
@@ -553,11 +465,11 @@
]
},
"locked": {
"lastModified": 1783174389,
"narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=",
"lastModified": 1777944972,
"narHash": "sha256-VfGRo1qTBKOe3s2gOv8LSoA6Fk19PvBlwQ1ECN0Evn8=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9",
"rev": "c591bf665727040c6cc5cb409079acb22dcce33c",
"type": "github"
},
"original": {
@@ -566,28 +478,6 @@
"repo": "sops-nix",
"type": "github"
}
},
"worblehat": {
"inputs": {
"libdib": "libdib",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1780762731,
"narHash": "sha256-EuDaLnasWN0mpi995n+fAQQfPGBhqNW4fNjlQRpHt58=",
"ref": "main",
"rev": "931bd2d63e285e767c8c81c103dda3c0a63f2965",
"revCount": 108,
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/worblehat.git"
},
"original": {
"ref": "main",
"type": "git",
"url": "https://git.pvv.ntnu.no/Projects/worblehat.git"
}
}
},
"root": "root",
+8 -53
View File
@@ -23,10 +23,7 @@
dibbler.url = "git+https://git.pvv.ntnu.no/Projects/dibbler.git?ref=main";
dibbler.inputs.nixpkgs.follows = "nixpkgs";
worblehat.url = "git+https://git.pvv.ntnu.no/Projects/worblehat.git?ref=main";
worblehat.inputs.nixpkgs.follows = "nixpkgs";
matrix-next.url = "github:dali99/nixos-matrix-modules/master";
matrix-next.url = "github:dali99/nixos-matrix-modules/v0.8.0";
matrix-next.inputs.nixpkgs.follows = "nixpkgs";
nix-gitea-themes.url = "git+https://git.pvv.ntnu.no/Drift/nix-gitea-themes.git?ref=main";
@@ -35,7 +32,7 @@
minecraft-heatmap.url = "git+https://git.pvv.ntnu.no/Projects/minecraft-heatmap.git?ref=main";
minecraft-heatmap.inputs.nixpkgs.follows = "nixpkgs";
roowho2.url = "git+https://git.pvv.ntnu.no/Projects/roowho2.git?ref=main&rev=c0c0e47c8a45673c62462cadf38a489b72fd39ec";
roowho2.url = "git+https://git.pvv.ntnu.no/Projects/roowho2.git?ref=main&rev=8e5f2849ff7c9616100fe928261512a7ad647939";
roowho2.inputs.nixpkgs.follows = "nixpkgs";
greg-ng.url = "git+https://git.pvv.ntnu.no/Grzegorz/greg-ng.git?ref=main";
@@ -50,11 +47,6 @@
qotd.url = "git+https://git.pvv.ntnu.no/Projects/qotd.git?ref=main";
qotd.inputs.nixpkgs.follows = "nixpkgs";
bro.url = "git+https://git.pvv.ntnu.no/Projects/bro.git?ref=main";
bro.inputs.nixpkgs.follows = "nixpkgs";
passwd2systemd-users.url = "git+https://git.pvv.ntnu.no/Projects/passwd2systemd-users.git?ref=main";
passwd2systemd-users.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = {
@@ -97,18 +89,6 @@
];
});
apps = forAllSystems (system: let
pkgs = nixpkgs.legacyPackages.${system};
in {
gitea-workflows = {
type = "app";
meta.description = "Run all gitea workflows locally";
program = toString (pkgs.writeShellScript "pvv-nixos-config-run-gitea-worflows" ''
${lib.getExe pkgs.gitea-actions-runner} exec -i node:current-trixie
'');
};
});
nixosConfigurations = let
nixosConfig = nixpkgs: name: configurationPath: extraArgs @ {
localSystem ? "x86_64-linux", # buildPlatform
@@ -173,7 +153,6 @@
sops-nix.nixosModules.sops
inputs.roowho2.nixosModules.default
self.nixosModules.rsync-pull-targets
self.nixosModules.python-http-handlers
])
++ modules;
}
@@ -205,12 +184,6 @@
(final: prev: {
inherit (self.packages.${prev.stdenv.hostPlatform.system}) out-of-your-element;
})
(final: prev: {
# See https://git.pvv.ntnu.no/Drift/issues/issues/369
mjolnir = prev.mjolnir.override {
nodejs = prev.nodejs_22;
};
})
];
};
bekkalokk = stableNixosConfig "bekkalokk" {
@@ -234,26 +207,15 @@
};
skrot = stableNixosConfig "skrot" {
modules = [
self.nixosModules.drumknotty
inputs.disko.nixosModules.disko
inputs.dibbler.nixosModules.default
];
overlays =
[
inputs.dibbler.overlays.default
inputs.worblehat.overlays.default
];
overlays = [inputs.dibbler.overlays.default];
};
dagali = stableNixosConfig "dagali" { };
shark = stableNixosConfig "shark" {};
wenche = stableNixosConfig "wenche" {};
temmie = stableNixosConfig "temmie" {
overlays = [
inputs.bro.overlays.default
inputs.passwd2systemd-users.overlays.default
];
modules = [
inputs.bro.nixosModules.default
];
};
temmie = stableNixosConfig "temmie" {};
gluttony = stableNixosConfig "gluttony" {
overlays = [
(final: prev: { bluemap = final.callPackage ./packages/bluemap.nix {}; })
@@ -268,7 +230,6 @@
modules = [
inputs.nix-gitea-themes.nixosModules.default
inputs.disko.nixosModules.disko
self.nixosModules.robots-txt
];
};
@@ -308,10 +269,8 @@
nixosModules = {
bluemap = ./modules/bluemap.nix;
drumknotty = ./modules/drumknotty;
gickup = ./modules/gickup;
matrix-ooye = ./modules/matrix-ooye.nix;
python-http-handlers = ./modules/python-http-handlers.nix;
robots-txt = ./modules/robots-txt.nix;
rsync-pull-targets = ./modules/rsync-pull-targets.nix;
snakeoil-certs = ./modules/snakeoil-certs.nix;
@@ -372,12 +331,7 @@
//
# Machines
lib.genAttrs allMachines
(machine: self.nixosConfigurations.${machine}.config.system.build.toplevel.overrideAttrs (prev: {
passthru =
(prev.passthru or { })
// self.nixosConfigurations.${machine}.config.system.build
// { inherit (self.nixosConfigurations.${machine}) pkgs config; };
}))
(machine: self.nixosConfigurations.${machine}.config.system.build.toplevel)
//
# Nix-topology
(let
@@ -405,6 +359,7 @@
inputs.nix-topology.nixosModules.default
./topology/service-extractors/greg-ng.nix
./topology/service-extractors/postgresql.nix
./topology/service-extractors/mysql.nix
./topology/service-extractors/gitea-runners.nix
];
})
+2 -2
View File
@@ -7,13 +7,11 @@
./services/alps.nix
./services/bluemap.nix
./services/radicale.nix
./services/idp-simplesamlphp
./services/kerberos.nix
./services/mediawiki
./services/nginx.nix
./services/phpfpm.nix
./services/prometheus-phpfpm-exporter.nix
./services/vaultwarden.nix
./services/webmail
./services/website
@@ -26,6 +24,8 @@
address = with values.hosts.bekkalokk; [ (ipv4 + "/25") (ipv6 + "/64") ];
};
services.btrfs.autoScrub.enable = true;
# Don't change (even during upgrades) unless you know what you are doing.
# See https://search.nixos.org/options?show=system.stateVersion
system.stateVersion = "25.11";
@@ -16,7 +16,6 @@
fileSystems."/" =
{ device = "/dev/sda1";
fsType = "btrfs";
options = [ "relatime" ];
};
fileSystems."/boot" =
+5 -18
View File
@@ -107,7 +107,6 @@ in {
CodeEditor
CodeMirror
DeleteBatch
PdfHandler
PluggableAuth
Popups
Scribunto
@@ -182,17 +181,12 @@ in {
];
# Misc program paths
$wgFFmpegLocation = '${lib.getExe pkgs.ffmpeg}';
$wgExiftool = '${lib.getExe pkgs.exiftool}';
$wgExiv2Command = '${lib.getExe pkgs.exiv2}';
$wgFFmpegLocation = '${pkgs.ffmpeg}/bin/ffmpeg';
$wgExiftool = '${pkgs.exiftool}/bin/exiftool';
$wgExiv2Command = '${pkgs.exiv2}/bin/exiv2';
# See https://gist.github.com/sergejmueller/088dce028b6dd120a16e
$wgJpegTran = '${lib.getExe' pkgs.mozjpeg "jpegtran"}';
$wgGitBin = '${lib.getExe pkgs.git}';
$wgDiff3 = '${lib.getExe' pkgs.diffutils "diff3"}';
$wgDiff = '${lib.getExe' pkgs.diffutils "diff"}';
$wgUseImageMagick = true;
$wgImageMagickConvertCommand = '${lib.getExe pkgs.imagemagick}';
$wgJpegTran = '${pkgs.mozjpeg}/bin/jpegtran';
$wgGitBin = '${pkgs.git}/bin/git';
# Debugging
$wgShowExceptionDetails = false;
@@ -217,13 +211,6 @@ in {
# EXT:WikiEditor
$wgWikiEditorRealtimePreview = true;
# EXT:PdfHandler
$wgPdfProcessor = '${lib.getExe pkgs.ghostscript_headless}';
$wgPdfPostProcessor = $wgImageMagickConvertCommand;
$wgPdfInfo = '${lib.getExe' pkgs.poppler-utils "pdfinfo"}';
$wgPdftoText = '${lib.getExe' pkgs.poppler-utils "pdftotext"}';
# Override key from hardcoded config in nixpkgs
$wgSecretKey = file_get_contents("${config.sops.secrets."mediawiki/secret-key".path}");
'';
};
@@ -1,54 +0,0 @@
{ config, lib, values, ... }:
let
cfg = config.services.prometheus.exporters.php-fpm;
pools = [
"idp"
"mediawiki"
"pvv-nettsiden"
"roundcube"
"snappymail"
];
in
{
services.phpfpm.pools = lib.genAttrs pools (_: {
settings."pm.status_path" = "/status";
});
services.prometheus.exporters.php-fpm = {
enable = true;
listenAddress = "127.0.0.1";
extraFlags = [
"--phpfpm.scrape-uri=${lib.concatMapStringsSep "," (name: "unix://${config.services.phpfpm.pools.${name}.socket};/status") pools}"
];
};
systemd.services.prometheus-php-fpm-exporter.serviceConfig = {
Slice = "system-monitoring.slice";
SupplementaryGroups = [ config.services.nginx.group ];
RestrictAddressFamilies = lib.mkForce [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
};
services.nginx = lib.mkIf cfg.enable {
virtualHosts."www.pvv.ntnu.no" = lib.mkIf config.services.nginx.enable {
forceSSL = true;
enableACME = true;
kTLS = true;
locations."/prometheus-php-fpm-exporter/metrics" = {
proxyPass = "http://localhost:${toString cfg.port}/metrics";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.hosts.ildkule.ipv4};
allow ${values.hosts.ildkule.ipv6};
deny all;
'';
};
};
};
}
-40
View File
@@ -1,40 +0,0 @@
{ config, lib, ... }:
let
domain = "dav.pvv.ntnu.no";
radicalePort = 5232;
in {
services.radicale = {
enable = true;
settings = {
server = {
hosts = [ "127.0.0.1:${toString radicalePort}" ];
};
auth = {
type = "imap";
imap_host = "imap.pvv.ntnu.no";
imap_security = "tls";
};
storage = {
filesystem_folder = "/var/lib/radicale/collections";
};
};
};
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
kTLS = true;
extraConfig = ''
client_max_body_size 128M;
'';
locations."/" = {
proxyPass = "http://127.0.0.1:${toString radicalePort}";
proxyWebsockets = true;
};
};
}
+1 -2
View File
@@ -10,9 +10,8 @@
enableACME = true;
kTLS = true;
locations = {
# "= /".return = "302 https://webmail.pvv.ntnu.no/roundcube";
"= /".return = "302 https://webmail.pvv.ntnu.no/roundcube";
"/roundcube".return = "302 https://webmail.pvv.ntnu.no/";
"/afterlogic_lite".return = "302 https://webmail.pvv.ntnu.no/roundcube";
"/squirrelmail".return = "302 https://webmail.pvv.ntnu.no/roundcube";
"/rainloop".return = "302 https://snappymail.pvv.ntnu.no/";
+37 -2
View File
@@ -29,7 +29,7 @@ in
dicts = with pkgs.aspellDicts; [ en en-computers nb nn fr de it ];
maxAttachmentSize = 20;
hostName = domain;
hostName = "roundcubeplaceholder.example.com";
database = {
host = "postgres.pvv.ntnu.no";
@@ -49,9 +49,44 @@ in
'';
};
# TODO: move this back to `webmail.pvv.ntnu.no/roundcube` subpath
services.nginx.virtualHosts."roundcubeplaceholder.example.com" = lib.mkForce { };
services.nginx.virtualHosts.${domain} = {
kTLS = true;
locations."/roundcube" = {
tryFiles = "$uri $uri/ =404";
index = "index.php";
root = pkgs.runCommandLocal "roundcube-dir" { } ''
mkdir -p $out
ln -s ${cfg.package} $out/roundcube
'';
extraConfig = ''
location ~ ^/roundcube/(${builtins.concatStringsSep "|" [
# https://wiki.archlinux.org/title/Roundcube
"README"
"INSTALL"
"LICENSE"
"CHANGELOG"
"UPGRADING"
"bin"
"SQL"
".+\\.md"
"\\."
"config"
"temp"
"logs"
]})/? {
deny all;
}
location ~ ^/roundcube/(.+\.php)(/?.*)$ {
fastcgi_split_path_info ^/roundcube(/.+\.php)(/.+)$;
include ${config.services.nginx.package}/conf/fastcgi_params;
include ${config.services.nginx.package}/conf/fastcgi.conf;
fastcgi_index index.php;
fastcgi_pass unix:${config.services.phpfpm.pools.roundcube.socket};
}
'';
};
};
}
@@ -119,7 +119,6 @@ in {
services.nginx.virtualHosts."pvv.ntnu.no" = {
globalRedirect = cfg.domainName;
redirectCode = 307;
kTLS = true;
forceSSL = true;
useACMEHost = "www.pvv.ntnu.no";
};
@@ -127,7 +126,6 @@ in {
services.nginx.virtualHosts."www.pvv.org" = {
globalRedirect = cfg.domainName;
redirectCode = 307;
kTLS = true;
forceSSL = true;
useACMEHost = "www.pvv.ntnu.no";
};
@@ -135,13 +133,11 @@ in {
services.nginx.virtualHosts."pvv.org" = {
globalRedirect = cfg.domainName;
redirectCode = 307;
kTLS = true;
forceSSL = true;
useACMEHost = "www.pvv.ntnu.no";
};
services.nginx.virtualHosts.${cfg.domainName} = {
kTLS = true;
locations = {
# Proxy home directories
"^~ /~" = {
@@ -37,56 +37,47 @@ in {
};
systemd.services.pvv-nettsiden-gallery-update = {
path = with pkgs; [ imagemagick gnutar gzip ];
script = ''
tar ${lib.cli.toCommandLineShellGNU { } {
extract = true;
file = "${transferDir}/gallery.tar.gz";
directory = ".";
}}
# Delete files and directories that exists in the gallery that don't exist in the tarball
filesToRemove=$(uniq -u <(sort <(find . -not -path './.thumbnails*') <(tar -tf '${transferDir}/gallery.tar.gz' | sed 's|/$||')))
while IFS= read -r fname; do
rm -f "$fname" ||:
rm -f ".thumbnails/$fname.png" ||:
done <<< "$filesToRemove"
find . -type d -empty -delete
mkdir -p .thumbnails
images=$(find . -type f -not -path './.thumbnails*')
while IFS= read -r fname; do
# Skip this file if an up-to-date thumbnail already exists
if [ -f ".thumbnails/$fname.png" ] && \
[ "$(date -R -r "$fname")" == "$(date -R -r ".thumbnails/$fname.png")" ]
then
continue
fi
echo "Creating thumbnail for $fname"
mkdir -p "$(dirname ".thumbnails/$fname")"
magick -define jpeg:size=200x200 "$fname" -thumbnail 300 -auto-orient ".thumbnails/$fname.png" ||:
touch -m -d "$(date -R -r "$fname")" ".thumbnails/$fname.png"
done <<< "$images"
'';
serviceConfig = {
WorkingDirectory = galleryDir;
User = config.services.pvv-nettsiden.user;
Group = config.services.pvv-nettsiden.group;
ExecStart = lib.getExe (pkgs.writeShellApplication {
name = "pvv-nettsiden-gallery-update-exec-start.sh";
runtimeInputs = with pkgs; [
coreutils
findutils
gnused
gnutar
gzip
imagemagick
];
text = ''
tar ${lib.cli.toCommandLineShellGNU { } {
extract = true;
file = "${transferDir}/gallery.tar.gz";
directory = ".";
}}
# Delete files and directories that exists in the gallery that don't exist in the tarball
filesToRemove="$(uniq -u <(sort <(find . -not -path './.thumbnails*') <(tar -tf '${transferDir}/gallery.tar.gz' | sed 's|/$||')))"
while IFS= read -r fname; do
rm -f "$fname" ||:
rm -f ".thumbnails/$fname.png" ||:
done <<< "$filesToRemove"
find . -type d -empty -delete
mkdir -p .thumbnails
images="$(find . -type f -not -path './.thumbnails*')"
while IFS= read -r fname; do
# Skip this file if an up-to-date thumbnail already exists
if [ -f ".thumbnails/$fname.png" ] && \
[ "$(date -R -r "$fname")" == "$(date -R -r ".thumbnails/$fname.png")" ]
then
continue
fi
echo "Creating thumbnail for $fname"
mkdir -p "$(dirname ".thumbnails/$fname")"
magick -define jpeg:size=200x200 "$fname" -thumbnail 300 -auto-orient ".thumbnails/$fname.png" ||:
touch -m -d "$(date -R -r "$fname")" ".thumbnails/$fname.png"
done <<< "$images"
'';
});
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
@@ -83,7 +83,6 @@ in
};
services.nginx.virtualHosts."mirrors.pvv.ntnu.no" = {
kTLS = true;
forceSSL = true;
enableACME = true;
@@ -22,7 +22,6 @@ in
sops.templates."hookshot-registration.yaml" = {
owner = config.users.users.matrix-synapse.name;
group = config.users.groups.keys-matrix-registrations.name;
mode = "0440";
restartUnits = [ "matrix-hookshot.service" ];
content = ''
id: matrix-hookshot
@@ -50,59 +49,12 @@ in
systemd.services.matrix-hookshot = {
serviceConfig = {
DynamicUser = true;
SupplementaryGroups = [
config.users.groups.keys-matrix-registrations.name
];
LoadCredential = [
"passkey.pem:${config.sops.secrets."matrix/hookshot/passkey".path}"
];
RuntimeDirectory = [ "matrix-hookshot/root-mnt" ];
RootDirectory = "/run/matrix-hookshot/root-mnt";
BindReadOnlyPaths = [
config.sops.templates."hookshot-registration.yaml".path
builtins.storeDir
"/etc"
"/run/nscd"
"/var/run/nscd"
];
AmbientCapabilities = "";
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = false; # node needs this
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
};
@@ -194,7 +146,6 @@ in
};
services.nginx.virtualHosts."hookshot.pvv.ntnu.no" = {
kTLS = true;
enableACME = true;
addSSL = true;
locations."/" = {
-49
View File
@@ -54,53 +54,4 @@
# TODO: Fix upstream module in nixpkgs
pantalaimon.username = "bot_admin";
};
systemd.services.mjolnir.serviceConfig = {
DynamicUser = true;
RuntimeDirectory = [ "mjolnir/root-mnt" ];
RootDirectory = "/run/mjolnir/root-mnt";
BindReadOnlyPaths = [
config.sops.secrets."matrix/mjolnir/access_token".path
builtins.storeDir
"/etc"
"/run/nscd"
"/var/run/nscd"
];
AmbientCapabilities = "";
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = false; # node needs this
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
}
@@ -56,55 +56,6 @@ in
enableSynapseIntegration = false;
};
systemd.services."matrix-ooye" = {
serviceConfig = {
RuntimeDirectory = [ "matrix-ooye/root-mnt" ];
RootDirectory = "/run/matrix-ooye/root-mnt";
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/run/nscd"
"/var/run/nscd"
];
AmbientCapabilities = "";
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = false; # node needs this
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
};
systemd.services."matrix-synapse" = {
after = [
"matrix-ooye-pre-start.service"
@@ -129,7 +80,6 @@ in
};
services.nginx.virtualHosts."ooye.pvv.ntnu.no" = {
kTLS = true;
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://localhost:${cfg.socket}";
+1 -1
View File
@@ -74,7 +74,7 @@ in {
name = "psycopg2";
args = {
host = "/var/run/postgresql";
database = "synapse";
dbname = "synapse";
user = "matrix-synapse";
cp_min = 1;
cp_max = 5;
+22 -23
View File
@@ -23,28 +23,27 @@ in
};
systemd.services.minecraft-heatmap-ingest-logs = lib.mkIf cfg.enable {
serviceConfig = {
LoadCredential = [
"sshkey:${config.sops.secrets."minecraft-heatmap/ssh-key/private".path}"
];
ExecStartPre = let
knownHostsFile = pkgs.writeText "minecraft-heatmap-known-hosts" ''
innovation.pvv.ntnu.no ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE9O/y5uqcLKCodg2Q+XfZPH/AoUIyBlDhigImU+4+Kn
innovation.pvv.ntnu.no ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClR9GvWeVPZHudlnFXhGHUX5sGX9nscsOsotnlQ4uVuGsgvRifsVsuDULlAFXwoV1tYp4vnyXlsVtMddpLI5ANOIDcZ4fgDxpfSQmtHKssNpDcfMhFJbfRVyacipjA4osxTxvLox/yjtVt+URjTHUA1MWzEwc26KfiOvWO5tCBTan7doN/4KOyT05GwBxwzUAwUmoGTacIITck2Y9qp4+xFYqehbXqPdBb15hFyd38OCQhtU1hWV2Yi18+hJ4nyjc/g5pr6mW09ULlFghe/BaTUXrTisYC6bMcJZsTDwsvld9581KPvoNZOTQhZPTEQCZZ1h54fe0ZHuveVB3TIHovZyjoUuaf4uiFOjJVaKRB+Ig+Il6r7tMUn9CyHtus/Nd86E0TFBzoKxM0OFu88oaUlDtZVrUJL5En1lGoimajebb1JPxllFN5hqIT+gVyMY6nRzkcfS7ieny/U4rzXY2rfz98selftgh3LsBywwADv65i+mPw1A/1QdND1R6fV4U=
innovation.pvv.ntnu.no ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNjl3HfsDqmALWCL9uhz9k93RAD2565ndBqUh4N/rvI7MCwEJ6iRCdDev0YzB1Fpg24oriyYoxZRP24ifC2sQf8=
'';
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
archive = true;
verbose = true;
progress = true;
no-owner = true;
no-group = true;
};
sshCommand = ''${pkgs.openssh}/bin/ssh -o UserKnownHostsFile='${knownHostsFile}' -i \"$CREDENTIALS_DIRECTORY\"/sshkey'';
in [
"${lib.getExe' pkgs.coreutils "mkdir"} -p '${cfg.minecraftLogsDir}'"
"${lib.getExe pkgs.rsync} ${rsyncArgs} --rsh=\"${sshCommand}\" root@innovation.pvv.ntnu.no:. '${cfg.minecraftLogsDir}'/"
];
};
serviceConfig.LoadCredential = [
"sshkey:${config.sops.secrets."minecraft-heatmap/ssh-key/private".path}"
];
preStart = let
knownHostsFile = pkgs.writeText "minecraft-heatmap-known-hosts" ''
innovation.pvv.ntnu.no ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE9O/y5uqcLKCodg2Q+XfZPH/AoUIyBlDhigImU+4+Kn
innovation.pvv.ntnu.no ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClR9GvWeVPZHudlnFXhGHUX5sGX9nscsOsotnlQ4uVuGsgvRifsVsuDULlAFXwoV1tYp4vnyXlsVtMddpLI5ANOIDcZ4fgDxpfSQmtHKssNpDcfMhFJbfRVyacipjA4osxTxvLox/yjtVt+URjTHUA1MWzEwc26KfiOvWO5tCBTan7doN/4KOyT05GwBxwzUAwUmoGTacIITck2Y9qp4+xFYqehbXqPdBb15hFyd38OCQhtU1hWV2Yi18+hJ4nyjc/g5pr6mW09ULlFghe/BaTUXrTisYC6bMcJZsTDwsvld9581KPvoNZOTQhZPTEQCZZ1h54fe0ZHuveVB3TIHovZyjoUuaf4uiFOjJVaKRB+Ig+Il6r7tMUn9CyHtus/Nd86E0TFBzoKxM0OFu88oaUlDtZVrUJL5En1lGoimajebb1JPxllFN5hqIT+gVyMY6nRzkcfS7ieny/U4rzXY2rfz98selftgh3LsBywwADv65i+mPw1A/1QdND1R6fV4U=
innovation.pvv.ntnu.no ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNjl3HfsDqmALWCL9uhz9k93RAD2565ndBqUh4N/rvI7MCwEJ6iRCdDev0YzB1Fpg24oriyYoxZRP24ifC2sQf8=
'';
in ''
mkdir -p '${cfg.minecraftLogsDir}'
"${lib.getExe pkgs.rsync}" \
--archive \
--verbose \
--progress \
--no-owner \
--no-group \
--rsh="${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=\"${knownHostsFile}\" -i \"$CREDENTIALS_DIRECTORY\"/sshkey" \
root@innovation.pvv.ntnu.no:/ \
'${cfg.minecraftLogsDir}'/
'';
};
}
+1 -32
View File
@@ -4,10 +4,7 @@ let
dataDir = "/data/mysql";
in
{
imports = [
./backup.nix
./timed-jobs.nix
];
imports = [ ./backup.nix ];
sops.secrets."mysql/password" = {
owner = "mysql";
@@ -26,9 +23,6 @@ in
bind-address = values.services.mysql.ipv4;
skip-networking = 0;
# Useful for the mysqld prometheus exporter
userstat = 1;
# This was needed in order to be able to use all of the old users
# during migration from knakelibrak to bicep in Sep. 2023
secure_auth = 0;
@@ -57,18 +51,6 @@ in
mode = "0700";
};
fileSystems.${dataDir} = lib.mkIf cfg.enable {
device = dataDir;
fsType = "none";
options = [
"bind"
"noatime"
"noauto"
"x-systemd.requires=systemd-tmpfiles-setup.service"
"x-systemd.requires=systemd-tmpfiles-resetup.service"
];
};
systemd.services.mysql = lib.mkIf cfg.enable {
after = [
"systemd-tmpfiles-setup.service"
@@ -76,7 +58,6 @@ in
];
serviceConfig = {
RequiresMountsFor = [ dataDir ];
BindPaths = [ "${dataDir}:${cfg.dataDir}" ];
LogsDirectory = "mysql";
@@ -90,16 +71,4 @@ in
];
};
};
services.logrotate = lib.mkIf (cfg.settings.mysqld.slow-query-log == 1) {
enable = true;
settings.mysql-slowlog = {
files = [ cfg.settings.mysqld.slow-query-log-file ];
frequency = "weekly";
rotate = 12;
create = "0660 mysql mysql";
minsize = "1M";
compress = true;
};
};
}
-48
View File
@@ -1,48 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.mysql;
in
{
config = lib.mkIf cfg.enable {
systemd.services = {
mysql-analyze = {
requires = [ "mysql.service" ];
after = [ "mysql.service" ];
description = "Refresh MariaDB optimizer statistics for all databases";
startAt = "Mon 05:00:00";
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
Nice = 19;
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
ExecStart = "${lib.getExe' cfg.package "mariadb-check"} --all-databases --analyze";
};
};
mysql-optimize = {
requires = [ "mysql.service" ];
after = [ "mysql.service" ];
description = "Check, repair and optimize all MariaDB databases";
startAt = "*-*-01 04:00:00";
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
Nice = 19;
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
ExecStart = [
"${lib.getExe' cfg.package "mariadb-check"} --all-databases --auto-repair"
"${lib.getExe' cfg.package "mariadb-check"} --all-databases --optimize"
];
};
};
};
};
}
+1 -47
View File
@@ -14,7 +14,6 @@ in
extensions = ps: with ps; [ pg_repack ];
enableTCPIP = true;
# NOTE: md5 accepts both md5 and scram-sha-256
authentication = ''
host all all ${values.ipv4-space} md5
host all all ${values.ipv6-space} md5
@@ -77,15 +76,6 @@ in
maintenance_io_concurrency = 100;
wal_recycle = true;
# -------------------------------- #
# Authentication
password_encryption = "scram-sha-256";
# Logging
log_connections = "authorization";
log_disconnections = true;
# SSL
ssl = true;
ssl_cert_file = "/run/credentials/postgresql.service/cert";
@@ -99,18 +89,6 @@ in
mode = "0700";
};
fileSystems."/data/postgresql" = lib.mkIf cfg.enable {
device = "/data/postgresql";
fsType = "none";
options = [
"bind"
"noatime"
"noauto"
"x-systemd.requires=systemd-tmpfiles-setup.service"
"x-systemd.requires=systemd-tmpfiles-resetup.service"
];
};
systemd.services.postgresql-setup = lib.mkIf cfg.enable {
after = [
"systemd-tmpfiles-setup.service"
@@ -122,7 +100,6 @@ in
"key:/etc/certs/postgres.key"
];
RequiresMountsFor = [ "/data/postgresql" ];
BindPaths = [ "/data/postgresql:/var/lib/postgresql" ];
};
};
@@ -138,7 +115,6 @@ in
"key:/etc/certs/postgres.key"
];
RequiresMountsFor = [ "/data/postgresql" ];
BindPaths = [ "/data/postgresql:/var/lib/postgresql" ];
};
};
@@ -150,27 +126,5 @@ in
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enable [ 5432 ];
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "postgres-update-collations.sh";
runtimeInputs = [
config.systemd.package
cfg.package
];
text = ''
run0 --user=postgres psql <${pkgs.writeText "postgres-update-collations.sql" ''
CREATE FUNCTION exec(text) returns text language plpgsql volatile
AS $f$
BEGIN
EXECUTE $1;
RETURN $1;
END;
$f$;
SELECT exec('ALTER DATABASE "' || datname || '" REFRESH COLLATION VERSION') FROM pg_database WHERE datistemplate = false;
''}
'';
})
];
networking.firewall.allowedUDPPorts = lib.mkIf cfg.enable [ 5432 ];
}
+1 -23
View File
@@ -29,29 +29,7 @@
firewall = {
enable = true;
# Allow SSH and HTTP and ports for email and irc
allowedTCPPorts = [
22 # SSH
80 # HTTP
# IRC
194 # IRC
994 # IRC (TLS)
6697 # IRC (SSL)
6665
6666
6667
6668
6669
# EMAIL
25 # STMP
465 # STMP (SSL)
587 # STMP (TLS/STARTTLS)
110 # POP3
995 # POP3 (SSL/TLS)
143 # IMAP
993 # IMAP (SSL/TLS)
];
allowedTCPPorts = [ 80 22 194 994 6665 6666 6667 6668 6669 6697 995 993 25 465 587 110 143 993 995 ];
allowedUDPPorts = [ 80 22 194 994 6665 6666 6667 6668 6669 6697 995 993 25 465 587 110 143 993 995 ];
};
# Use systemd-resolved inside the container
@@ -16,7 +16,6 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/4e8667f8-55de-4103-8369-b94665f42204";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
+78
View File
@@ -0,0 +1,78 @@
# Tracking document for new PVV kerberos auth stack
![Bensinstasjon på heimdal](https://bydelsnytt.no/wp-content/uploads/2022/08/esso_heimdal003.jpg)
<div align="center">
Bensinstasjon på heimdal
</div>
### TODO:
- [ ] setup heimdal
- [x] ensure running with systemd
- [x] compile smbk5pwd (part of openldap)
- [ ] set `modify -a -disallow-all-tix,requires-pre-auth default` declaratively
- [ ] fully initialize PVV.NTNU.NO
- [x] `kadmin -l init PVV.NTNU.NO`
- [x] add oysteikt/admin@PVV.NTNU.NO principal
- [x] add oysteikt@PVV.NTNU.NO principal
- [x] add krbtgt/PVV.NTNU.NO@PVV.NTNU.NO principal?
- why is this needed, and where is it documented?
- `kadmin check` seems to work under sudo?
- (it is included by default, just included as error message
in a weird state)
- [x] Ensure client is working correctly
- [x] Ensure kinit works on darbu
- [x] Ensure kpasswd works on darbu
- [x] Ensure kadmin get <user> (and other restricted commands) works on darbu
- [ ] Ensure kdc is working correctly
- [x] Ensure kinit works on dagali
- [x] Ensure kpasswd works on dagali
- [ ] Ensure kadmin get <user> (and other restricte commands) works on dagali
- [x] Fix FQDN
- https://github.com/NixOS/nixpkgs/issues/94011
- https://github.com/NixOS/nixpkgs/issues/261269
- Possibly fixed by disabling systemd-resolved
- [ ] setup cyrus sasl
- [x] ensure running with systemd
- [x] verify GSSAPI support plugin is installed
- `nix-shell -p cyrus_sasl --command pluginviewer`
- [x] create "host/localhost@PVV.NTNU.NO" and export to keytab
- [x] verify cyrus sasl is able to talk to heimdal
- `sudo testsaslauthd -u oysteikt -p <password>`
- [ ] provide ldap principal to cyrus sasl through keytab
- [ ] setup openldap
- [x] ensure running with systemd
- [ ] verify openldap is able to talk to cyrus sasl
- [ ] create user for oysteikt in openldap
- [ ] authenticate openldap login through sasl
- does this require creating an ldap user?
- [ ] fix smbk5pwd integration
- [x] add smbk5pwd schemas to openldap
- [x] create openldap db for smbk5pwd with overlays
- [ ] test to ensure that user sync is working
- [ ] test as user source (replace passwd)
- [ ] test as PAM auth source
- [ ] test as auth source for 3rd party appliation
- [ ] Set up ldap administration panel
- Doesn't seem like there are many good ones out there. Maybe phpLDAPAdmin?
- [ ] Set up kerberos SRV DNS entry
### Information and URLS
- OpenLDAP SASL: https://www.openldap.org/doc/admin24/sasl.html
- Use a keytab: https://kb.iu.edu/d/aumh
- 2 ways for openldap to auth: https://security.stackexchange.com/questions/65093/how-to-test-ldap-that-authenticates-with-kerberos
- Cyrus guide OpenLDAP + SASL + GSSAPI: https://www.cyrusimap.org/sasl/sasl/faqs/openldap-sasl-gssapi.html
- Configuring GSSAPI and Cyrus SASL: https://web.mit.edu/darwin/src/modules/passwordserver_sasl/cyrus_sasl/doc/gssapi.html
- PVV Kerberos docs: https://wiki.pvv.ntnu.no/wiki/Drift/Kerberos
- OpenLDAP smbk5pwd source: https://git.openldap.org/nivanova/openldap/-/tree/master/contrib/slapd-modules/smbk5pwd
- saslauthd(8): https://linux.die.net/man/8/saslauthd
+51
View File
@@ -0,0 +1,51 @@
{ config, pkgs, values, lib, ... }:
{
imports = [
./hardware-configuration.nix
../../base.nix
../../misc/metrics-exporters.nix
./services/heimdal.nix
#./services/openldap.nix
./services/cyrus-sasl.nix
];
# buskerud does not support efi?
# boot.loader.systemd-boot.enable = true;
# boot.loader.efi.canTouchEfiVariables = true;
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
# resolved messes up FQDN coming from nscd
services.resolved.enable = false;
networking.hostName = "dagali";
networking.domain = lib.mkForce "pvv.local";
networking.hosts = {
"129.241.210.185" = [ "dagali.pvv.local" ];
};
#networking.search = [ "pvv.ntnu.no" "pvv.org" ];
networking.nameservers = [ "129.241.0.200" "129.241.0.201" ];
networking.tempAddresses = "disabled";
networking.networkmanager.enable = true;
systemd.network.networks."ens18" = values.defaultNetworkConfig // {
matchConfig.Name = "ens18";
address = with values.hosts.dagali; [ (ipv4 + "/25") (ipv6 + "/64") ];
};
# List packages installed in system profile
environment.systemPackages = with pkgs; [
# TODO: consider adding to base.nix
nix-output-monitor
];
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "24.05"; # Did you read the comment?
}
+33
View File
@@ -0,0 +1,33 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/4de345e2-be41-4d10-9b90-823b2c77e9b3";
fsType = "ext4";
};
swapDevices =
[ { device = "/dev/disk/by-uuid/aa4b9a97-a7d8-4608-9f67-4ad084f1baf7"; }
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.ens18.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
+21
View File
@@ -0,0 +1,21 @@
{ config, ... }:
let
cfg = config.services.saslauthd;
in
{
# TODO: This is seemingly required for openldap to authenticate
# against kerberos, but I have no idea how to configure it as
# such. Does it need a keytab? There's a binary "testsaslauthd"
# that follows with `pkgs.cyrus_sasl` that might be useful.
services.saslauthd = {
enable = true;
mechanism = "kerberos5";
config = ''
mech_list: gs2-krb5 gssapi
keytab: /etc/krb5.keytab
'';
};
# TODO: maybe the upstream module should consider doing this?
environment.systemPackages = [ cfg.package ];
}
+100
View File
@@ -0,0 +1,100 @@
{ config, pkgs, lib, ... }:
let
realm = "PVV.LOCAL";
cfg = config.security.krb5;
in
{
security.krb5 = {
enable = true;
# NOTE: This is required in order to build smbk5pwd, because of some nested includes.
# We should open an issue upstream (heimdal, not nixpkgs), but this patch
# will do for now.
package = pkgs.heimdal.overrideAttrs (prev: {
postInstall = prev.postInstall + ''
cp include/heim_threads.h $dev/include
'';
});
settings = {
realms.${realm} = {
kdc = [ "dagali.${lib.toLower realm}" ];
admin_server = "dagali.${lib.toLower realm}";
kpasswd_server = "dagali.${lib.toLower realm}";
default_domain = lib.toLower realm;
primary_kdc = "dagali.${lib.toLower realm}";
};
kadmin.default_keys = lib.concatStringsSep " " [
"aes256-cts-hmac-sha1-96:pw-salt"
"aes128-cts-hmac-sha1-96:pw-salt"
];
libdefaults.default_etypes = lib.concatStringsSep " " [
"aes256-cts-hmac-sha1-96"
"aes128-cts-hmac-sha1-96"
];
libdefaults = {
default_realm = realm;
dns_lookup_kdc = false;
dns_lookup_realm = false;
};
domain_realm = {
"${lib.toLower realm}" = realm;
".${lib.toLower realm}" = realm;
};
logging = {
# kdc = "CONSOLE";
kdc = "SYSLOG:DEBUG:AUTH";
admin_server = "SYSLOG:DEBUG:AUTH";
default = "SYSLOG:DEBUG:AUTH";
};
};
};
services.kerberos_server = {
enable = true;
settings = {
realms.${realm} = {
dbname = "/var/lib/heimdal/heimdal";
mkey = "/var/lib/heimdal/m-key";
acl = [
{
principal = "kadmin/admin";
access = "all";
}
{
principal = "felixalb/admin";
access = "all";
}
{
principal = "oysteikt/admin";
access = "all";
}
];
};
# kadmin.default_keys = lib.concatStringsSep " " [
# "aes256-cts-hmac-sha1-96:pw-salt"
# "aes128-cts-hmac-sha1-96:pw-salt"
# ];
# libdefaults.default_etypes = lib.concatStringsSep " " [
# "aes256-cts-hmac-sha1-96"
# "aes128-cts-hmac-sha1-96"
# ];
# password_quality.min_length = 8;
};
};
networking.firewall.allowedTCPPorts = [ 88 464 749 ];
networking.firewall.allowedUDPPorts = [ 88 464 749 ];
networking.hosts = {
"127.0.0.2" = lib.mkForce [ ];
"::1" = lib.mkForce [ ];
};
}
+121
View File
@@ -0,0 +1,121 @@
{ config, pkgs, lib, ... }:
{
services.openldap = let
dn = "dc=pvv,dc=ntnu,dc=no";
cfg = config.services.openldap;
heimdal = config.security.krb5.package;
in {
enable = true;
# NOTE: this is a custom build of openldap with support for
# perl and kerberos.
package = pkgs.openldap.overrideAttrs (prev: {
# https://github.com/openldap/openldap/blob/master/configure
configureFlags = prev.configureFlags ++ [
# Connect to slapd via UNIX socket
"--enable-local"
# Cyrus SASL
"--enable-spasswd"
# Reverse hostname lookups
"--enable-rlookups"
# perl
"--enable-perl"
];
buildInputs = prev.buildInputs ++ [
pkgs.perl
# NOTE: do not upstream this, it might not work with
# MIT in the same way
heimdal
];
extraContribModules = prev.extraContribModules ++ [
# https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules
"smbk5pwd"
];
});
settings = {
attrs = {
olcLogLevel = [ "stats" "config" "args" ];
# olcAuthzRegexp = ''
# gidNumber=.*\\\+uidNumber=0,cn=peercred,cn=external,cn=auth
# "uid=heimdal,${dn2}"
# '';
# olcSaslSecProps = "minssf=0";
};
children = {
"cn=schema".includes = let
# NOTE: needed for smbk5pwd.so module
schemaToLdif = name: path: pkgs.runCommandNoCC name {
buildInputs = with pkgs; [ schema2ldif ];
} ''
schema2ldif "${path}" > $out
'';
hdb-ldif = schemaToLdif "hdb.ldif" "${heimdal.src}/lib/hdb/hdb.schema";
samba-ldif = schemaToLdif "samba.ldif" "${heimdal.src}/tests/ldap/samba.schema";
in [
"${cfg.package}/etc/schema/core.ldif"
"${cfg.package}/etc/schema/cosine.ldif"
"${cfg.package}/etc/schema/nis.ldif"
"${cfg.package}/etc/schema/inetorgperson.ldif"
"${hdb-ldif}"
"${samba-ldif}"
];
# NOTE: installation of smbk5pwd.so module
# https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules/smbk5pwd
"cn=module{0}".attrs = {
objectClass = [ "olcModuleList" ];
olcModuleLoad = [ "${cfg.package}/lib/modules/smbk5pwd.so" ];
};
# NOTE: activation of smbk5pwd.so module for {1}mdb
"olcOverlay={0}smbk5pwd,olcDatabase={1}mdb".attrs = {
objectClass = [ "olcOverlayConfig" "olcSmbK5PwdConfig" ];
olcOverlay = "{0}smbk5pwd";
olcSmbK5PwdEnable = [ "krb5" "samba" ];
olcSmbK5PwdMustChange = toString (60 * 60 * 24 * 10000);
};
"olcDatabase={1}mdb".attrs = {
objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
olcDatabase = "{1}mdb";
olcSuffix = dn;
# TODO: PW is supposed to be a secret, but it's probably fine for testing
olcRootDN = "cn=users,${dn}";
# TODO: replace with proper secret
olcRootPW.path = pkgs.writeText "olcRootPW" "pass";
olcDbDirectory = "/var/lib/openldap/test-smbk5pwd-db";
olcDbIndex = "objectClass eq";
olcAccess = [
''{0}to attrs=userPassword,shadowLastChange
by dn.exact=cn=users,${dn} write
by self write
by anonymous auth
by * none''
''{1}to dn.base=""
by * read''
/* allow read on anything else */
# ''{2}to *
# by cn=users,${dn} write by dn.exact=gidNumber=0+uidNumber=0+cn=peercred,cn=external write
# by * read''
];
};
};
};
};
}
-1
View File
@@ -16,7 +16,6 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/33825f0d-5a63-40fc-83db-bfa1ebb72ba0";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
@@ -28,7 +28,6 @@
fileSystems."/" = {
device = "/dev/mapper/pool-root";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" = {
+2 -2
View File
@@ -93,7 +93,7 @@ in {
no-group = true;
rsh = "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
in "${lib.getExe pkgs.rsync} ${rsyncArgs} root@innovation.pvv.ntnu.no:. ${vanillaSurvival}";
in "${lib.getExe pkgs.rsync} ${rsyncArgs} root@innovation.pvv.ntnu.no:/ ${vanillaSurvival}";
ExecStartPost = let
rsyncArgs = lib.cli.toCommandLineShellGNU { } {
archive = true;
@@ -103,7 +103,7 @@ in {
no-group = true;
rsh = "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=%d/ssh-known-hosts -i %d/sshkey";
};
in "${lib.getExe pkgs.rsync} ${rsyncArgs} --groupmap=root:nginx ${config.services.bluemap.webRoot}/ root@bekkalokk.pvv.ntnu.no:.";
in "${lib.getExe pkgs.rsync} ${rsyncArgs} --groupmap=root:nginx ${config.services.bluemap.webRoot}/ root@bekkalokk.pvv.ntnu.no:/";
LoadCredential = [
"sshkey:${config.sops.secrets."bluemap/ssh-key".path}"
"ssh-known-hosts:${config.sops.secrets."bluemap/ssh-known-hosts".path}"
@@ -2,10 +2,9 @@
{
imports = [
./gatus
./grafana.nix
./loki.nix
./prometheus
./scrutiny.nix
./uptime-kuma.nix
];
}
@@ -1,169 +0,0 @@
{ config, lib, ... }:
let
cfg = config.services.gatus;
in
{
imports = [
./minecraft-checker.nix
./postgres-checker.nix
./mariadb-checker.nix
];
services.gatus = {
enable = true;
settings = {
web = {
address = "127.0.0.1";
port = 19283;
};
storage = {
type = "sqlite";
path = "/var/lib/gatus/data.db";
};
ui = {
title = "PVV Nede!?";
header = "😭😭😭";
dashboard-heading = "PVV Nede!?";
dashboard-subheading = "Kan noen ringe drift?";
};
endpoints = let
mkMachine = name: {
inherit name;
group = "Machines";
url = "icmp://${name}.pvv.ntnu.no";
conditions = [
"[CONNECTED] == true"
];
};
mkWebsite = name: url: {
inherit name url;
group = "Websites";
method = "GET";
conditions = [
"[STATUS] == 200"
];
};
mkService = name: url: {
inherit name url;
group = "Services";
conditions = [
"[CONNECTED] == true"
];
};
in (lib.sortOn (m: m.name) [
(mkMachine "ambidextrous")
(mkMachine "bekkalokk")
(mkMachine "bicep")
(mkMachine "bikkje")
(mkMachine "brzeczyszczykiewicz")
(mkMachine "georg")
(mkMachine "gluttony")
(mkMachine "ildkule")
(mkMachine "kana")
(mkMachine "kommode")
(mkMachine "lupine-1")
(mkMachine "lupine-2")
(mkMachine "lupine-3")
(mkMachine "lupine-4")
(mkMachine "lupine-5")
(mkMachine "skrot")
(mkMachine "temmie")
(mkMachine "wenche")
(mkMachine "balduzius")
(mkMachine "blossom")
(mkMachine "bubbles")
(mkMachine "buskerud")
(mkMachine "buttercup")
(mkMachine "demiurgen")
(mkMachine "drolsum")
(mkMachine "hildring")
(mkMachine "innovation")
(mkMachine "isvegg")
(mkMachine "knutsen")
(mkMachine "ludvigsen" // {
url = "icmp://ludvigsen-tap.pvv.ntnu.no";
})
(mkMachine "microbel")
(mkMachine "mirage")
(mkMachine "orchid")
(mkMachine "principal")
(mkMachine "sleipner")
(mkMachine "smask")
(mkMachine "tom")
(mkMachine "wegonke")
]) ++ [
(mkWebsite "Bluemap" "https://minecraft.pvv.ntnu.no")
(mkWebsite "Element Web" "https://chat.pvv.ntnu.no")
(mkWebsite "Gitea" "https://git.pvv.ntnu.no/api/healthz" // {
conditions = [
"[STATUS] == 200"
"[BODY].status == pass"
];
})
(mkWebsite "Grafana" "https://grafana.pvv.ntnu.no/api/health" // {
conditions = [
"[STATUS] == 200"
"[BODY].database == ok"
];
})
(mkWebsite "Grzegorz - Brzeczyszczykiewicz" "https://brzeczyszczykiewicz.pvv.ntnu.no")
(mkWebsite "Grzegorz - Georg" "https://georg.pvv.ntnu.no")
(mkWebsite "IDP" "https://idp.pvv.ntnu.no")
(mkWebsite "Mailing Lists" "http://list.pvv.ntnu.no")
(mkWebsite "Mapcrafter" "http://isvegg.pvv.ntnu.no/kart")
(mkWebsite "PVV-Nettsiden" "https://www.pvv.ntnu.no")
(mkWebsite "Roundcube" "https://webmail.pvv.ntnu.no/roundcube")
(mkWebsite "Scrutiny" "https://scrutiny.pvv.ntnu.no")
(mkWebsite "Snappymail" "http://snappymail.pvv.ntnu.no")
(mkWebsite "Userweb - Temmie" "https://temmie.pvv.ntnu.no/~oysteikt")
(mkWebsite "Userweb - Tom" "https://www.pvv.ntnu.no/~oysteikt")
(mkWebsite "Vaultwarden" "https://pw.pvv.ntnu.no/alive")
(mkWebsite "Wiki" "https://wiki.pvv.ntnu.no/w/api.php?action=query&format=json")
(mkService "Gitea SSH" "ssh://git.pvv.ntnu.no:2222")
(mkService "QoTD" "tcp://bekkalokk.pvv.ntnu.no:17")
(mkService "Minecraft" "http://localhost:1337" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "PostgreSQL" "http://localhost:1338" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "MariaDB" "http://localhost:1339" // {
conditions = [
"[STATUS] == 200"
"[BODY].ok == true"
];
})
(mkService "Email (SMTP)" "starttls://mail.pvv.ntnu.no:587")
(mkService "Email (POP3)" "tls://mail.pvv.ntnu.no:995")
(mkService "Email (IMAP)" "tls://mail.pvv.ntnu.no:993")
(mkService "Matrix Synapse" "https://matrix.pvv.ntnu.no/_matrix/client/versions" // {
method = "GET";
conditions = [
"[STATUS] == 200"
];
})
];
};
};
services.nginx.virtualHosts."status.pvv.ntnu.no" = lib.mkIf cfg.enable {
enableACME = true;
forceSSL = true;
kTLS = true;
locations."/".proxyPass = "http://localhost:${toString cfg.settings.web.port}";
};
}
@@ -1,79 +0,0 @@
{ config, pkgs, ... }:
{
sops.secrets."keys/gatus/mariadb" = {
restartUnits = [ "phh-gatus-mariadb-checker.service" ];
};
sops.templates."gatus-mariadb-checker.env" = {
restartUnits = [ "phh-gatus-mariadb-checker.service" ];
content = ''
MYSQL_HOST=mysql.pvv.ntnu.no
MYSQL_PORT=3306
MYSQL_DATABASE=mysql
MYSQL_USER=gatus_healthcheck
MYSQL_PASSWORD=${config.sops.placeholder."keys/gatus/mariadb"}
'';
};
services.python-http-handlers."gatus-mariadb-checker" = {
listenStreams = [ "127.0.0.1:1339" ];
libraries = with pkgs.python3Packages; [
pymysql
];
serviceConfig = {
EnvironmentFile = config.sops.templates."gatus-mariadb-checker.env".path;
};
handler = ''
import os
import json
import pymysql
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
conn = pymysql.connect(
host=os.environ["MYSQL_HOST"],
port=int(os.environ.get("MYSQL_PORT", "3306")),
user=os.environ["MYSQL_USER"],
password=os.environ["MYSQL_PASSWORD"],
database=os.environ.get("MYSQL_DATABASE", "mysql"),
connect_timeout=5,
)
try:
with conn.cursor() as cur:
cur.execute("SELECT VERSION();")
(version,) = cur.fetchone()
cur.execute("SHOW STATUS LIKE 'Threads_connected';")
(_, connections) = cur.fetchone()
cur.execute("SHOW DATABASES;")
databases = cur.fetchall()
finally:
conn.close()
body = {
"ok": True,
"version": version,
"connections": int(connections),
"databases": len(databases),
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
};
}
@@ -1,40 +0,0 @@
{ lib, pkgs, ... }:
{
services.python-http-handlers."gatus-minecraft-checker" = {
listenStreams = [ "127.0.0.1:1337" ];
libraries = with pkgs.python3Packages; [
mcstatus
];
handler = ''
import json
from mcstatus import JavaServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
mcserver = JavaServer.lookup("minecraft.pvv.ntnu.no")
status = mcserver.status()
body = {
"ok": True,
"players": status.players.online,
"version": status.version.name,
"latency": status.latency,
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.end_headers()
self.wfile.write(data)
'';
};
}
@@ -1,79 +0,0 @@
{ config, pkgs, ... }:
{
sops.secrets."keys/gatus/postgres" = {
restartUnits = [ "phh-gatus-postgres-checker.service" ];
};
sops.templates."gatus-postgres-checker.env" = {
restartUnits = [ "phh-gatus-postgres-checker.service" ];
content = ''
PGHOST=postgres.pvv.ntnu.no
PGPORT=5432
PGDATABASE=postgres
PGUSER=gatus_healthcheck
PGPASSWORD=${config.sops.placeholder."keys/gatus/postgres"}
'';
};
services.python-http-handlers."gatus-postgres-checker" = {
listenStreams = [ "127.0.0.1:1338" ];
libraries = with pkgs.python3Packages; [
psycopg2
];
serviceConfig = {
EnvironmentFile = config.sops.templates."gatus-postgres-checker.env".path;
};
handler = ''
import os
import json
import psycopg2
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
try:
conn = psycopg2.connect(
host=os.environ["PGHOST"],
port=os.environ.get("PGPORT", "5432"),
dbname=os.environ.get("PGDATABASE", "postgres"),
user=os.environ["PGUSER"],
password=os.environ["PGPASSWORD"],
connect_timeout=5,
)
try:
with conn.cursor() as cur:
cur.execute("SELECT version();")
(version,) = cur.fetchone()
cur.execute("SELECT count(*) FROM pg_stat_activity;")
(connections,) = cur.fetchone()
cur.execute("SELECT count(*) FROM pg_database WHERE NOT datistemplate;")
(databases,) = cur.fetchone()
finally:
conn.close()
body = {
"ok": True,
"version": version,
"connections": connections,
"databases": databases,
}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception as e:
data = json.dumps({"ok": False, "error": str(e)}).encode()
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
};
}
+4 -24
View File
@@ -1,4 +1,4 @@
{ config, pkgs, values, ... }:
{ config, pkgs, ... }:
let
cfg = config.services.loki;
@@ -9,8 +9,8 @@ in {
configuration = {
auth_enabled = false;
server = {
http_listen_port = 31832;
http_listen_address = "127.0.0.1";
http_listen_port = 3100;
http_listen_address = "0.0.0.0";
grpc_listen_port = 9096;
};
@@ -81,25 +81,5 @@ in {
};
};
services.nginx.virtualHosts."loki.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
kTLS = true;
locations = {
"/".return = "403";
"/loki/api/v1/push" = {
proxyPass = "http://${cfg.configuration.server.http_listen_address}:${toString cfg.configuration.server.http_listen_port}/loki/api/v1/push";
extraConfig = ''
allow 127.0.0.1;
allow ::1;
allow ${values.ipv4-space};
allow ${values.ipv6-space};
allow ${values.ntnu.ipv4-space};
allow ${values.ntnu.ipv6-space};
deny all;
'';
};
};
};
networking.firewall.allowedTCPPorts = [ cfg.configuration.server.http_listen_port ];
}
@@ -7,7 +7,6 @@ in {
./machines.nix
./matrix-synapse.nix
./mysqld.nix
./phpfpm.nix
./postgres.nix
];
@@ -1,12 +1,14 @@
{ ... }:
{
services.prometheus.scrapeConfigs = [{
job_name = "exim";
scrape_interval = "15s";
scheme = "http";
static_configs = [{
targets = [ "microbel.pvv.ntnu.no:9636" ];
}];
}];
services.prometheus = {
scrapeConfigs = [
{
job_name = "exim";
scrape_interval = "15s";
static_configs = [{
targets = [ "microbel.pvv.ntnu.no:9636" ];
}];
}
];
};
}
@@ -6,63 +6,32 @@
targets = map (port: "${name}.pvv.ntnu.no:${toString port}") ports;
};
nixosMachines = [
"ildkule"
"bekkalokk"
"bicep"
"brzeczyszczykiewicz"
"georg"
"gluttony"
"kommode"
"lupine-1"
"lupine-2"
"lupine-3"
"lupine-4"
"lupine-5"
# TODO: export prometheus stats via apache on temmie
# "temmie"
"wenche"
];
defaultNodeExporterPort = 9100;
defaultSystemdExporterPort = 9101;
defaultNixosExporterPort = 9102;
in {
services.prometheus.scrapeConfigs = [
{
job_name = "nixos-node";
scheme = "https";
metrics_path = "/prometheus-node-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "nixos-systemd";
scheme = "https";
metrics_path = "/prometheus-systemd-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "nixos-flake-input";
scheme = "https";
metrics_path = "/prometheus-nixos-flake-input-exporter/metrics";
static_configs = map (name: {
labels.hostname = name;
targets = [ "${name}.pvv.ntnu.no:443" ];
}) nixosMachines;
}
{
job_name = "non-nixos-node";
scheme = "http";
metrics_path = "/metrics";
static_configs = [
(mkHostScrapeConfig "hildring" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "isvegg" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "microbel" [ defaultNodeExporterPort ])
];
}
];
services.prometheus.scrapeConfigs = [{
job_name = "base_info";
static_configs = [
(mkHostScrapeConfig "ildkule" [ cfg.exporters.node.port cfg.exporters.systemd.port defaultNixosExporterPort ])
(mkHostScrapeConfig "bekkalokk" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "bicep" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "brzeczyszczykiewicz" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "georg" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "gluttony" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "kommode" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-1" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-2" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-3" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-4" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "lupine-5" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "temmie" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "wenche" [ defaultNodeExporterPort defaultSystemdExporterPort defaultNixosExporterPort ])
(mkHostScrapeConfig "hildring" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "isvegg" [ defaultNodeExporterPort ])
(mkHostScrapeConfig "microbel" [ defaultNodeExporterPort ])
];
}];
}
@@ -1,15 +0,0 @@
{ ... }:
{
services.prometheus.scrapeConfigs = [{
job_name = "phpfpm";
scheme = "https";
metrics_path = "/prometheus-php-fpm-exporter/metrics";
static_configs = [
{
labels.hostname = "bekkalokk";
targets = [ "www.pvv.ntnu.no:443" ];
}
];
}];
}
@@ -1,40 +0,0 @@
{ config, values, ... }:
let
cfg = config.services.scrutiny;
in
{
services.scrutiny = {
enable = true;
settings = {
web.listen = {
host = "127.0.0.1";
port = 18293;
basepath = "";
};
# notify.urls = [
# "matrix://username:password@host:port/[?rooms=!roomID1[,roomAlias2]]"
# ];
};
};
services.nginx.virtualHosts."scrutiny.pvv.ntnu.no" = {
kTLS = true;
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${cfg.settings.web.listen.host}:${toString cfg.settings.web.listen.port}";
};
# TODO: allow website access to the outside world, but restrict input api
extraConfig = ''
allow ${values.hosts.ildkule.ipv4}/32;
allow ${values.hosts.ildkule.ipv6}/128;
allow 127.0.0.1/32;
allow ::1/128;
allow ${values.ipv4-space};
allow ${values.ipv6-space};
deny all;
'';
};
}
@@ -0,0 +1,27 @@
{ config, pkgs, lib, ... }:
let
cfg = config.services.uptime-kuma;
domain = "status.pvv.ntnu.no";
stateDir = "/data/monitoring/uptime-kuma";
in {
services.uptime-kuma = {
enable = true;
settings = {
PORT = "5059";
HOST = "127.0.1.2";
};
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
kTLS = true;
locations."/".proxyPass = "http://${cfg.settings.HOST}:${cfg.settings.PORT}";
};
fileSystems."/var/lib/private/uptime-kuma" = {
device = stateDir;
fsType = "bind";
options = [ "bind" ];
};
}
+2
View File
@@ -15,6 +15,8 @@
address = with values.hosts.kommode; [ (ipv4 + "/25") (ipv6 + "/64") ];
};
services.btrfs.autoScrub.enable = true;
services.qemuGuest.enable = true;
# Don't change (even during upgrades) unless you know what you are doing.
-1
View File
@@ -48,7 +48,6 @@
# swap.swapfile.size = "4G";
mountpoint = "/";
mountOptions = [ "relatime" ];
};
};
@@ -72,52 +72,50 @@ in
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
PrivateNetwork = true;
ExecStart = let
logo-svg = fp /assets/logo_blue_regular.svg;
logo-png = fp /assets/logo_blue_regular.png;
extraLinks = pkgs.writeText "gitea-extra-links.tmpl" ''
<a class="item" href="https://git.pvv.ntnu.no/Drift/-/projects/4">Tokyo Drift Issues</a>
'';
extraLinksFooter = pkgs.writeText "gitea-extra-links-footer.tmpl" ''
<a class="item" href="https://www.pvv.ntnu.no/">PVV</a>
<a class="item" href="https://wiki.pvv.ntnu.no/">Wiki</a>
<a class="item" href="https://wiki.pvv.ntnu.no/wiki/Tjenester/Kodelager">PVV Gitea Howto</a>
'';
project-labels = (pkgs.formats.yaml { }).generate "gitea-project-labels.yaml" {
labels = lib.importJSON ./labels/projects.json;
};
customTemplates = pkgs.runCommandLocal "gitea-templates" {
nativeBuildInputs = with pkgs; [
coreutils
gnused
];
} ''
# Bigger icons
install -Dm444 '${cfg.package.src}/templates/repo/icon.tmpl' "$out/repo/icon.tmpl"
sed -i -e 's/24/60/g' "$out/repo/icon.tmpl"
'';
install = lib.getExe' pkgs.coreutils "install";
in [
"${install} -Dm444 '${logo-svg}' '${cfg.customDir}/public/assets/img/logo.svg'"
"${install} -Dm444 '${logo-png}' '${cfg.customDir}/public/assets/img/logo.png'"
"${install} -Dm444 '${./loading.apng}' '${cfg.customDir}/public/assets/img/loading.png'"
"${install} -Dm444 '${extraLinks}' '${cfg.customDir}/templates/custom/extra_links.tmpl'"
"${install} -Dm444 '${extraLinksFooter}' '${cfg.customDir}/templates/custom/extra_links_footer.tmpl'"
"${install} -Dm444 '${project-labels}' '${cfg.customDir}/options/label/project-labels.yaml'"
"${install} -Dm644 '${./emotes/bruh.png}' '${cfg.customDir}/public/assets/img/emoji/bruh.png'"
"${install} -Dm644 '${./emotes/huh.gif}' '${cfg.customDir}/public/assets/img/emoji/huh.png'"
"${install} -Dm644 '${./emotes/grr.png}' '${cfg.customDir}/public/assets/img/emoji/grr.png'"
"${install} -Dm644 '${./emotes/okiedokie.jpg}' '${cfg.customDir}/public/assets/img/emoji/okiedokie.png'"
"${lib.getExe pkgs.rsync} -a '${customTemplates}/' '${cfg.customDir}/templates/'"
];
};
script = let
logo-svg = fp /assets/logo_blue_regular.svg;
logo-png = fp /assets/logo_blue_regular.png;
extraLinks = pkgs.writeText "gitea-extra-links.tmpl" ''
<a class="item" href="https://git.pvv.ntnu.no/Drift/-/projects/4">Tokyo Drift Issues</a>
'';
extraLinksFooter = pkgs.writeText "gitea-extra-links-footer.tmpl" ''
<a class="item" href="https://www.pvv.ntnu.no/">PVV</a>
<a class="item" href="https://wiki.pvv.ntnu.no/">Wiki</a>
<a class="item" href="https://wiki.pvv.ntnu.no/wiki/Tjenester/Kodelager">PVV Gitea Howto</a>
'';
project-labels = (pkgs.formats.yaml { }).generate "gitea-project-labels.yaml" {
labels = lib.importJSON ./labels/projects.json;
};
customTemplates = pkgs.runCommandLocal "gitea-templates" {
nativeBuildInputs = with pkgs; [
coreutils
gnused
];
} ''
# Bigger icons
install -Dm444 '${cfg.package.src}/templates/repo/icon.tmpl' "$out/repo/icon.tmpl"
sed -i -e 's/24/60/g' "$out/repo/icon.tmpl"
'';
in ''
install -Dm444 '${logo-svg}' '${cfg.customDir}/public/assets/img/logo.svg'
install -Dm444 '${logo-png}' '${cfg.customDir}/public/assets/img/logo.png'
install -Dm444 '${./loading.apng}' '${cfg.customDir}/public/assets/img/loading.png'
install -Dm444 '${extraLinks}' '${cfg.customDir}/templates/custom/extra_links.tmpl'
install -Dm444 '${extraLinksFooter}' '${cfg.customDir}/templates/custom/extra_links_footer.tmpl'
install -Dm444 '${project-labels}' '${cfg.customDir}/options/label/project-labels.yaml'
install -Dm644 '${./emotes/bruh.png}' '${cfg.customDir}/public/assets/img/emoji/bruh.png'
install -Dm644 '${./emotes/huh.gif}' '${cfg.customDir}/public/assets/img/emoji/huh.png'
install -Dm644 '${./emotes/grr.png}' '${cfg.customDir}/public/assets/img/emoji/grr.png'
install -Dm644 '${./emotes/okiedokie.jpg}' '${cfg.customDir}/public/assets/img/emoji/okiedokie.png'
'${lib.getExe pkgs.rsync}' -a '${customTemplates}/' '${cfg.customDir}/templates/'
'';
};
}
+1 -106
View File
@@ -136,12 +136,9 @@ in {
picture = {
AVATAR_MAX_FILE_SIZE = 1024 * 1024 * 5;
# NOTE: go any bigger than this, and gitea will freeze your gif >:(
AVATAR_MAX_ORIGIN_SIZE = 1024 * 1024 * 4;
AVATAR_MAX_ORIGIN_SIZE = 1024 * 1024 * 2;
};
actions.ENABLED = true;
webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," [
"external"
];
};
dump = {
@@ -196,108 +193,6 @@ in {
};
};
environment.robots-txt."gitea" = {
virtualHost = domain;
rules = [
{
pre_comment = ''
Gitea internals
See these for more information:
- https://gitea.com/robots.txt
- https://codeberg.org/robots.txt
'';
User-agent = "*";
Disallow = [
"/api/*"
"/avatars"
"/*/*/src/commit/*"
"/*/*/commit/*"
"/*/*/*/refs/*"
"/*/*/*/star"
"/*/*/*/watch"
"/*/*/labels"
"/*/*/activity/*"
"/vendor/*"
"/swagger.*.json"
"/repo/create"
"/repo/migrate"
"/org/create"
"/*/*/fork"
"/*/*/watchers"
"/*/*/stargazers"
"/*/*/forks"
"*/.git/"
"/*.git"
"/*.atom"
"/*.rss"
];
Crawl-delay = "2";
}
{
pre_comment = "Language Spam";
Disallow = "/*?lang=";
}
{
pre_comment = ''
AI bots
Sourced from:
- https://www.vg.no/robots.txt
- https://codeberg.org/robots.txt
'';
User-agent = [
"AI2Bot"
"Ai2Bot-Dolma"
"Amazonbot"
"Applebot-Extended"
"Bytespider"
"CCBot"
"ChatGPT-User"
"Claude-Web"
"ClaudeBot"
"Crawlspace"
"Diffbot"
"FacebookBot"
"FriendlyCrawler"
"GPTBot"
"Google-Extended"
"ICC-Crawler"
"ImagesiftBot"
"Kangaroo Bot"
"Meta-ExternalAgent"
"OAI-SearchBot"
"Omgili"
"Omgilibot"
"PanguBot"
"PerplexityBot"
"PetalBot"
"Scrapy"
"SemrushBot-OCOB"
"Sidetrade indexer bot"
"Timpibot"
"VelenPublicWebCrawler"
"Webzio-Extended"
"YouBot"
"anthropic-ai"
"cohere-ai"
"cohere-training-data-crawler"
"facebookexternalhit"
"iaskspider/2.0"
"img2dataset"
"meta-externalagent"
"omgili"
"omgilibot"
];
Disallow = "/";
Crawl-delay = "2";
}
{
Sitemap = "https://${domain}/sitemap.xml";
}
];
};
networking.firewall.allowedTCPPorts = [ sshPort ];
services.rsync-pull-targets = {
+4 -6
View File
@@ -38,11 +38,11 @@ in
Type = "oneshot";
User = cfg.user;
PrivateNetwork = true;
ExecStart = [
"${lib.getExe pkgs.gnupg} --import '${config.sops.secrets."gitea/gpg-signing-key-public".path}'"
"${lib.getExe pkgs.gnupg} --import '${config.sops.secrets."gitea/gpg-signing-key-private".path}'"
];
};
script = ''
${lib.getExe pkgs.gnupg} --import ${config.sops.secrets."gitea/gpg-signing-key-public".path}
${lib.getExe pkgs.gnupg} --import ${config.sops.secrets."gitea/gpg-signing-key-private".path}
'';
};
services.gitea.settings."repository.signing" = {
@@ -50,8 +50,6 @@ in
SIGNING_NAME = "PVV Git";
SIGNING_EMAIL = "gitea@git.pvv.ntnu.no";
INITIAL_COMMIT = "always";
MERGES = lib.concatStringsSep "," [ "always" ];
CRUD_ACTIONS = lib.concatStringsSep "," [ "always" ];
WIKI = "always";
};
}
@@ -11,9 +11,9 @@ in
systemd.services.gitea-import-users = lib.mkIf cfg.enable {
enable = true;
preStart=''${pkgs.rsync}/bin/rsync -e "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=$CREDENTIALS_DIRECTORY/ssh-known-hosts -i $CREDENTIALS_DIRECTORY/sshkey" -a pvv@smtp.pvv.ntnu.no:/etc/passwd /run/gitea-import-users/passwd'';
environment.PASSWD_FILE_PATH = "/run/gitea-import-users/passwd";
serviceConfig = {
ExecStartPre = ''${pkgs.rsync}/bin/rsync -e "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=$CREDENTIALS_DIRECTORY/ssh-known-hosts -i $CREDENTIALS_DIRECTORY/sshkey" -a pvv@smtp.pvv.ntnu.no:/etc/passwd /run/gitea-import-users/passwd'';
ExecStart = pkgs.writers.writePython3 "gitea-import-users" {
flakeIgnore = [
"E501" # Line over 80 chars lol
+10 -62
View File
@@ -5,73 +5,21 @@
(fp /base)
./services/gitea-runner.nix
] ++ lib.optionals (lupineName == "lupine-5") [
./services/openvpn.nix
];
sops.defaultSopsFile = fp /secrets/lupine/lupine.yaml;
boot.binfmt.emulatedSystems = [
"aarch64-linux"
"armv7l-linux"
"i686-linux"
];
systemd.network.networks."30-enp0s31f6" = values.defaultNetworkConfig // {
matchConfig.Name = "enp0s31f6";
address = with values.hosts.${lupineName}; [ (ipv4 + "/25") (ipv6 + "/64") ];
networkConfig.LLDP = false;
};
systemd.network.wait-online = {
anyInterface = true;
};
systemd.network = if (lupineName != "lupine-5")
then {
networks."30-enp0s31f6" = (values.defaultNetworkConfig // {
matchConfig.Name = "enp0s31f6";
address = with values.hosts.${lupineName}; [ (ipv4 + "/25") (ipv6 + "/64") ];
networkConfig.LLDP = false;
});
wait-online = {
anyInterface = true;
};
}
else {
netdevs."10-br0".netdevConfig = {
Name = "br0";
Kind = "bridge";
};
netdevs."20-tap0".netdevConfig = {
Name = "tap0";
Kind = "tap";
};
networks."10-enp0s31f6" = {
matchConfig.Name = "enp0s31f6";
bridge = [ "br0" ];
};
networks."20-br0" = {
matchConfig.Name = "br0";
address = with values.hosts.${lupineName}; [
(ipv4 + "/25")
(ipv6 + "/64")
values.services.knutsen-vpn
];
networkConfig.LLDP = false;
dns = ["129.241.0.200" "129.241.0.201" "2001:700:300:1900::200" "2001:700:300:1900::201"];
domains = ["pvv.ntnu.no" "pvv.org"];
gateway = [values.hosts.gateway values.hosts.gateway6];
networkConfig.IPv6AcceptRA = "no";
DHCP = "no";
};
networks."30-tap0" = {
matchConfig.Name = "tap0";
bridge = [ "br0" ];
};
wait-online = {
anyInterface = true;
};
};
# There are no smart devices
services.smartd.enable = false;
# Don't change (even during upgrades) unless you know what you are doing.
# See https://search.nixos.org/options?show=system.stateVersion
-101
View File
@@ -1,101 +0,0 @@
{ config, pkgs, lib, values, ... }:
let
renderConfig = attrs: lib.pipe attrs [
(lib.filterAttrs (_: value: !(builtins.isNull value || value == false)))
(builtins.mapAttrs (_: value:
if builtins.isList value then builtins.concatStringsSep " " (map toString value)
else if value == true then value
else if builtins.any (f: f value) [
builtins.isString
builtins.isInt
builtins.isFloat
lib.isPath
lib.isDerivation
] then toString value
else throw "Unknown value in lupine openvpn config:\n${value}"
))
(lib.mapAttrsToList (name: value: if value == true then name else "${name} ${value}"))
(builtins.concatStringsSep "\n")
(x: x + "\n\n")
];
in
{
sops.secrets = {
"openvpn/ca/crt" = { };
"openvpn/server/crt" = { };
"openvpn/server/key" = { };
};
services.openvpn.servers."ov-tunnel" = {
config = renderConfig {
mode = "server";
# TODO: use aliases
local = "0.0.0.0";
port = 1194;
proto = "udp";
dev = "tap0";
dev-type = "tap";
script-security = 0;
ca = config.sops.secrets."openvpn/ca/crt".path;
cert = config.sops.secrets."openvpn/server/crt".path;
key = config.sops.secrets."openvpn/server/key".path;
dh = "none";
# Maintain a record of client <-> virtual IP address
# associations in this file. If OpenVPN goes down or
# is restarted, reconnecting clients can be assigned
# the same virtual IP address from the pool that was
# previously assigned.
# ifconfig-pool-persist = ./ipp.txt;
server-bridge = builtins.concatStringsSep " " [
# Gateway
"129.241.210.129"
# Netmask
"255.255.255.128"
# Pool start
values.services.knutsen-tap
# Pool end
values.services.ludvigsen-tap
];
keepalive = "10 120";
user = "nobody";
group = "nobody";
status = "/var/log/openvpn-status.log";
client-config-dir = pkgs.writeTextDir "ludvigsen" ''
# Sett IP-adr. for tap0 til ludvigsens PVV-addresse.
ifconfig-push ${values.services.ludvigsen-tap} 255.255.255.128
# Hvordan skal man faa dette til aa funke, tro?
# ifconfig-ipv6-push 2001:700:300:1900::xxx/64
# La ludvigsen bruke std. PVV-gateway til all trafikk (unntatt VPN-tunnellen).
push "redirect-gateway"
'';
persist-key = true;
persist-tun = true;
tls-version-min = "1.2";
tls-version-max = "1.2";
verb = 5;
explicit-exit-notify = 1;
};
};
networking.firewall = {
allowedTCPPorts = [ 1194 ];
allowedUDPPorts = [ 1194 ];
};
}
-1
View File
@@ -16,7 +16,6 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/224c45db-9fdc-45d4-b3ad-aaf20b3efa8a";
fsType = "ext4";
options = [ "relatime" ];
};
fileSystems."/boot" =
+27 -2
View File
@@ -12,8 +12,6 @@
./hardware-configuration.nix
./disk-config.nix
(fp /base)
./services/drumknotty.nix
];
boot.consoleLogLevel = 0;
@@ -28,6 +26,33 @@
];
};
sops.secrets = {
"dibbler/postgresql/password" = {
owner = "dibbler";
group = "dibbler";
};
};
services.dibbler = {
enable = true;
kioskMode = true;
limitScreenWidth = 80;
limitScreenHeight = 42;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "pvv_vv";
dbname = "pvv_vv";
host = "postgres.pvv.ntnu.no";
password_file = config.sops.secrets."dibbler/postgresql/password".path;
};
};
};
};
systemd.services."serial-getty@ttyUSB0" = lib.mkIf (!config.virtualisation.isVmVariant) {
enable = true;
wantedBy = [ "getty.target" ]; # to start at boot
-1
View File
@@ -31,7 +31,6 @@
type = "filesystem";
format = "ext4";
mountpoint = "/";
mountOptions = [ "relatime" ];
};
};
};
-57
View File
@@ -1,57 +0,0 @@
{ config, ... }:
{
sops.secrets = {
"dibbler/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
"worblehat/postgresql/password" = {
owner = "drumknotty";
group = "drumknotty";
};
};
services.drumknotty = {
enable = true;
kioskMode = true;
screen = {
limitWidth = 80;
limitHeight = 42;
};
dibbler = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "pvv_vv";
dbname = "pvv_vv";
host = "postgres.pvv.ntnu.no";
password_file = config.sops.secrets."dibbler/postgresql/password".path;
};
};
};
};
worblehat = {
enable = true;
settings = {
general.quit_allowed = false;
database = {
type = "postgresql";
postgresql = {
username = "worblehat";
dbname = "worblehat";
host = "postgres.pvv.ntnu.no";
password = config.sops.secrets."worblehat/postgresql/password".path;
};
};
};
};
};
services.roowho2.settings.rwhod.ignoreUsers = [ "drumknotty" ];
}
-1
View File
@@ -16,7 +16,6 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/c3aed415-0054-4ac5-8d29-75a99cc26451";
fsType = "btrfs";
options = [ "relatime" ];
};
fileSystems."/boot" =
+2 -61
View File
@@ -1,4 +1,4 @@
{ lib, pkgs, values, ... }:
{ lib, values, ... }:
let
# See microbel:/etc/exports
letters = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
@@ -6,20 +6,6 @@ in
{
systemd.targets."pvv-homedirs" = {
description = "PVV Homedir Partitions";
requires = map (l: "pvv-homedir-create-uidmapped-bindmounts@${l}.service") letters;
};
systemd.tmpfiles.settings."10-pvv-homedirs" = {
"/run/pvvhome".d = {
user = "root";
group = "root";
mode = "0755";
};
"/run/pvvhome/by-uid".d = {
user = "root";
group = "root";
mode = "0755";
};
};
systemd.mounts = map (l: {
@@ -31,7 +17,7 @@ in
type = "nfs";
what = "homepvv${l}.pvv.ntnu.no:/export/home/pvv/${l}";
where = "/run/pvvhome/${l}";
where = "/run/pvv-home-mounts/${l}";
options = lib.concatStringsSep "," [
"nfsvers=3"
@@ -68,49 +54,4 @@ in
"rw"
];
}) letters;
systemd.services."pvv-homedir-create-uidmapped-bindmounts@" = {
bindsTo = [ "run-pvvhome-%i.mount" ];
after = [ "run-pvvhome-%i.mount" ];
serviceConfig = {
Type = "oneshot";
};
path = with pkgs; [
coreutils
systemdMinimal
];
scriptArgs = "%i";
script = ''
for dir in "/run/pvvhome/$1"/*/; do
[[ -d "$dir" ]] || continue
uid="$(stat -c '%u' "$dir")"
mountpoint="/run/pvvhome/by-uid/$uid"
mkdir -p "$mountpoint"
unit_name=$(systemd-escape --path --suffix=mount "$mountpoint")
if systemctl --quiet is-active "$unit_name" ||
systemctl --quiet is-failed "$unit_name"; then
echo "Skipping existing mount unit: $unit_name"
continue
fi
systemd-mount \
--collect \
--fsck=no \
--type=none \
--options=bind \
--property=BindsTo=$(systemd-escape --path --suffix=mount "/run/pvvhome/$1") \
--property=After=$(systemd-escape --path --suffix=mount "/run/pvvhome/$1") \
"$dir" \
"$mountpoint" \
|| echo "Failed mounting for uid $uid"
done
'';
};
}
@@ -1 +0,0 @@
target
@@ -1,171 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "apache-log-processor"
version = "0.1.0"
dependencies = [
"nix",
"time",
]
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "deranged"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"powerfmt",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "nix"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "num-conv"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "time"
version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "time-macros"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
@@ -1,19 +0,0 @@
[package]
name = "apache-log-processor"
version = "0.1.0"
edition = "2024"
autobins = false
license = "MIT"
authors = [
"projects@pvv.ntnu.no",
]
[dependencies]
nix = { version = "0.31.3", features = ["event", "fs", "user"] }
time = { version = "0.3.47", features = ["formatting", "local-offset"] }
[[bin]]
name = "apache-log-processor"
bench = false
path = "src/main.rs"
@@ -1,33 +0,0 @@
{
lib
, rustPlatform
, stdenv
}:
let
cargoToml = fromTOML (builtins.readFile ./Cargo.toml);
cargoLock = ./Cargo.lock;
mainProgram = (lib.head cargoToml.bin).name;
pname = cargoToml.package.name;
in
rustPlatform.buildRustPackage {
inherit pname;
inherit (cargoToml.package) version;
src = lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.unions [
./Cargo.toml
./Cargo.lock
./src
];
};
cargoLock.lockFile = cargoLock;
doCheck = true;
meta = with lib; {
license = licenses.mit;
platforms = platforms.linux;
inherit mainProgram;
};
}
@@ -1,321 +0,0 @@
use nix::{
errno::Errno,
fcntl::{FcntlArg, OFlag, fcntl, open},
sys::{
epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollTimeout},
stat::Mode,
},
unistd::{User, getegid, geteuid, read, setegid, seteuid, write},
};
use std::{
collections::VecDeque,
os::fd::{AsFd, BorrowedFd, OwnedFd},
path::PathBuf,
process::exit,
};
use time::{OffsetDateTime, format_description};
const READ_BUFFER_SIZE: usize = 8 * 1024;
#[derive(Debug, Clone, Copy)]
enum LogMode {
Access,
Error,
}
fn main() -> Result<(), String> {
let log_mode = match std::env::args().nth(1).as_deref() {
Some("access") => LogMode::Access,
Some("error") => LogMode::Error,
Some(other) => {
return Err(format!(
"invalid log mode `{other}`; expected `access` or `error`"
));
}
None => return Err("missing log mode argument; expected `access` or `error`".to_string()),
};
let tee_file = match log_mode {
LogMode::Access => None,
LogMode::Error => Some(
open(
&PathBuf::from("/var/log/httpd/error.log"),
OFlag::O_WRONLY | OFlag::O_APPEND | OFlag::O_CREAT | OFlag::O_CLOEXEC,
Mode::S_IRUSR | Mode::S_IWUSR,
)
.map_err(|error| format!("failed to open error log for teeing: {error}"))?,
),
};
let stdin = std::io::stdin();
fcntl(stdin.as_fd(), FcntlArg::F_GETFL)
.map(OFlag::from_bits_retain)
.map(|flags| FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK))
.and_then(|flags| fcntl(stdin.as_fd(), flags))
.map_err(|error| format!("failed to make stdin nonblocking: {error}"))?;
let epoll = Epoll::new(EpollCreateFlags::EPOLL_CLOEXEC)
.map_err(|error| format!("failed to create epoll instance: {error}"))?;
epoll
.add(
stdin.as_fd(),
EpollEvent::new(
EpollFlags::EPOLLIN | EpollFlags::EPOLLERR | EpollFlags::EPOLLHUP,
0,
),
)
.map_err(|error| format!("failed to register stdin with epoll: {error}"))?;
if let Err(error) = event_loop(log_mode, epoll, stdin.as_fd(), tee_file) {
eprintln!("Error: {error}");
exit(1);
}
Ok(())
}
fn event_loop(
log_mode: LogMode,
epoll: Epoll,
stdin_fd: BorrowedFd<'_>,
mut tee_file: Option<OwnedFd>,
) -> Result<(), String> {
let mut events = [EpollEvent::empty(); 1];
let mut pending = VecDeque::new();
loop {
let ready = loop {
match epoll.wait(&mut events, EpollTimeout::NONE) {
Ok(ready) => break ready,
Err(Errno::EINTR) => continue,
Err(error) => {
return Err(format!("epoll wait failed: {error}"));
}
}
};
if ready == 0 {
continue;
}
let mut scratch = [0u8; READ_BUFFER_SIZE];
let eof = loop {
match read(stdin_fd, &mut scratch) {
Ok(0) => break true,
Ok(read_bytes) => pending.extend(scratch[..read_bytes].iter().copied()),
Err(Errno::EINTR) => continue,
Err(Errno::EAGAIN) => break false,
Err(error) => {
return Err(format!("failed to read from stdin: {error}"));
}
}
};
while let Some(newline_index) = pending.iter().position(|byte| *byte == b'\n') {
let line = pending.make_contiguous();
process_line(log_mode, &line[..=newline_index], &mut tee_file)?;
pending.drain(..=newline_index);
}
if eof {
if !pending.is_empty() {
process_line(log_mode, pending.make_contiguous(), &mut tee_file)?;
pending.clear();
}
return Ok(());
}
}
}
fn process_line(
log_mode: LogMode,
line: &[u8],
tee_file: &mut Option<OwnedFd>,
) -> Result<(), String> {
if let Some(tee_file) = tee_file.as_ref() {
write_all_fd(tee_file, line).map_err(|error| {
format!("failed to append to APACHE_LOG_PROCESSOR_TEE_FILE: {error}")
})?;
}
if let Some(user) =
parse_username_from_line(line).and_then(|name| User::from_name(name).ok().flatten())
{
let identity = EffectiveIdentity::switch_to(&user).map_err(|error| {
format!(
"failed to switch effective identity to {} (uid {}, gid {}): {error}",
user.name, user.uid, user.gid
)
})?;
let result: Result<(), String> = (|| {
let dir = user.dir.join("nobackup/weblogs");
if !dir.is_dir() {
return Err(format!(
"logs directory {} does not exist for user {}",
dir.display(),
user.name
));
}
let now = OffsetDateTime::now_local()
.unwrap_or_else(|_| OffsetDateTime::now_utc())
.format(&format_description::parse("[year]-[month]-[day]").unwrap())
.map_err(|error| {
format!("failed to format current date for log file name: {error}")
})?;
let logfile = dir.join(match log_mode {
LogMode::Access => format!("access-{now}.log"),
LogMode::Error => format!("error-{now}.log"),
});
let fd = open(
&logfile,
OFlag::O_WRONLY | OFlag::O_APPEND | OFlag::O_CREAT | OFlag::O_CLOEXEC,
Mode::S_IRUSR
| Mode::S_IWUSR
| Mode::S_IRGRP
| Mode::S_IROTH
| Mode::S_IWGRP
| Mode::S_IWOTH,
)
.map_err(|error| format!("failed to open log file for user {}: {error}", user.name))?;
write_all_fd(fd.as_fd(), line).map_err(|error| {
format!(
"failed to append to log file for user {}: {error}",
user.name
)
})?;
Ok(())
})();
if let Err(error) = result {
eprintln!("Error processing log line for user {}: {error}", user.name);
}
identity.restore().map_err(|error| {
format!(
"failed to restore original effective identity after handling {}: {error}",
user.name
)
})?;
}
Ok(())
}
fn parse_username_from_line(line: &[u8]) -> Option<&str> {
line.splitn(8, |&b| b == b' ')
.nth(6)
.and_then(|path| {
path.strip_prefix(b"/~")
.and_then(|rest| rest.split(|&b| b == b'/').next())
})
.or_else(|| {
line.windows(b"/home/pvv/".len())
.enumerate()
.find_map(|(start, window)| {
(window == b"/home/pvv/")
.then_some(start + b"/home/pvv/".len())
.and_then(|start| line.get(start..))
.filter(|rest| rest.get(1) == Some(&b'/'))
.and_then(|rest| rest.get(2..))
.and_then(|rest| rest.split(|&b| b == b'/').next())
})
})
.filter(|segment| !segment.is_empty())
.and_then(|segment| std::str::from_utf8(segment).ok())
}
fn write_all_fd<Fd: AsFd>(fd: Fd, mut buffer: &[u8]) -> nix::Result<()> {
while !buffer.is_empty() {
match write(fd.as_fd(), buffer) {
Ok(0) => return Err(Errno::EIO),
Ok(written) => buffer = &buffer[written..],
Err(Errno::EINTR) => continue,
Err(error) => return Err(error),
}
}
Ok(())
}
struct EffectiveIdentity {
saved_euid: nix::unistd::Uid,
saved_egid: nix::unistd::Gid,
restored: bool,
}
impl EffectiveIdentity {
fn switch_to(user: &User) -> nix::Result<Self> {
let guard = Self {
saved_euid: geteuid(),
saved_egid: getegid(),
restored: false,
};
setegid(user.gid)?;
if let Err(error) = seteuid(user.uid) {
let _ = setegid(guard.saved_egid);
return Err(error);
}
Ok(guard)
}
fn restore(mut self) -> nix::Result<()> {
let restore_uid = seteuid(self.saved_euid);
let restore_gid = setegid(self.saved_egid);
self.restored = true;
restore_uid?;
restore_gid?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_user_from_access_log() {
let inputs = [(
"1.2.3.4 - - [25/May/2026:10:07:24 +0200] \"GET /~oysteikt/ HTTP/2.0\" 200 3708",
"oysteikt",
)];
for (line, expected_user) in inputs {
let parsed_user = parse_username_from_line(line.as_bytes());
assert_eq!(
parsed_user,
Some(expected_user),
"Failed to parse user from line: {line}"
);
}
}
#[test]
fn test_parse_user_from_error_log() {
let inputs = [(
"[Sat May 09 20:45:21.480016 2026] [authz_core:error] [pid 3555:tid 3617] [remote 1::2:42000] AH01630: client denied by server configuration: /home/pvv/d/oysteikt/web-docs/.git",
"oysteikt",
)];
for (line, expected_user) in inputs {
let parsed_user = parse_username_from_line(line.as_bytes());
assert_eq!(
parsed_user,
Some(expected_user),
"Failed to parse user from line: {line}"
);
}
}
}
+347 -5
View File
@@ -1,10 +1,352 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.httpd;
homeLetters = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
phpOptions = lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}"){
display_errors = "Off";
display_startup_errors = "Off";
post_max_size = "40M";
upload_max_filesize = "40M";
});
# https://nixos.org/manual/nixpkgs/stable/#ssec-php-user-guide-installing-with-extensions
phpEnv = pkgs.php.buildEnv {
extensions = { all, ... }: with all; [
bz2
curl
decimal
gd
imagick
mysqli
mysqlnd
pgsql
posix
protobuf sqlite3
uuid
xml
xsl
zlib
zstd
pdo
pdo_mysql
pdo_pgsql
pdo_sqlite
];
extraConfig = phpOptions;
};
perlEnv = pkgs.perl.withPackages (ps: with ps; [
pkgs.exiftool
pkgs.ikiwiki
pkgs.irssi
pkgs.nix.libs.nix-perl-bindings
CGI
DBDPg
DBDSQLite
DBDmysql
DBI
Git
ImageMagick
JSON
TemplateToolkit
]);
# https://nixos.org/manual/nixpkgs/stable/#python.buildenv-function
pythonEnv = pkgs.python3.buildEnv.override {
extraLibs = with pkgs.python3Packages; [
legacy-cgi
matplotlib
requests
];
ignoreCollisions = true;
};
sendmailWrapper = pkgs.writeShellApplication {
name = "sendmail";
runtimeInputs = [ ];
text = ''
args=("$@")
if [[ -z "$USERDIR_USER" ]] && [[ "$USERDIR_USER" != "pvv" ]]; then
# Prepend -fusername to the argument list, so bounces go to the user
args=("-f$USERDIR_USER" "''${args[@]}")
fi
exec '${lib.getExe pkgs.system-sendmail}' "''${args[@]}"
'';
};
# https://nixos.org/manual/nixpkgs/stable/#sec-building-environment
fhsEnv = pkgs.buildEnv {
name = "userweb-env";
ignoreCollisions = true;
paths = with pkgs; [
bash
sendmailWrapper
perlEnv
pythonEnv
phpEnv
]
++ (with phpEnv.packages; [
# composer
])
++ [
# Useful packages for homepages
exiftool
gnuplot
ikiwiki-full
imagemagick
jhead
ruby
sbcl
sourceHighlight
# Missing packages from tom
# blosxom
# pyblosxom
# mediawiki (TODO: do people host their own mediawikis in userweb?)
# nanoblogger
# Version control
cvs
rcs
git
# Compression/Archival
bzip2
gnutar
gzip
lz4
unzip
xz
zip
zstd
# Other tools you might expect to find on a normal system
acl
coreutils-full
curl
diffutils
file
findutils
gawk
gnugrep
gnumake
gnupg
gnused
less
man
util-linux
vim
wget
which
xdg-utils
];
extraOutputsToInstall = [
"man"
"doc"
];
};
in
{
imports = [
./httpd.nix
./log-processor.nix
./mail.nix
./module.nix
./packages.nix
./passwd-sync.nix
];
services.httpd = {
enable = true;
adminAddr = "drift@pvv.ntnu.no";
# TODO: consider upstreaming systemd support
# TODO: mod_log_journald in v2.5
package = pkgs.apacheHttpd.overrideAttrs (prev: {
nativeBuildInputs = prev.nativeBuildInputs ++ [ pkgs.pkg-config ];
buildInputs = prev.buildInputs ++ [ pkgs.systemdLibs ];
configureFlags = prev.configureFlags ++ [ "--enable-systemd" ];
});
enablePHP = true;
phpPackage = phpEnv;
inherit phpOptions;
enablePerl = true;
# TODO: mod_log_journald in v2.5
extraModules = [
"systemd"
"userdir"
# TODO: I think the compilation steps of pkgs.apacheHttpdPackages.mod_perl might have some
# incorrect or restrictive assumptions upstream, either nixpkgs or source
# {
# name = "perl";
# path = let
# mod_perl = pkgs.apacheHttpdPackages.mod_perl.override {
# apacheHttpd = cfg.package.out;
# perl = perlEnv;
# };
# in "${mod_perl}/modules/mod_perl.so";
# }
];
extraConfig = ''
TraceEnable on
LogLevel warn rewrite:trace3
ScriptLog ${cfg.logDir}/cgi.log
'';
# virtualHosts."userweb.pvv.ntnu.no" = {
virtualHosts."temmie.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
UserDir ${lib.concatMapStringsSep " " (l: "/home/pvv/${l}/*/web-docs") homeLetters}
UserDir disabled root
AddHandler cgi-script .cgi
DirectoryIndex index.html index.html.var index.php index.php3 index.cgi index.phtml index.shtml meg.html
SetEnvIf Request_URI "^/~([^/]+)" USERDIR_USER=$1
<Directory "/home/pvv/?/*/web-docs">
Options MultiViews Indexes SymLinksIfOwnerMatch ExecCGI IncludesNoExec
AllowOverride All
Require all granted
</Directory>
<DirectoryMatch "^/home/pvv/.*/web-docs/(${lib.concatStringsSep "|" [
"\\.git"
"\\.hg"
"\\.svn"
"\\.ssh"
"\\.env"
"\\.envrc"
"\\.bzr"
"\\.venv"
"CVS"
"RCS"
".*\\.swp"
".*\\.bak"
".*~"
]})(/|$)">
AllowOverride All
Require all denied
</DirectoryMatch>
'';
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
# socket activation comes in v2.5
# systemd.sockets.httpd = {
# wantedBy = [ "sockets.target" ];
# description = "HTTPD socket";
# listenStreams = [
# "0.0.0.0:80"
# "0.0.0.0:443"
# ];
# };
systemd.services.httpd = {
after = [ "pvv-homedirs.target" ];
requires = [ "pvv-homedirs.target" ];
environment = {
PATH = lib.mkForce "/usr/bin";
};
serviceConfig = {
Type = lib.mkForce "notify";
ExecStart = lib.mkForce "${cfg.package}/bin/httpd -D FOREGROUND -f /etc/httpd/httpd.conf -k start";
ExecReload = lib.mkForce "${cfg.package}/bin/httpd -f /etc/httpd/httpd.conf -k graceful";
ExecStop = lib.mkForce "";
KillMode = "mixed";
ConfigurationDirectory = [ "httpd" ];
LogsDirectory = [ "httpd" ];
LogsDirectoryMode = "0700";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
LockPersonality = true;
PrivateDevices = true;
PrivateTmp = true;
# NOTE: this removes CAP_NET_BIND_SERVICE...
# PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SocketBindAllow = [
"tcp:80"
"tcp:443"
];
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
];
UMask = "0077";
RuntimeDirectory = [ "httpd/root-mnt" ];
RootDirectory = "/run/httpd/root-mnt";
MountAPIVFS = true;
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
# NCSD socket
"/var/run"
"/var/lib/acme"
"${fhsEnv}/bin:/bin"
"${fhsEnv}/sbin:/sbin"
"${fhsEnv}/lib:/lib"
"${fhsEnv}/share:/share"
] ++ (lib.mapCartesianProduct ({ parent, child }: "${fhsEnv}${child}:${parent}${child}") {
parent = [
"/local"
"/opt"
"/opt/local"
"/store"
"/store/gnu"
"/usr"
"/usr/local"
];
child = [
"/bin"
"/sbin"
"/lib"
"/libexec"
"/include"
"/share"
];
});
BindPaths = map (l: "/run/pvv-home-mounts/${l}:/home/pvv/${l}") homeLetters;
};
};
# TODO: create phpfpm pools with php environments that contain packages similar to those present on tom
}
-318
View File
@@ -1,318 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.httpd;
mcfg = config.services.pvv-userweb;
in
{
services.httpd = {
enable = true;
adminAddr = "drift@pvv.ntnu.no";
# TODO: consider upstreaming systemd support
# TODO: mod_log_journald in v2.5
package = pkgs.apacheHttpd.overrideAttrs (prev: {
nativeBuildInputs = prev.nativeBuildInputs ++ [ pkgs.pkg-config ];
buildInputs = prev.buildInputs ++ [ pkgs.systemdLibs ];
configureFlags = prev.configureFlags ++ [ "--enable-systemd" ];
});
enablePHP = true;
phpPackage = mcfg.php.env;
phpOptions = mcfg.php.options;
# NOTE: we include our own `mod_perl` in `extraModules` instead.
enablePerl = false;
# NOTE: we include `mod_userdir` in `extraModules` and configure this in `extraConfig` ourselves.
# enableUserDir = false;
# TODO: mod_log_journald in v2.5
extraModules = [
"systemd"
"userdir"
{
name = "perl";
path = let
mod_perl = pkgs.symlinkJoin {
name = "userweb_modperl_with_custom_perl_env";
ignoreCollisions = true;
paths = [
(pkgs.apacheHttpdPackages.mod_perl.override {
apacheHttpd = cfg.package.out;
})
mcfg.perl.env
];
};
in "${mod_perl}/modules/mod_perl.so";
}
];
logPerVirtualHost = false;
extraConfig = lib.mkIf mcfg.debugMode ''
TraceEnable on
LogLevel warn rewrite:trace3
'';
virtualHosts."temmie.pvv.ntnu.no" = {
forceSSL = true;
enableACME = true;
serverAliases = [
"www2.pvv.ntnu.no"
];
extraConfig = ''
<Directory "${pkgs.emptyDirectory}">
Require all denied
LogLevel authz_core:crit
</Directory>
CustomLog "${cfg.logDir}/access.log" combined
CustomLog "/run/httpd-log-processor-access.fifo" combined
ErrorLog "/run/httpd-log-processor-error.fifo"
ScriptLog "${cfg.logDir}/cgi.log"
UserDir ${lib.concatMapStringsSep " " (l: "/home/pvv/${l}/*/web-docs") mcfg.homeLetters}
UserDir disabled root
UserDir disabled pvv
AddHandler cgi-script .cgi
DirectoryIndex ${lib.concatStringsSep " " [
"index.htm"
"index.html"
"index.html.var"
"index.shtml"
"index.xhtml"
"index.php"
"index.php3"
"index.php4"
"index.php5"
"index.php7"
"index.php8"
"index.pht"
"index.phtml"
"index.cgi"
"index.txt"
"meg.html"
]}
SetEnvIf Request_URI "^/~([^/]+)" USERDIR_USER=$1
<Directory "/home/pvv/?/*/web-docs">
Options MultiViews Indexes SymLinksIfOwnerMatch ExecCGI IncludesNoExec
AllowOverride All
Require all granted
</Directory>
${lib.concatMapStringsSep "\n" (d: ''
<DirectoryMatch "/${d}(/|$)">
Require all denied
</DirectoryMatch>
'') [
"\\.git"
"\\.hg"
"\\.svn"
"\\.ssh"
"\\.bzr"
"\\.venv"
"CVS"
"RCS"
".*\\.bak"
".*\\.bak.*"
".*\\.bkp"
".*\\.bkp.*"
".*\\.backup"
".*\\.backup.*"
]}
${lib.concatMapStringsSep "\n" (d: ''
<Files "${d}">
Require all denied
</Files>
'') [
".env"
".env.*"
".envs"
".envs.*"
".envrc"
"*.swp"
"*~"
"*.bak"
"*.bak*"
"*.bkp"
"*.bkp*"
"*.backup"
"*.backup*"
"*.lck"
"*.lock"
"LCK..*"
]}
<FilesMatch ".+\.ph(p[34578]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
Require all denied
</FilesMatch>
<FilesMatch "\.pl$">
SetHandler modperl
PerlResponseHandler ModPerl::Registry
Options +ExecCGI
</FilesMatch>
'';
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
# socket activation comes in v2.5
# systemd.sockets.httpd = {
# wantedBy = [ "sockets.target" ];
# description = "HTTPD socket";
# listenStreams = [
# "0.0.0.0:80"
# "0.0.0.0:443"
# ];
# };
# NOTE: 54 -> 33, this is the UID/GID we used for www-data on tom in the past.
# Any files accessed by or created by httpd will do so over NFS with this
# UID/GID pair as its credentials.
# This overlaps with the hardcoded `disnix` uid in nixpkgs, but we *probably*
# won't be using that for the foreseeable future.
users.users."wwwrun".uid = lib.mkForce 33;
users.groups."wwwrun".gid = lib.mkForce 33;
systemd.targets.userweb = {
description = "PVV HTTPD UserWeb";
};
systemd.slices.system-userweb = {
description = "PVV HTTPD UserWeb";
};
systemd.services.httpd = {
after = [
"pvv-homedirs.target"
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
requires = [
"pvv-homedirs.target"
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
requiredBy = [ "userweb.target" ];
environment = {
PATH = lib.mkForce "/usr/bin";
};
serviceConfig = {
Type = lib.mkForce "notify";
ExecStart = lib.mkForce "${cfg.package}/bin/httpd -D FOREGROUND -f /etc/httpd/httpd.conf -k start";
ExecReload = lib.mkForce "${cfg.package}/bin/httpd -f /etc/httpd/httpd.conf -k graceful";
ExecStop = lib.mkForce "";
KillMode = "mixed";
Slice = "system-userweb.slice";
ConfigurationDirectory = [ "httpd" ];
LogsDirectory = [ "httpd" ];
LogsDirectoryMode = "0700";
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] ++ lib.optionals mcfg.debugMode [ "CAP_SYS_PTRACE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ] ++ lib.optionals mcfg.debugMode [ "CAP_SYS_PTRACE" ];
LockPersonality = !mcfg.debugMode;
PrivateDevices = true;
PrivateTmp = true;
# NOTE: this removes CAP_NET_BIND_SERVICE...
# PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SocketBindAllow = [
"tcp:80"
"tcp:443"
];
SystemCallArchitectures = "native";
SystemCallFilter = lib.mkIf (!mcfg.debugMode) [ "@system-service" ];
UMask = "0077";
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [ "httpd/root-mnt" ];
RootDirectory = "/run/httpd/root-mnt";
MountAPIVFS = true;
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/dev/null"
"/var/lib/acme"
"/var/run/nscd"
"${mcfg.fhsEnv}/bin:/bin"
"${mcfg.fhsEnv}/sbin:/sbin"
"${mcfg.fhsEnv}/lib:/lib"
"${mcfg.fhsEnv}/share:/share"
] ++ (lib.mapCartesianProduct ({ parent, child }: "${mcfg.fhsEnv}${child}:${parent}${child}") {
parent = [
"/local"
"/opt"
"/opt/local"
"/store"
"/store/gnu"
"/usr"
"/usr/local"
"/run/current-system/sw"
];
child = [
"/bin"
"/sbin"
"/lib"
"/libexec"
"/include"
"/share"
];
});
BindPaths = (lib.mapCartesianProduct ({ directoryFn, letter }: "/run/pvvhome/${letter}:${directoryFn letter}${letter}") {
directoryFn = [
(_: "/home/pvv/")
(l: "/amd/homepvv${l}/")
];
letter = mcfg.homeLetters;
}) ++ [
"/run/httpd-log-processor-access.fifo"
"/run/httpd-log-processor-error.fifo"
];
};
};
# TODO: create phpfpm pools with php environments that contain packages similar to those present on tom
}
@@ -1,91 +0,0 @@
Debian-exim
_cvsadmin
_ssh
adm
audio
avahi
backup
bin
cdrom
cl-builder
clamav
clock
colord
courier
crontab
daemon
debian-spamd
dialout
dip
dirmngr
disk
dovecot
fax
floppy
fuse
games
geoclue
gnats
input
irc
kmem
kvm
list
lock
lp
lpadmin
mail
man
messagebus
mlocate
munin
netdev
news
nogroup
ntp
ntpsec
oident
opendkim
operator
plocate
plugdev
polkitd
postdrop
postfix
postgres
prometheus
prometheus-exporter
proxy
rdma
root
# runit
salt
sambashare
saned
sasl
scanner
sgx
shadow
src
ssl-cert
staff
stunnel4
sudo
sys
systemd-coredump
systemd-journal
systemd-network
systemd-resolve
systemd-timesync
tape
tcpdump
tty
users
utempter
utmp
uucp
uuidd
video
voice
winbindd_priv
www-data
@@ -1,74 +0,0 @@
# System Users
Debian-exim
_apt
_rpc
avahi
backup
bin
cl-builder
clamav
colord
courier
daemon
debian-spamd
debian-spamd
dirmngr
distccd
dovecot
dovenull
driftsupport
fetchmail
games
geoclue
gitea
gnats
hplip
irc
list
lp
mail
mail2news
mailnews
man
messagebus
munin
news
nobody
noone
ntp
ntpsec
oident
opendkim
polkitd
postfix
postgres
prometheus
prometheus-exporter
proxy
root
rwhod
salt
saned
spamd
sshd
statd
stunnel4
sync
sys
systemd-coredump
systemd-network
systemd-resolve
systemd-timesync
tcpdump
uucp
uuidd
vaultwarden
www-data
# Misc
nuccc04
nuccc
kybkokos
kybkokos2
testbruker2309
testbruker2404
@@ -1,113 +0,0 @@
{ config, lib, pkgs, values, ... }:
let
mcfg = config.services.pvv-userweb;
in
{
systemd.targets.sockets.wants = [
"httpd-log-processor@access.socket"
"httpd-log-processor@error.socket"
];
systemd.sockets."httpd-log-processor@" = lib.mkIf config.services.httpd.enable {
requiredBy = [ "userweb.target" ];
socketConfig = {
ListenFIFO = "/run/httpd-log-processor-%i.fifo";
RemoveOnStop = true;
SocketUser = "wwwrun";
SocketGroup = "wwwrun";
SocketMode = "0600";
};
};
systemd.services."httpd-log-processor@" = lib.mkIf config.services.httpd.enable {
requiredBy = [ "userweb.target" ];
after = [ "httpd-passwd-sync.service" ];
requires = [ "httpd-passwd-sync.service" ];
serviceConfig = {
User = "wwwrun";
Group = "wwwrun";
Slice = "system-userweb.slice";
Restart = "on-failure";
StandardInput = "socket";
StandardOutput = "journal";
StandardError = "journal";
ExecStart = "${lib.getExe mcfg.apacheLogProcessorPackage} %i";
AmbientCapabilities = [ "CAP_SETUID" "CAP_SETGID" ];
CapabilityBoundingSet = [ "CAP_SETUID" "CAP_SETGID" ];
DeviceAllow = [ "" ];
IPAddressDeny = "any";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateIPC = true;
PrivateNetwork = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = "tmpfs";
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [ "none" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"@setuid"
"~@resources"
];
UMask = "0077";
RootDirectory = "/run/httpd-log-processor-%i/root-mnt";
MountAPIVFS = true;
RuntimeDirectoryMode = "0750";
RuntimeDirectory = [ "httpd-log-processor-%i/root-mnt" ];
BindReadOnlyPaths = [
builtins.storeDir
"/etc"
"/var/lib/httpd-passwd-sync/passwd:/etc/passwd"
"/var/lib/httpd-passwd-sync/group:/etc/group"
"${pkgs.writeText "userweb-fake-nsswitch.conf" ''
passwd: files
group: files
shadow: files
sudoers: files
hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns
networks: files
ethers: files
services: files
protocols: files
rpc: files
subuid: files
subgid: files
''}:/etc/nsswitch.conf"
] ++ lib.optionals mcfg.debugMode [
"/bin"
];
BindPaths = map (l: "/run/pvvhome/${l}:/home/pvv/${l}") mcfg.homeLetters ++ [
"/var/log/httpd"
];
};
};
}
+6 -113
View File
@@ -1,119 +1,12 @@
{ config, lib, pkgs, ... }:
{ config, lib, ... }:
{
assertions = [{
assertion = config.services.nullmailer.enable;
message = ''
Expected nullmailer to be enabled for temmie userweb.
services.postfix.enable = lib.mkForce false;
If you change the default sendmail implementation, please make sure that temmie userweb works correctly!
'';
}];
services.bro = {
services.nullmailer = {
enable = true;
instances.userweb-sendmail = {
enable = true;
client = {
settings.BRO_FILE_FLAGS = [
"-C"
];
};
server = {
settings = {
executable = let
sendmailWrapper = pkgs.writeShellApplication {
name = "sendmail";
runtimeInputs = [ ];
bashOptions = [
"errexit"
"pipefail"
];
text = ''
args=("$@")
if [[ -z "$USERDIR_USER" ]] && [[ "$USERDIR_USER" != "pvv" ]]; then
# Prepend -fusername to the argument list, so bounces go to the user
args=("-f$USERDIR_USER" "''${args[@]}")
fi
exec '${lib.getExe pkgs.system-sendmail}' -t -i "''${args[@]}"
'';
};
in lib.getExe sendmailWrapper;
allowed-env = [ "USERDIR_USER" ];
};
};
config = {
me = config.networking.fqdn;
remotes = "mail.pvv.ntnu.no smtp --port=25";
};
};
environment.systemPackages = [
(config.services.bro.instances.userweb-sendmail.client.package.overrideAttrs (prev: {
buildCommand = prev.buildCommand + ''
mv "$out/bin/sendmail" "$out/bin/bro-sendmail"
'';
}))
];
users.users.nullmailer-user = {
enable = true;
isSystemUser = true;
group = "nullmailer-user";
};
users.groups.nullmailer-user = { };
systemd.services.bro-userweb-sendmail = {
serviceConfig = {
User = "nullmailer-user";
Group = "nullmailer-user";
Slice = "system-userweb.slice";
ReadWritePaths = [
"/var/spool/nullmailer"
];
AmbientCapabilities = "";
CapabilityBoundingSet = "";
NoNewPrivileges = false;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = false;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateMounts = true;
ProcSubset = "pid";
ProtectProc = "invisible";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
];
UMask = "0077";
};
};
systemd.services.httpd.serviceConfig = {
BindPaths = [ (lib.head config.systemd.sockets.bro-userweb-sendmail.listenStreams) ];
};
}
-118
View File
@@ -1,118 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.pvv-userweb;
in
{
options.services.pvv-userweb = {
enable = lib.mkEnableOption "" // {
default = true;
};
debugMode = lib.mkEnableOption "";
apacheLogProcessorPackage = lib.mkOption {
type = lib.types.package;
default = pkgs.callPackage ./apache-log-processor { };
};
homeLetters = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "a" "b" "c" "d" "h" "i" "j" "k" "l" "m" "z" ];
readOnly = true;
};
packages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = _: [ ];
};
php.extensions = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
php.options = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = {
display_errors = "Off";
display_startup_errors = "Off";
post_max_size = "40M";
upload_max_filesize = "40M";
};
apply = attrs: lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k} = ${v}") attrs);
};
# https://nixos.org/manual/nixpkgs/stable/#ssec-php-user-guide-installing-with-extensions
php.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = pkgs.php.buildEnv {
extensions = cfg.php.extensions;
extraConfig = cfg.php.options;
};
};
perl.packages = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
perl.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = (pkgs.perl.withPackages cfg.perl.packages).overrideAttrs (prev: {
# NOTE: `pkgs.perl.propagatedBuildInputs` don't actually propagate through the
# wrapper derivation created by `withPackages`. This should compensate
# for that.
postBuild = prev.postBuild + ''
cp -r '${pkgs.perl}/nix-support' "$out"/nix-support
'';
});
};
python3.packages = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = _: [ ];
};
python3.env = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = pkgs.python3.buildEnv.override {
extraLibs = cfg.python3.packages pkgs.python3Packages;
ignoreCollisions = true;
};
};
fhsEnv = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = let
in pkgs.buildEnv {
name = "userweb-env";
ignoreCollisions = true;
paths = with pkgs; [
bash
config.services.bro.instances.userweb-sendmail.client.package
cfg.perl.env
cfg.python3.env
cfg.php.env
] ++ cfg.packages;
extraOutputsToInstall = [
"man"
"doc"
];
};
};
};
config = lib.mkIf cfg.enable {
services.pvv-userweb.packages = lib.mkIf cfg.debugMode (with pkgs; [
glibc.getent
strace
systemd
]);
};
}
-104
View File
@@ -1,104 +0,0 @@
{ pkgs, ... }:
{
services.pvv-userweb = {
packages = with pkgs; [
# Useful packages for homepages
exiftool
gnuplot
ikiwiki-full
imagemagick
jhead
ruby
sbcl
sourceHighlight
# Missing packages from tom
# blosxom
# pyblosxom
# mediawiki (TODO: do people host their own mediawikis in userweb?)
# nanoblogger
# Version control
cvs
rcs
git
# Compression/Archival
bzip2
gnutar
gzip
lz4
unzip
xz
zip
zstd
# Other tools you might expect to find on a normal system
acl
coreutils-full
curl
diffutils
file
findutils
gawk
gnugrep
gnumake
gnupg
gnused
less
man
util-linux
vim
wget
which
xdg-utils
];
php.extensions = { all, ... }: with all; [
bz2
curl
decimal
gd
imagick
mysqli
mysqlnd
pgsql
posix
protobuf sqlite3
uuid
xml
xsl
zlib
zstd
pdo
pdo_mysql
pdo_pgsql
pdo_sqlite
];
perl.packages = perlPkgs: with perlPkgs; [
pkgs.exiftool
pkgs.ikiwiki
pkgs.irssi
pkgs.nix.libs.nix-perl-bindings
CGI
DBDPg
DBDSQLite
DBDmysql
DBI
Git
ImageMagick
JSON
TemplateToolkit
];
python3.packages = pythonPkgs: with pythonPkgs; [
legacy-cgi
matplotlib
requests
];
};
}
@@ -1,147 +0,0 @@
{ 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"
];
};
};
};
}
-1
View File
@@ -13,7 +13,6 @@
fileSystems."/" =
{ device = "/dev/disk/by-uuid/4e8ecdd2-d453-4fff-b952-f06da00f3b85";
fsType = "ext4";
options = [ "relatime" ];
};
swapDevices = [ {
-198
View File
@@ -1,198 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.drumknotty;
in
{
imports = [
./dibbler.nix
./worblehat.nix
];
options.services.drumknotty = {
enable = lib.mkEnableOption "DrumknoTTY";
kioskMode = lib.mkEnableOption "" // {
description = ''
Whether to let dibbler take over the entire machine.
This will restrict the machine to a single TTY and make the program unquittable.
You can still get access to PTYs via SSH and similar, if enabled.
'';
};
screen = {
package = lib.mkPackageOption pkgs "screen" { };
sessionName = lib.mkOption {
type = lib.types.str;
default = "drumknotty";
example = "myscreensessionname";
description = ''
Sets the screen session name.
'';
};
limitHeight = lib.mkOption {
type = with lib.types; nullOr ints.unsigned;
default = null;
example = 42;
description = ''
If set, limits the height of the screen dibbler uses to the given number of lines.
'';
};
limitWidth = lib.mkOption {
type = with lib.types; nullOr ints.unsigned;
default = null;
example = 80;
description = ''
If set, limits the width of the screen dibbler uses to the given number of columns.
'';
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.enable -> lib.any (b: b) [
cfg.dibbler.enable
cfg.worblehat.enable
];
message = "DrumknoTTY must have at least one service enabled";
}
];
users = {
users.drumknotty = {
group = "drumknotty";
extraGroups = [ "lp" ];
isNormalUser = true;
# TODO: make this display the error log or error message in case that
# the screen session service is bootlooping or otherwise off.
shell =
lib.mkIf cfg.kioskMode
(pkgs.writeShellScriptBin "login-shell"
"${lib.getExe' cfg.screen.package "screen"} -x ${cfg.screen.sessionName} -p dibbler"
// {
shellPath = "/bin/login-shell";
});
};
groups.drumknotty = { };
};
boot.kernelParams = lib.mkIf cfg.kioskMode [
"console=tty1"
];
services.getty.autologinUser = lib.mkIf cfg.kioskMode "drumknotty";
systemd.services.drumknotty-screen-session = lib.mkIf cfg.kioskMode {
description = "Drumknotty Screen Session";
wantedBy = [
"default.target"
];
after =
# TODO: this could be refined
if (cfg.dibbler.createLocalDatabase || cfg.worblehat.createLocalDatabase) then
[
"postgresql.service"
"dibbler-setup-database.service"
"worblehat-setup-database.service"
]
else
[
"network.target"
];
serviceConfig = {
Type = "forking";
RemainAfterExit = false;
Restart = "always";
RestartSec = "5s";
SuccessExitStatus = 1;
User = "drumknotty";
Group = "drumknotty";
ExecStartPre =
let
screenArgs = lib.escapeShellArgs [
# Send the specified command to a running screen session
"-X"
# Session name
"-S"
"${cfg.screen.sessionName}"
"kill"
];
in
"-${lib.getExe' cfg.screen.package "screen"} ${screenArgs}";
ExecStart =
let
screenrc = let
convertToFile = lines: lib.pipe lines [
lib.concatLists
(lib.concatStringsSep "\n")
(pkgs.writeText "drumknotty-screenrc")
];
in convertToFile [
(lib.optionals (cfg.screen.limitWidth != null) [
"screen width ${toString cfg.screen.limitWidth}"
])
(lib.optionals (cfg.screen.limitHeight != null) [
"screen height ${toString cfg.screen.limitHeight}"
])
(let
dibblerArgs = lib.cli.toCommandLineShellGNU { } {
config = "/etc/dibbler/dibbler.toml";
};
in lib.optionals cfg.dibbler.enable [
"screen -t dibbler ${lib.getExe cfg.dibbler.package} ${dibblerArgs} loop"
])
(let
worblehatArgs = lib.cli.toCommandLineShellGNU { } {
config = "/etc/worblehat/config.toml";
};
in lib.optionals cfg.worblehat.enable [
"screen -t worblehat ${lib.getExe cfg.worblehat.package} ${worblehatArgs} cli"
])
[ "select 0" ]
];
screenArgs = lib.escapeShellArgs [
# -dm creates the screen in detached mode without accessing it
"-dm"
# Session name
"-S"
"${cfg.screen.sessionName}"
# Set optimal output mode instead of VT100 emulation
"-O"
# Enable login mode, updates utmp entries
"-l"
# Config file path
"-c"
"${screenrc}"
];
in
"${lib.getExe' cfg.screen.package "screen"} ${screenArgs}";
};
};
};
}
-118
View File
@@ -1,118 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
mainCfg = config.services.drumknotty;
cfg = config.services.drumknotty.dibbler;
format = pkgs.formats.toml { };
in
{
options.services.drumknotty.dibbler = {
enable = lib.mkEnableOption "";
package = lib.mkPackageOption pkgs "dibbler" { };
settings = lib.mkOption {
description = "Configuration for dibbler";
default = { };
type = lib.types.submodule {
freeformType = format.type;
};
};
createLocalDatabase = lib.mkEnableOption "" // {
description = ''
Whether to set up a local postgres database automatically.
::: {.note}
You must set up postgres manually before enabling this option.
:::
'';
};
};
config = lib.mkIf (mainCfg.enable && cfg.enable) {
assertions = [
{
assertion = cfg.createLocalDatabase -> config.services.postgresql.enable;
message = "PostgreSQL must be enabled for dibbler to create a local database";
}
];
environment.systemPackages = [ cfg.package ];
environment.etc."dibbler/dibbler.toml".source = format.generate "dibbler.toml" cfg.settings;
services.drumknotty.dibbler.settings = {
limits = {
low_credit_warning_limit = lib.mkDefault (-100);
user_recent_transaction_limit = lib.mkDefault 100;
};
printer = {
label_type = lib.mkDefault "62";
label_rotate = lib.mkDefault false;
};
database = {
type = lib.mkIf cfg.createLocalDatabase "postgresql";
postgresql = {
username = lib.mkDefault "dibbler";
dbname = lib.mkDefault "dibbler";
host = lib.mkIf cfg.createLocalDatabase "/run/postgresql";
};
};
};
services.drumknotty.dibbler.settings.general = lib.mkIf mainCfg.kioskMode {
quit_allowed = false;
stop_allowed = false;
};
services.postgresql = lib.mkIf cfg.createLocalDatabase {
authentication = ''
local ${cfg.settings.database.postgresql.dbname} ${cfg.settings.database.postgresql.username} peer map=${cfg.settings.database.postgresql.username}
'';
identMap = ''
${cfg.settings.database.postgresql.username} drumknotty ${cfg.settings.database.postgresql.username}
'';
ensureDatabases = [ cfg.settings.database.postgresql.dbname ];
ensureUsers = [{
name = cfg.settings.database.postgresql.username;
ensureDBOwnership = true;
ensureClauses.login = true;
}];
};
systemd.services.dibbler-setup-database = lib.mkIf cfg.createLocalDatabase {
description = "Dibbler database setup";
wantedBy = [ "default.target" ];
requiredBy = [ "drumknotty-screen-session.service" ];
before = [ "drumknotty-screen-session.service" ];
after = [ "postgresql.service" ];
unitConfig = {
ConditionPathExists = "!/var/lib/dibbler/.db-setup-done";
};
serviceConfig = {
Type = "oneshot";
ExecStart = "${lib.getExe cfg.package} --config /etc/dibbler/dibbler.toml create-db";
ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/dibbler/.db-setup-done";
StateDirectory = "dibbler";
User = "drumknotty";
Group = "drumknotty";
};
};
systemd.services."drumknotty-screen-session".serviceConfig.StateDirectory = [
"dibbler"
"dibbler/crashdumps"
];
};
}
-213
View File
@@ -1,213 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
mainCfg = config.services.drumknotty;
cfg = config.services.drumknotty.worblehat;
format = pkgs.formats.toml { };
in
{
options.services.drumknotty.worblehat = {
enable = lib.mkEnableOption "";
package = lib.mkPackageOption pkgs "worblehat" { };
settings = lib.mkOption {
description = "Configuration for worblehat";
default = { };
type = lib.types.submodule {
freeformType = format.type;
};
};
createLocalDatabase = lib.mkEnableOption "" // {
description = ''
Whether to set up a local postgres database automatically.
::: {.note}
You must set up postgres manually before enabling this option.
:::
'';
};
deadline-daemon = {
enable = lib.mkEnableOption "" // {
description = ''
Whether to enable the worblehat deadline-daemon service,
which periodically checks for upcoming deadlines and notifies users.
Note that this service is independent of the main worblehat service,
and must be enabled separately.
'';
};
onCalendar = lib.mkOption {
type = lib.types.str;
description = ''
How often to trigger rendering the map,
in the format of a systemd timer onCalendar configuration.
See {manpage}`systemd.timer(5)`.
'';
default = "*-*-* 10:15:00";
};
};
};
config = lib.mkMerge [
{
assertions = [
{
assertion = cfg.createLocalDatabase -> config.services.postgresql.enable;
message = "PostgreSQL must be enabled for worblehat to create a local database";
}
];
# TODO: Retrieve defaults from the example config file in the project code.
services.drumknotty.worblehat.settings = {
logging = {
debug = lib.mkDefault true;
debug_sql = lib.mkDefault false;
};
database = {
type = lib.mkDefault "sqlite";
sqlite.path = lib.mkDefault "./worblehat.sqlite";
postgresql = {
host = lib.mkDefault "localhost";
port = lib.mkDefault 5432;
username = lib.mkDefault "worblehat";
password = lib.mkDefault "/var/lib/worblehat/db-password";
database = lib.mkDefault "worblehat";
};
};
flask = {
TESTING = lib.mkDefault true;
DEBUG = lib.mkDefault true;
FLASK_ENV = lib.mkDefault "development";
SECRET_KEY = lib.mkDefault "change-me";
};
smtp = {
enabled = lib.mkDefault false;
host = lib.mkDefault "smtp.pvv.ntnu.no";
port = lib.mkDefault 587;
username = lib.mkDefault "worblehat";
password = lib.mkDefault "/var/lib/worblehat/smtp-password";
from = lib.mkDefault "worblehat@pvv.ntnu.no";
subject_prefix = lib.mkDefault "[Worblehat]";
};
deadline_daemon = {
enabled = lib.mkDefault true;
dryrun = lib.mkDefault false;
warn_days_before_borrowing_deadline = lib.mkDefault [
5
1
];
days_before_queue_position_expires = lib.mkDefault 14;
warn_days_before_expiring_queue_position_deadline = lib.mkDefault [
3
1
];
};
};
systemd.services."drumknotty-screen-session".serviceConfig.StateDirectory = [
"worblehat"
];
}
(lib.mkIf ((mainCfg.enable && cfg.enable) || cfg.deadline-daemon.enable) {
environment.systemPackages = [ cfg.package ];
environment.etc."worblehat/config.toml".source = format.generate "worblehat-config.toml" cfg.settings;
})
(lib.mkIf (mainCfg.enable && cfg.enable) {
services.drumknotty.worblehat.settings.general = lib.mkIf mainCfg.kioskMode {
quit_allowed = false;
stop_allowed = false;
};
services.drumknotty.worblehat.settings.database = lib.mkIf cfg.createLocalDatabase {
type = "postgresql";
postgresql.host = "/run/postgresql";
};
services.postgresql = lib.mkIf cfg.createLocalDatabase {
authentication = ''
local ${cfg.settings.database.postgresql.database} ${cfg.settings.database.postgresql.username} peer map=${cfg.settings.database.postgresql.username}
'';
identMap = ''
${cfg.settings.database.postgresql.username} drumknotty ${cfg.settings.database.postgresql.username}
'';
ensureDatabases = [ cfg.settings.database.postgresql.database ];
ensureUsers = [{
name = cfg.settings.database.postgresql.username;
ensureDBOwnership = true;
ensureClauses.login = true;
}];
};
systemd.services.worblehat-setup-database = lib.mkIf cfg.createLocalDatabase {
description = "Worblehat database setup";
wantedBy = [ "default.target" ];
requiredBy = [ "drumknotty-screen-session.service" ];
before = [ "drumknotty-screen-session.service" ];
after = [ "postgresql.service" ];
unitConfig = {
ConditionPathExists = "!/var/lib/worblehat/.db-setup-done";
};
serviceConfig = {
Type = "oneshot";
ExecStart = "${lib.getExe cfg.package} --config /etc/worblehat/config.toml create-db";
ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/worblehat/.db-setup-done";
StateDirectory = "worblehat";
User = "drumknotty";
Group = "drumknotty";
};
};
})
(lib.mkIf cfg.deadline-daemon.enable {
systemd.timers.worblehat-deadline-daemon = lib.mkIf cfg.deadline-daemon.enable {
description = "Worblehat Deadline Daemon";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfg.deadline-daemon.onCalendar;
Persistent = true;
};
};
systemd.services.worblehat-deadline-daemon = lib.mkIf cfg.deadline-daemon.enable {
description = "Worblehat Deadline Daemon";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
Type = "oneshot";
CPUSchedulingPolicy = "idle";
IOSchedulingClass = "idle";
ExecStart =
let
worblehatArgs = lib.cli.toCommandLineShellGNU { } {
config = "/etc/worblehat/config.toml";
};
in
"${lib.getExe cfg.package} ${worblehatArgs} deadline-daemon";
User = "drumknotty";
Group = "drumknotty";
};
};
})
];
}
+1 -3
View File
@@ -16,7 +16,7 @@ in {
};
systemd.user.services.restart-greg-ng = {
serviceConfig.ExecStart = "${lib.getExe' pkgs.systemd "systemctl"} --user restart greg-ng.service";
script = "systemctl --user restart greg-ng.service";
startAt = "*-*-* 06:30:00";
};
@@ -123,7 +123,5 @@ in {
};
};
};
services.roowho2.settings.rwhod.ignoreUsers = [ "greg" ];
}
+2 -3
View File
@@ -171,9 +171,6 @@ in
requires = [ "matrix-ooye-pre-start.service" ];
wantedBy = [ "multi-user.target" ];
startLimitIntervalSec = 5;
startLimitBurst = 5;
serviceConfig = {
ExecStart = lib.getExe config.services.matrix-ooye.package;
WorkingDirectory = "/var/lib/matrix-ooye";
@@ -185,6 +182,8 @@ in
#PrivateDevices = true;
Restart = "on-failure";
RestartSec = "5s";
StartLimitIntervalSec = "5s";
StartLimitBurst = "5";
DynamicUser = true;
};
};
-224
View File
@@ -1,224 +0,0 @@
{ config, options, lib, pkgs, utils, ... }:
let
cfg = config.services.python-http-handlers;
in
{
options.services.python-http-handlers = lib.mkOption {
default = { };
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
options = {
enable = lib.mkEnableOption "" // {
default = true;
description = "Whether to enable this python HTTP handler.";
};
name = lib.mkOption {
type = lib.types.str;
default = "phh-${name}";
defaultText = "phh-<name>";
description = ''
The name of this HTTP handler.
This will be used for the systemd service among other things.
'';
};
listenStreams = lib.mkOption {
type = with lib.types; listOf str;
default = [
"/run/phh-${name}.socket"
];
defaultText = lib.literalExpression ''
[
"/run/phh-<name>.socket"
]
'';
description = ''
For each item in this list, a `ListenStream`
option in the `[Socket]` section will be created.
'';
};
socketConfig = lib.mkOption {
type = utils.systemdUtils.unitOptions.unitOption;
default = { };
description = ''
Config for the systemd socket's `[Socket]` section.
See {manpage}`systemd.socket(5)` for details.
'';
};
serviceConfig = lib.mkOption {
type = utils.systemdUtils.unitOptions.unitOption;
default = { };
description = ''
Config for the systemd service's `[Service]` section.
See {manpage}`systemd.exec(5)` and {manpage}`systemd.service(5)` for details.
'';
};
enableDefaultHardening = lib.mkEnableOption "" // {
default = true;
description = ''
Whether to enable a set of recommended systemd hardening directives.
If this breaks the service, you can either override the offending directives
through {option}`serviceConfig`, or disable this option altogether.
'';
};
libraries = lib.mkOption {
type = with lib.types; listOf package;
default = [ ];
example = lib.literalExpression ''
with pkgs.python3Packages; [
matplotlib
numpy
pillow
]
'';
description = ''
Extra python libraries to make available to the service.
'';
};
flakeIgnore = lib.mkOption {
type = with lib.types; listOf str;
default = [
"E111" # indentation is not a multiple of four
"E201" # whitespace after (
"E202" # whitespace after )
"E203" # whitespace before :
"E211" # whitespace before (
"E251" # unexpected spaces around keyword / parameter equals
"E301" # expected 1 blank line, found 0
"E302" # expected 2 blank lines, found 0
"E303" # too many blank lines
"E305" # expected 2 blank lines after end of function or class
"E306" # expected 1 blank line before a nested definition
"E501" # max line length
"E704" # multiple statements on one line (def)
];
description = ''
A list of flake8 rules to ignore while linting the python code.
An opinionated list of bogus rules (according to module author) is provided as default.
'';
};
handler = lib.mkOption {
type = lib.types.lines;
default = ''
import json
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = {"ok": True}
data = json.dumps(body).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
'';
description = ''
Python code including the HTTP handler for the server.
You can include as many imports and functions as you'd like here, but you will need
to at least provide a `class Handler(BaseHTTPRequestHandler)` to handle incoming HTTP requests.
'';
};
};
}));
};
config = {
systemd.sockets = lib.pipe cfg [
lib.attrValues
(lib.filter (v: v.enable))
(vs: lib.genAttrs' vs (v: {
inherit (v) name;
value = {
wantedBy = [ "sockets.target" ];
inherit (v) listenStreams;
socketConfig = {
Accept = false;
} // v.socketConfig;
};
}))
];
systemd.services = lib.pipe cfg [
lib.attrValues
(lib.filter (v: v.enable))
(vs: lib.genAttrs' vs (v: {
inherit (v) name;
value = {
serviceConfig = {
Type = "simple";
DynamicUser = true;
ExecStart = let
package = pkgs.writers.writePython3Bin "${v.name}-bin" {
inherit (v) libraries flakeIgnore;
} ''
import socket
from http.server import HTTPServer, BaseHTTPRequestHandler
${v.handler}
class NoBindHTTPServer(HTTPServer):
def server_bind(): pass
def server_activate(): pass
def main():
httpd = NoBindHTTPServer(
("", 0),
Handler,
bind_and_activate=False,
)
httpd.socket = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM)
httpd.serve_forever()
if __name__ == '__main__':
main()
'';
in lib.getExe package;
} // (lib.optionalAttrs v.enableDefaultHardening {
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
}) // v.serviceConfig;
};
}))
];
};
}
+20 -25
View File
@@ -38,23 +38,18 @@ lib.mergeAttrsList [
})
(mw-ext {
name = "CodeMirror";
commit = "7ab826eff8c4097589a3199c40c507717af23234";
hash = "sha256-kMIyGW9J4OSGSetByel7hEGgxPRJmQ53it6ndpYA/Hs=";
commit = "f06dfd40a08562a841ddf11b4ae3444ef06c98c7";
hash = "sha256-5zXkBjOwFdoQezkPRJ2AcBZLZEEpGG6FawO2K3KzllI=";
})
(mw-ext {
name = "DeleteBatch";
commit = "b5920283cfe78b86a63a1037a81651c58ce764da";
hash = "sha256-LwuVX2s5Q4uc6o7hlTjFzRTwvSCwTk74gBpX0HoLDMA=";
})
(mw-ext {
name = "PdfHandler";
commit = "dc1a3ca04ac6ec7d7de7ce5355803510508a2575";
hash = "sha256-ltAQZtfTMMLRPATA7rclSNW8Yz4ctGc30CxlL3SRBWU=";
commit = "9bc75a753efefedfc88c598fb01f18a7e4b61f00";
hash = "sha256-1xA758fsvoioN9xuq0hRqZKtPXMQViVLtuRINDtowdk=";
})
(mw-ext {
name = "PluggableAuth";
commit = "4b57a23e32d72bd3f74184ff2734aa483a5b0c63";
hash = "sha256-ZGw0Wgz0Sg04YDcOzkOGywmfQ6s6Ex17QbjmUDO1D8c=";
commit = "64133683b73d8eeea8069fe7ed9cb7237fd5c212";
hash = "sha256-wqpfgVLenZp6XC510nrsrbvK1IMEPcWVYq5YuAOt5+c=";
})
(mw-ext {
name = "Popups";
@@ -63,38 +58,38 @@ lib.mergeAttrsList [
})
(mw-ext {
name = "Scribunto";
commit = "35c85c96167922adc98e62dd6573789d906dd7d7";
hash = "sha256-FEWADJW53cDOlLseM62VL66PENv/jNnwuCMo2Pb02ek=";
commit = "cbab0c740e03c8e6184fd647d95e24e0826d20cb";
hash = "sha256-vXS3+wrUBVtPsETa19pMvud9sALGt4Ao9mM5rQRbBQc=";
})
(mw-ext {
name = "SimpleSAMLphp";
kebab-name = "simple-saml-php";
commit = "70778bb02f972abbb51e6ba3e0f6545b00dcab00";
hash = "sha256-wfmFJKy+ih84qFM9DVcCQFAZBx45s7Hl0lRnseMPhGY=";
commit = "fc5ad4501434fe85198f0b1f0087d798efa91f9f";
hash = "sha256-se0krTglo1fShJXj38bPLhw65tZC5P54Ywt7oeZrLes=";
})
(mw-ext {
name = "TemplateData";
commit = "cca3b3430067f2161bf65de822f70dd38fe07bba";
hash = "sha256-OxLwiF8FlWizkpDF9GXYfjehKtrltX8ihiCE+fNJpgw=";
commit = "d37b02f6ed194138ac7193a0782bbf6efb9164f8";
hash = "sha256-NpzVBzX7qfXkIE+jh33ndooS9GE8ZF3/Jynm22in7IQ=";
})
(mw-ext {
name = "TemplateStyles";
commit = "101a159dd0190759a16551a86800144c18b6ff5c";
hash = "sha256-IGQQVAx8/76ivHq9b97ec1AlFoqbRl7uhXhwoFimsG4=";
commit = "f85614c26a0057a9f418342f89214a04c9de9988";
hash = "sha256-XZOtM3iadjE5vavsjkx7kfJNhLZlnnFt1CN+mv6XVHQ=";
})
(mw-ext {
name = "UserMerge";
commit = "6c0d105e07538c34bfde989bd26fa1945f8d1b79";
hash = "sha256-w058Ihk0I98hIG1tkVJGy1bzbv7XXyUksGexXgCN540=";
commit = "2f2432c909a36691ca0002daf6fb304d6c182beb";
hash = "sha256-ZP8Tp6u+uJxx3I39YGMmkP0sTnjAQUSaxImAJaRv+Ek=";
})
(mw-ext {
name = "VisualEditor";
commit = "8d8c6d7f179a5f799e1fa8cba207d81f58f722d2";
hash = "sha256-wbYHXi2vD521EMzUl7ttinG4YdLv/DwYvVUew7dka0g=";
commit = "1508d49d0dd71fdc1d18badd23671441b3bc327b";
hash = "sha256-VNiCVNrCAImAr1tS9T28KPPzzNsKPz5ELFRIBtng+So=";
})
(mw-ext {
name = "WikiEditor";
commit = "f53000f0499858fe74e4f5008b2f5e467d9d9382";
hash = "sha256-+HTXZEVCwMD8z6c1kCZA3k686HzNd30pJljzRvf+gMg=";
commit = "aba5e7c6701877a6b43583709751658fec606d47";
hash = "sha256-XmbQy0NXuY3oVGkkgC233kkzfBfx32HDylloGYXU/Nc=";
})
]

Some files were not shown because too many files have changed in this diff Show More