diff --git a/flake.nix b/flake.nix index f805528..f2f73ff 100644 --- a/flake.nix +++ b/flake.nix @@ -192,11 +192,37 @@ group = "postgres"; mode = "0400"; }; + postgres-baikal = { + file = ./secrets/postgres-baikal.age; + owner = "postgres"; + group = "postgres"; + mode = "0400"; + }; }; } ./hosts/sql ]; }; + nixosConfigurations."dav" = nixpkgs.lib.nixosSystem { + #system = "x86_64-linux"; + #pkgs = import nixpkgs { inherit system; }; + inherit system; + modules = [ + agenix.nixosModules.default + { environment.systemPackages = [ (agenix.packages.${system}.default) ]; } + { + age.secrets = { + radicale-htpasswd = { + file = ./secrets/radicale_htpasswd.age; + owner = "radicale"; + group = "radicale"; + mode = "0400"; + }; + }; + } + ./hosts/dav + ]; + }; }; #); } diff --git a/hosts/dav/baikal.nix b/hosts/dav/baikal.nix new file mode 100644 index 0000000..91c2a15 --- /dev/null +++ b/hosts/dav/baikal.nix @@ -0,0 +1,24 @@ +{ config, ... }: + +{ + imports = [ + ../../services/nginx.nix + ]; + + services = { + baikal = { + enable = true; + virtualHost = "dav.${config.networking.domain}"; + }; + + nginx.virtualHosts."dav.${config.networking.domain}" = { + default = true; + quic = true; + kTLS = true; + forceSSL = true; + enableACME = true; + locations."/all.ics".root = "/srv/www/calendar"; + }; + }; +} + diff --git a/hosts/dav/default.nix b/hosts/dav/default.nix new file mode 100644 index 0000000..a7e857f --- /dev/null +++ b/hosts/dav/default.nix @@ -0,0 +1,37 @@ +{ ... }: + +{ + imports = [ + ../common.nix + ../../services/openssh.nix + ../../services/prometheus-node.nix + #./radicale.nix + ./baikal.nix + ]; + + networking = { + hostName = "dav"; + firewall = { + allowedTCPPorts = [ + 80 # HTTP/1 + 443 # HTTP/2 + ]; + allowedUDPPorts = [ + 443 # HTTP/3 + ]; + }; + }; + + environment.etc."ssh/banner".text = '' + __ + /\ \ + \_\ \ __ __ __ + /'_` \ /'__`\ /\ \/\ \ + /\ \L\ \/\ \L\.\_\ \ \_/ | + \ \___,_\ \__/.\_\\ \___/ + \/__,_ /\/__/\/_/ \/__/ + ''; + services.openssh.settings.Banner = "/etc/ssh/banner"; + + system.stateVersion = "26.05"; +} diff --git a/hosts/dav/radicale.nix b/hosts/dav/radicale.nix new file mode 100644 index 0000000..47b120b --- /dev/null +++ b/hosts/dav/radicale.nix @@ -0,0 +1,96 @@ +{ config, pkgs, ... }: + +let + calendarAggregate = pkgs.writers.writePython3 "calendar-aggregate.py" { libraries = [ pkgs.python3Packages.icalendar ]; } '' + from pathlib import Path + from icalendar import Calendar + + combined = Calendar() + + for path in Path("/var/lib/radicale/collections").rglob("*.ics"): + with open(path, "rb") as f: + cal = Calendar.from_ical(f.read()) + + for component in cal.walk("VEVENT"): + combined.add_component(component) + + with open("/srv/www/calendar/all.ics", "wb") as f: + f.write(combined.to_ical()) + ''; +in +{ + imports = [ + ../../services/nginx.nix + ../../services/prometheus-nginx.nix + ]; + + systemd = { + services.calendar-aggregate = { + script = "${calendarAggregate}"; + serviceConfig.Type = "oneshot"; + }; + timers.calendar-aggregate = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "5m"; + OnUnitActiveSec = "5m"; + }; + }; + }; + + services = { + radicale = { + enable = true; + rights = { + readonly = { + user = ""; + collection = ".*"; + permissions = "r"; + }; + principal = { + user = ".*"; + collection = "{user}"; + permissions = "rw"; + }; + collections = { + user = ".*"; + collection = "{user}/.*"; + permissions = "rw"; + }; + }; + settings = { + server = { + hosts = [ "[::1]:5232" ]; + validate_user_value = "strict"; + validate_path_value = "strict"; + }; + auth = { + type = "htpasswd"; + htpasswd_filename = config.age.secrets.radicale-htpasswd.path; + htpasswd_encryption = "bcrypt"; + }; + storage.filesystem_folder = "/var/lib/radicale/collections"; + headers."Access-Control-Allow-Origin" = "*"; + }; + }; + + nginx.virtualHosts."dav.${config.networking.domain}" = { + default = true; + quic = true; + kTLS = true; + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://[::1]:5232"; + recommendedProxySettings = true; + extraConfig = '' + proxy_pass_header Authorization; + ''; + }; + "/all.ics".root = "/srv/www/calendar"; + }; + }; + }; +} + diff --git a/hosts/sql/postgres.nix b/hosts/sql/postgres.nix index cd1fa90..fb46209 100644 --- a/hosts/sql/postgres.nix +++ b/hosts/sql/postgres.nix @@ -14,6 +14,7 @@ let (mkEntry "hedgedoc" 26) # md.berlin.ccc.de (mkEntry "grafana" 14) # monitoring.berlin.ccc.de (mkEntry "forgejo" 16) # git.berlin.ccc.de + (mkEntry "baikal" 24) # dav.berlin.ccc.de ]; mkEntry = name: octet: { user = { diff --git a/secrets/postgres-baikal.age b/secrets/postgres-baikal.age new file mode 100644 index 0000000..8624f22 Binary files /dev/null and b/secrets/postgres-baikal.age differ diff --git a/secrets/radicale_htpasswd.age b/secrets/radicale_htpasswd.age new file mode 100644 index 0000000..64ac55d Binary files /dev/null and b/secrets/radicale_htpasswd.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 2e2d9ee..4013e03 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -22,6 +22,7 @@ let _sql = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPcSXjDSyVVVdJbpheOhT0fIuOGFk+jsHhjrAVnBNLQV root@sql"; _www = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4TJCMuJZn03soKuxxv6ywFKiXfhLf9Ab03fbMqNaBJ root@www"; _monitoring = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINmRWdAUur0lb08NiB6ZWLrGmCeELRV30ElxRLfVJGPB root@monitoring"; + _dav = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICArHbX8OlNOv8HCWyyFvyi60d6MRFYe+apK0iGJ7yIM root@dav"; in { "matrix_admin_password.age".publicKeys = xengi; @@ -58,5 +59,10 @@ in ++ shokinn ++ [ _sql ]; "postgres-extkuma.age".publicKeys = xengi ++ [ _sql ]; + "postgres-baikal.age".publicKeys = xengi ++ [ + _sql + _dav + ]; "www-staging-htpasswd.age".publicKeys = xengi ++ [ _www ]; + "radicale_htpasswd.age".publicKeys = xengi ++ [ _dav ]; }