Add port attrset

This commit is contained in:
Jakob Lechner 2023-11-22 14:49:57 +00:00
parent e7f9b90db3
commit f0762b17c6
No known key found for this signature in database
GPG key ID: 996082EFB5906C10
26 changed files with 233 additions and 48 deletions

33
custom-utils/default.nix Normal file
View file

@ -0,0 +1,33 @@
{ lib, ... }:
let
filterPort = pm: port: (
lib.attrsets.catAttrs port (
lib.attrsets.attrValues (
lib.attrsets.filterAttrs (n: v: v ? "${port}") pm
)
)
);
onlyUniqueItemsInList = (x: lib.lists.length x == lib.lists.length (lib.lists.unique x));
protocols = (x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x))));
mkRange = (x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1));
validateList = allowed: builtins.all (x: builtins.elem x allowed);
in
{
validatePortAttrset = portmap:
if ! onlyUniqueItemsInList (lib.flatten (map
(x:
if lib.isInt x then x
else if lib.isList x then x
else if lib.isAttrs x then
(
if ! validateList [ "range" ] (builtins.attrNames x) then builtins.abort "found invalid attribute name"
else if x ? "range" then if lib.lists.length x.range == 2 then mkRange x.range else builtins.abort "range needs a list with exactly two items"
else builtins.abort "found invalid attrset"
)
else builtins.abort "found invalid entry in portmap"
)
(filterPort portmap "udp"))) then builtins.abort "Found duplicate ports."
else if ! validateList [ "tcp" "udp" ] (protocols portmap) then builtins.abort "Found invalid protocol."
else portmap;
}

33
custom-utils/ports.nix Normal file
View file

@ -0,0 +1,33 @@
{ lib, ... }:
let
filterPort = pm: port: (
lib.attrsets.catAttrs port (
lib.attrsets.attrValues (
lib.attrsets.filterAttrs (n: v: v ? "${port}") pm
)
)
);
onlyUniqueItemsInList = (x: lib.lists.length x == lib.lists.length (lib.lists.unique x));
protocols = (x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x))));
mkRange = (x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1));
validateList = allowed: builtins.all (x: builtins.elem x allowed);
in
{
validatePortAttrset = portmap:
if ! onlyUniqueItemsInList (lib.flatten (map
(x:
if lib.isInt x then x
else if lib.isList x then x
else if lib.isAttrs x then
(
if ! validateList [ "range" ] (builtins.attrNames x) then builtins.abort "found invalid attribute name"
else if x ? "range" then if lib.lists.length x.range == 2 then mkRange x.range else builtins.abort "range needs a list with exactly two items"
else builtins.abort "found invalid attrset"
)
else builtins.abort "found invalid entry in portmap"
)
(filterPort portmap "udp"))) then builtins.abort "Found duplicate ports."
else if ! validateList [ "tcp" "udp" ] (protocols portmap) then builtins.abort "Found invalid protocol."
else portmap;
}

View file

@ -151,7 +151,10 @@
./modules
{
_module.args.inputs = inputs;
_module.args = {
inputs = inputs;
custom-utils = import ./custom-utils { lib = nixpkgs.lib; };
};
}
# deployment settings

View file

@ -0,0 +1,7 @@
{ lib, custom-utils, ... }:
custom-utils.validatePortAttrset {
asterisk-rtp = { udp.range = [ 10000 10200 ]; };
unifi.tcp = 8443;
doorbell-audiosocket.tcp = 9092;
}

View file

@ -1,13 +1,15 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../../ports.nix args;
secretConfigFiles = [
"ari"
"pjsip"
"voicemail"
];
rtp = {
start = 10000;
end = 10200;
start = builtins.elemAt ports.asterisk-rtp.udp.range 0;
end = builtins.elemAt ports.asterisk-rtp.udp.range 1;
};
in
{

View file

@ -1,4 +1,8 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
sops.secrets.myintercom-doorbell-password = {
sopsFile = ../secrets.yaml;
@ -11,7 +15,7 @@
passwordFile = config.sops.secrets.myintercom-doorbell-password.path;
audiosocket = {
address = "127.0.0.1";
port = 9092;
port = ports.doorbell-audiosocket.tcp;
uuid = "4960ab41-dbef-4773-a25e-90536d97345e";
};
callerId = "Sprechanlage";

View file

@ -1,9 +1,13 @@
{ pkgs, ... }:
args@{ pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
services.unifi = {
enable = true;
openFirewall = true;
unifiPackage = pkgs.unifi;
};
networking.firewall.allowedTCPPorts = [ 8443 ];
networking.firewall.allowedTCPPorts = [ ports.unifi.tcp ];
}

16
hosts/iron/ports.nix Normal file
View file

@ -0,0 +1,16 @@
{ lib, custom-utils, ... }:
custom-utils.validatePortAttrset {
jellyfin.tcp = 8096;
matrix-synapse.tcp = 8008;
navidrome.tcp = 4533;
nginx-http.tcp = 80;
nginx-https.tcp = 443;
postfix-relay.tcp = 25;
postfix-submission.tcp = [ 465 587 ];
qbittorrent-torrent.tcp = 59832;
qbittorrent-webui.tcp = 8099;
radicale.tcp = 5232;
unifi.tcp = 8443;
wireguard-public-ip-tunnel.udp = 51000;
}

View file

@ -1,4 +1,7 @@
{ lib, pkgs, ... }:
args@{ lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
services.jellyfin = {
enable = true;
@ -57,7 +60,7 @@
# add_header X-XSS-Protection "1; mode=block";
# add_header X-Content-Type-Options "nosniff";
location / {
proxy_pass http://127.0.0.1:8096;
proxy_pass http://127.0.0.1:${toString ports.jellyfin.tcp};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -67,7 +70,7 @@
proxy_buffering off;
}
location = /web/ {
proxy_pass http://127.0.0.1:8096/web/index.html;
proxy_pass http://127.0.0.1:${toString ports.jellyfin.tcp}/web/index.html;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -76,7 +79,7 @@
proxy_set_header X-Forwarded-Host $http_host;
}
location /socket {
proxy_pass http://127.0.0.1:8096;
proxy_pass http://127.0.0.1:${toString ports.jellyfin.tcp};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

View file

@ -1,4 +1,8 @@
{ config, pkgs, ... }:
args@{ config, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
sops.secrets.hetzner-api-key = {
sopsFile = ../secrets.yaml;
@ -12,6 +16,7 @@
mailserver = {
enable = true;
fqdn = "hha.jalr.de";
relayPort = ports.postfix-relay.tcp;
domains = [
{
domain = "jalr.de";

View file

@ -1,9 +1,11 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
cfg = config.services.matrix-synapse.settings;
fqdn = "matrix.jalr.de";
domain = "jalr.de";
turnHost = "turn.jalr.de";
ports = import ../../ports.nix args;
in
{
sops.secrets = {
@ -23,7 +25,7 @@ in
database.name = "sqlite3";
listeners = lib.singleton {
port = 8008;
port = ports.matrix-synapse.tcp;
bind_addresses = [ "127.0.0.1" "::1" ];
type = "http";
tls = false;

View file

@ -1,10 +1,11 @@
{ config, lib, pkgs, utils, ... }:
args@{ config, lib, pkgs, utils, custom-utils, ... }:
let
port = 4533;
ports = import ../ports.nix args;
settings = {
# https://www.navidrome.org/docs/usage/configuration-options/#available-options
Address = "127.0.0.1";
Port = port;
Port = ports.navidrome.tcp;
DevActivityPanel = false;
};
passwordEncryptionKeyFile = config.sops.secrets.navidrome-password-encryption-key.path;
@ -38,7 +39,7 @@ in
extraConfig = ''
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
proxy_pass http://127.0.0.1:${toString port};
proxy_pass http://127.0.0.1:${toString ports.navidrome.tcp};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View file

@ -1,7 +1,13 @@
{ pkgs, ... }:
args@{ pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
services.nginx = {
enable = true;
defaultHTTPListenPort = ports.nginx-http.tcp;
defaultSSLListenPort = ports.nginx-https.tcp;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;

View file

@ -1,7 +1,8 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
listenPort = 51000;
ports = import ../ports.nix args;
listenPort = ports.wireguard-public-ip-tunnel.udp;
remoteHost = "magnesium.jalr.de";
remotePort = 51000;
publicKey = "ABZCQfzlHJ1/iNbWFf6jVvdqSmqjxm3w5bpa0SYclBU=";

View file

@ -1,4 +1,8 @@
{ config, ... }:
args@{ config, lib, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
sops.secrets.radicale-htpasswd = {
owner = "nginx";
@ -11,7 +15,7 @@
forceSSL = true;
basicAuthFile = config.sops.secrets.radicale-htpasswd.path;
locations."/radicale/" = {
proxyPass = "http://localhost:5232/";
proxyPass = "http://127.0.0.1:${toString ports.radicale.tcp}/";
recommendedProxySettings = true;
#basicAuthFile = "";
extraConfig = ''
@ -28,7 +32,7 @@
enable = true;
settings = {
server = {
hosts = "127.0.0.1:5232,[::1]:5232";
hosts = "127.0.0.1:${toString ports.radicale.tcp},[::1]:${toString ports.radicale.tcp}";
ssl = false;
};
encoding = {

View file

@ -1,10 +1,16 @@
args@{ config, lib, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
jalr.qbittorrent = {
enable = true;
downloadDir = "/sturzbach";
fqdn = "sturzbach.jalr.de";
webuiPort = ports.qbittorrent-webui.tcp;
};
networking.firewall = {
allowedTCPPorts = [ 59832 ];
allowedTCPPorts = [ ports.qbittorrent-torrent.tcp ];
};
}

View file

@ -1,9 +1,13 @@
{ pkgs, ... }:
args@{ pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
services.unifi = {
enable = true;
openFirewall = true;
unifiPackage = pkgs.unifi;
};
networking.firewall.allowedTCPPorts = [ 8443 ];
networking.firewall.allowedTCPPorts = [ ports.unifi.tcp ];
}

12
hosts/magnesium/ports.nix Normal file
View file

@ -0,0 +1,12 @@
{ lib, custom-utils, ... }:
custom-utils.validatePortAttrset {
coturn-cli.tcp = 5766;
coturn-plain = { tcp = [ 3478 3479 ]; udp = [ 3478 3479 ]; };
coturn-relay.udp.range = [ 49160 49200 ];
coturn-tls = { tcp = [ 5349 5350 ]; udp = [ 5349 5350 ]; };
mosquitto.tcp = 1883;
nginx-http.tcp = 80;
nginx-https.tcp = 443;
wireguard-public-ip-tunnel.udp = 51000;
}

View file

@ -1,7 +1,8 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.coturn;
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
cfg = config.services.coturn;
fqdn = "turn.jalr.de";
in
{
@ -10,7 +11,21 @@ in
sopsFile = ../secrets.yaml;
};
services.coturn = {
services.coturn = (
if ports.coturn-plain.tcp != ports.coturn-plain.udp then builtins.abort "coturn: plain TCP and UDP ports must match."
else if ports.coturn-tls.tcp != ports.coturn-tls.udp then builtins.abort "coturn: TLS TCP and UDP ports must match."
else if lib.lists.length ports.coturn-plain.tcp != 2 then builtins.abort "coturn: exactly two plain ports must be given."
else if lib.lists.length ports.coturn-tls.tcp != 2 then builtins.abort "coturn: exactly two TLS ports must be given."
else {
listening-port = builtins.elemAt ports.coturn-plain.tcp 0;
alt-listening-port = builtins.elemAt ports.coturn-plain.tcp 1;
tls-listening-port = builtins.elemAt ports.coturn-tls.tcp 0;
alt-tls-listening-port = builtins.elemAt ports.coturn-tls.tcp 1;
cli-port = ports.coturn-cli.tcp;
min-port = builtins.elemAt ports.coturn-relay.udp.range 0;
max-port = builtins.elemAt ports.coturn-relay.udp.range 1;
}
) // {
enable = true;
# config adapted from synapses turn howto:
@ -25,9 +40,6 @@ in
cert = "/run/turnserver/fullchain.pem";
pkey = "/run/turnserver/key.pem";
min-port = 49160;
max-port = 49200;
no-cli = true;
extraConfig = ''
@ -87,12 +99,12 @@ in
};
networking.firewall = {
allowedTCPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port ];
allowedUDPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port ];
allowedTCPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port alt-tls-listening-port ];
allowedUDPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port alt-tls-listening-port ];
allowedUDPPortRanges = lib.singleton {
from = cfg.min-port;
to = cfg.max-port;
from = builtins.elemAt ports.coturn-relay.udp.range 0;
to = builtins.elemAt ports.coturn-relay.udp.range 1;
};
};
}

View file

@ -1,5 +1,7 @@
{ config, lib, pkgs, ... }:
let port = 1883;
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
services.mosquitto = {
@ -7,12 +9,12 @@ in
persistence = true;
listeners = [
{
port = port;
port = ports.mosquitto.tcp;
settings = {
allow_anonymous = true;
};
}
];
};
networking.firewall.allowedTCPPorts = [ port ];
networking.firewall.allowedTCPPorts = [ ports.mosquitto.tcp ];
}

View file

@ -1,7 +1,8 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
listenPort = 51000;
ports = import ../ports.nix args;
listenPort = ports.wireguard-public-ip-tunnel.udp;
publicKey = "GCmQs7upvDYFueEfqD2yJkkOZg3K7YaGluWWzdjsyTo=";
in
{

View file

@ -1,12 +1,16 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
domain = "jalr.de";
matrixDomain = "matrix.jalr.de";
in
{
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.allowedTCPPorts = [ ports.nginx-http.tcp ports.nginx-https.tcp ];
services.nginx = {
enable = true;
defaultHTTPListenPort = ports.nginx-http.tcp;
defaultSSLListenPort = ports.nginx-https.tcp;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;

View file

@ -0,0 +1,8 @@
{ lib, custom-utils, ... }:
custom-utils.validatePortAttrset {
nginx-http.tcp = 80;
nginx-https.tcp = 443;
ports.postfix-relay.tcp = 25;
ports.postfix-submission.tcp = [ 465 587 ];
}

View file

@ -1,4 +1,8 @@
{ config, lib, pkgs, ... }:
args@{ config, lib, pkgs, custom-utils, ... }:
let
ports = import ../ports.nix args;
in
{
nixpkgs.config.permittedInsecurePackages = [
"python3.10-requests-2.28.2"
@ -36,6 +40,7 @@
jalr.mailserver = {
enable = true;
fqdn = "tickets.weinturm.jalr.de";
relayPort = ports.postfix-relay.tcp;
domains = [
{
domain = "tickets.weinturm-open-air.de";

View file

@ -5,6 +5,11 @@ in
{
options.jalr.mailserver = with lib; with lib.types; {
enable = mkEnableOption "simple mail server";
relayPort = mkOption {
description = "SMTP port for relay mail relay.";
type = port;
default = 25;
};
fqdn = mkOption {
type = str;
description = ''

View file

@ -39,6 +39,8 @@ lib.mkIf cfg.enable {
services.postfix = {
enable = true;
relayPort = cfg.relayPort;
enableSubmission = true; # plain/STARTTLS (latter is forced in submissionOptions)
enableSubmissions = true; # submission with implicit TLS (TCP/465)