diff --git a/esphome/.gitignore b/esphome/.gitignore new file mode 100644 index 0000000..d8b4157 --- /dev/null +++ b/esphome/.gitignore @@ -0,0 +1,5 @@ +# Gitignore settings for ESPHome +# This is an example and may include too much for your use-case. +# You can modify this file to suit your needs. +/.esphome/ +/secrets.yaml diff --git a/esphome/door.yaml b/esphome/door.yaml new file mode 100644 index 0000000..28b348f --- /dev/null +++ b/esphome/door.yaml @@ -0,0 +1,56 @@ +esphome: + name: "door" + friendly_name: "Door" + platform: ESP32 + board: esp-wrover-kit + +api: + encryption: + key: !secret apikey_door + +ota: + - platform: esphome + password: !secret otapass_door + +ethernet: + type: LAN8720 + mdc_pin: GPIO23 + mdio_pin: GPIO18 + clk_mode: GPIO0_IN + phy_addr: 1 + power_pin: GPIO16 + +logger: + +output: + - platform: gpio + pin: GPIO2 + id: output_relay + +button: + - platform: template + name: "door opener" + id: btn_door_opener + icon: mdi:lock-open + on_press: + - output.turn_on: output_relay + - delay: 2s + - output.turn_off: output_relay + +time: + - platform: sntp + id: sntp_time + timezone: Europe/Berlin + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + +wireguard: + address: 10.20.16.2 + private_key: !secret wireguard_key_door + peer_endpoint: jalr-bw.duckdns.org + peer_public_key: Ew25M4+OxfBGfW3g98m2chq+TIgWhxpVulrsuFmwOic= + netmask: 255.255.255.252 + peer_port: 51001 + peer_persistent_keepalive: 120s diff --git a/esphome/secrets.yaml.gpg b/esphome/secrets.yaml.gpg new file mode 100644 index 0000000..1c22600 --- /dev/null +++ b/esphome/secrets.yaml.gpg @@ -0,0 +1,2 @@ +^ci5V@#kf18^dCjMZДeb0J>PpP*)͡OD%D20 H2 vzF?yL3!KӊE,|%tc4pZ#6ԠkoMx|eV_9S}7ҦןBԃ]stvax>pj%ZY^_pV[Mh#b=ݠ3~:{ +oLOՕMtC<arZ&u, =zAc>#lZOM@i̠)u; \ No newline at end of file diff --git a/flake.lock b/flake.lock index 8d98ae2..571f57c 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1727196810, - "narHash": "sha256-xQzgXRlczZoFfrUdA4nD5qojCQVqpiIk82aYINQZd+U=", + "lastModified": 1745369821, + "narHash": "sha256-mi6cAjuBztm9gFfpiVo6mAn81cCID6nmDXh5Kmyjwyc=", "owner": "nix-community", "repo": "disko", - "rev": "6d42596a35d34918a905e8539a44d3fc91f42b5b", + "rev": "c5140c6079ff690e85eac0b86e254de16a79a4b7", "type": "github" }, "original": { @@ -41,11 +41,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -125,16 +125,15 @@ "flake-compat": "flake-compat", "gitignore": "gitignore", "nixpkgs": [ - "nixpkgs-unstable" - ], - "nixpkgs-stable": "nixpkgs-stable" + "nixpkgs" + ] }, "locked": { - "lastModified": 1726745158, - "narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=", + "lastModified": 1742649964, + "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74", + "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", "type": "github" }, "original": { @@ -146,11 +145,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1727040444, - "narHash": "sha256-19FNN5QT9Z11ZUMfftRplyNN+2PgcHKb3oq8KMW/hDA=", + "lastModified": 1745392233, + "narHash": "sha256-xmqG4MZArM1JNxPJ33s0MtuBzgnaCO9laARoU3AfP8E=", "owner": "nixos", "repo": "nixos-hardware", - "rev": "d0cb432a9d28218df11cbd77d984a2a46caeb5ac", + "rev": "8bf8a2a0822365bd8f44fd1a19d7ed0a1d629d64", "type": "github" }, "original": { @@ -162,64 +161,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1726969270, - "narHash": "sha256-8fnFlXBgM/uSvBlLWjZ0Z0sOdRBesyNdH0+esxqizGc=", + "lastModified": 1745279238, + "narHash": "sha256-AQ7M9wTa/Pa/kK5pcGTgX/DGqMHyzsyINfN7ktsI7Fo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "23cbb250f3bf4f516a2d0bf03c51a30900848075", + "rev": "9684b53175fc6c09581e94cc85f05ab77464c7e3", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1720386169, - "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_2": { - "locked": { - "lastModified": 1725762081, - "narHash": "sha256-vNv+aJUW5/YurRy1ocfvs4q/48yVESwlC/yHzjkZSP8=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "dc454045f5b5d814e5862a6d057e7bb5c29edc05", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "release-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-unstable": { - "locked": { - "lastModified": 1726937504, - "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "9357f4f23713673f310988025d9dc261c20e70c6", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } @@ -260,7 +211,6 @@ "nix-pre-commit-hooks": "nix-pre-commit-hooks", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", - "nixpkgs-unstable": "nixpkgs-unstable", "sbruder-overlay": "sbruder-overlay", "sops-nix": "sops-nix" } @@ -279,11 +229,11 @@ "poetry2nix": "poetry2nix" }, "locked": { - "lastModified": 1719952130, - "narHash": "sha256-j38XlExNwK4ycmoNEdH/dHUd1QGdNvD3gx/UuLY+04Q=", + "lastModified": 1743090264, + "narHash": "sha256-0eKQMldOcNBwkzf09zJWf8io3Kd3PjGQSnhpOueWEdk=", "owner": "sbruder", "repo": "nixpkgs-overlay", - "rev": "3487b8ce24d40cc898f3dba0a9af5e028e1d5844", + "rev": "f107df0aba9e3d582d1c01b40392416e47fb28dd", "type": "github" }, "original": { @@ -296,15 +246,14 @@ "inputs": { "nixpkgs": [ "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable_2" + ] }, "locked": { - "lastModified": 1726524647, - "narHash": "sha256-qis6BtOOBBEAfUl7FMHqqTwRLB61OL5OFzIsOmRz2J4=", + "lastModified": 1745310711, + "narHash": "sha256-ePyTpKEJTgX0gvgNQWd7tQYQ3glIkbqcW778RpHlqgA=", "owner": "Mic92", "repo": "sops-nix", - "rev": "e2d404a7ea599a013189aa42947f66cede0645c8", + "rev": "5e3e92b16d6fdf9923425a8d4df7496b2434f39c", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a3f323d..d7e8011 100644 --- a/flake.nix +++ b/flake.nix @@ -1,31 +1,40 @@ { inputs = { - disko.inputs.nixpkgs.follows = "nixpkgs"; - disko.url = "github:nix-community/disko"; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; flake-utils.url = "github:numtide/flake-utils"; - nix-pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix/master"; - nix-pre-commit-hooks.inputs.flake-utils.follows = "flake-utils"; - nix-pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs-unstable"; + nix-pre-commit-hooks = { + url = "github:cachix/pre-commit-hooks.nix/master"; + inputs.nixpkgs.follows = "nixpkgs"; + }; - nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; - - nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; nixos-hardware.url = "github:nixos/nixos-hardware/master"; - krops.url = "github:Mic92/krops"; - krops.inputs.flake-utils.follows = "flake-utils"; - krops.inputs.nixpkgs.follows = "nixpkgs"; + krops = { + url = "github:Mic92/krops"; + inputs.flake-utils.follows = "flake-utils"; + inputs.nixpkgs.follows = "nixpkgs"; + }; - sops-nix.url = "github:Mic92/sops-nix"; - sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; - sbruder-overlay.url = "github:sbruder/nixpkgs-overlay"; - sbruder-overlay.inputs.flake-utils.follows = "flake-utils"; - sbruder-overlay.inputs.nix-pre-commit-hooks.follows = "nix-pre-commit-hooks"; - sbruder-overlay.inputs.nixpkgs.follows = "nixpkgs"; + sbruder-overlay = { + url = "github:sbruder/nixpkgs-overlay"; + inputs = { + flake-utils.follows = "flake-utils"; + nix-pre-commit-hooks.follows = "nix-pre-commit-hooks"; + nixpkgs.follows = "nixpkgs"; + }; + }; }; outputs = @@ -50,8 +59,13 @@ src = ./.; hooks = { black.enable = true; + deadnix.enable = true; nixpkgs-fmt.enable = true; shellcheck.enable = true; + statix = { + enable = true; + settings.ignore = [ ".direnv" ]; + }; }; }; }; @@ -59,13 +73,13 @@ devShells.default = pkgs.mkShell { name = "fablab-nixos-config"; - buildInputs = (with pkgs; [ + buildInputs = with pkgs; [ black nixpkgs-fmt shellcheck sops ssh-to-pgp - ]); + ]; shellHook = '' find ${./keys} -type f -print0 | xargs -0 ${pkgs.gnupg}/bin/gpg --quiet --import @@ -73,7 +87,7 @@ }; apps = lib.mapAttrs - (name: program: { type = "app"; program = toString program; }) + (_name: program: { type = "app"; program = toString program; }) (flake-utils.lib.flattenTree { deploy = lib.recurseIntoAttrs (lib.mapAttrs (hostname: machine: @@ -107,7 +121,7 @@ }); packages = lib.filterAttrs - (n: v: lib.elem system v.meta.platforms) + (_n: v: lib.elem system v.meta.platforms) (flake-utils.lib.flattenTree { inherit (pkgs) fablab; diff --git a/machines/default.nix b/machines/default.nix index 6fd7ae9..d178468 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -1,4 +1,4 @@ -{ ... }@inputs: +inputs: let hardware = inputs.nixos-hardware.nixosModules; in diff --git a/machines/party/configuration.nix b/machines/party/configuration.nix index d28760c..050ee59 100644 --- a/machines/party/configuration.nix +++ b/machines/party/configuration.nix @@ -9,13 +9,15 @@ nixpkgs.config = { allowAliases = false; }; console.keyMap = "de"; - services.xserver.layout = "de"; - services.xserver.enable = true; - services.xserver.desktopManager.gnome.enable = true; - services.xserver.displayManager.gdm = { + services.xserver = { enable = true; - autoSuspend = false; + layout = "de"; + desktopManager.gnome.enable = true; + displayManager.gdm = { + enable = true; + autoSuspend = false; + }; }; security.sudo.wheelNeedsPassword = false; diff --git a/machines/party/hardware-configuration.nix b/machines/party/hardware-configuration.nix index a07aa08..b19150a 100644 --- a/machines/party/hardware-configuration.nix +++ b/machines/party/hardware-configuration.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, modulesPath, ... }: +{ modulesPath, ... }: { imports = [ diff --git a/machines/party/services/colorchord.nix b/machines/party/services/colorchord.nix index 95c87fa..7a3c865 100644 --- a/machines/party/services/colorchord.nix +++ b/machines/party/services/colorchord.nix @@ -1,4 +1,4 @@ -{ inputs, lib, pkgs, ... }: +{ lib, pkgs, ... }: let ledDevices = { kanister = { diff --git a/machines/raven/configuration.nix b/machines/raven/configuration.nix index d16de7c..7cf07e8 100644 --- a/machines/raven/configuration.nix +++ b/machines/raven/configuration.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, ... }: { imports = [ @@ -7,11 +7,11 @@ ./services ]; - networking.hostName = "raven"; time.timeZone = "Etc/UTC"; networking = { + hostName = "raven"; useDHCP = false; vlans = { labprod = { @@ -51,6 +51,7 @@ "voip" ]; }; + firewall.allowedTCPPorts = [ 80 443 ]; }; i18n.defaultLocale = "en_US.UTF-8"; @@ -84,12 +85,19 @@ services.nginx.enable = true; - networking.firewall.allowedTCPPorts = [ 80 443 ]; - # FIXME networking.hosts = { "192.168.94.1" = [ "raven.lab.fablab-nea.de" "labsync.lab.fablab-nea.de" ]; }; + fablab.luksUsbUnlock = { + enable = true; + devices."${config.disko.devices.disk.nvme.content.partitions.luks.content.name}" = { + keyPath = "${config.networking.hostName}.key"; + usbDevice = "by-label/RAM_USB"; + waitForDevice = 10; + }; + }; + system.stateVersion = "24.05"; } diff --git a/machines/raven/disko.nix b/machines/raven/disko.nix index 84ad2ea..0429f57 100644 --- a/machines/raven/disko.nix +++ b/machines/raven/disko.nix @@ -1,4 +1,6 @@ { + boot.initrd.systemd.enable = true; + disko.devices = { disk = { nvme = { @@ -21,7 +23,7 @@ size = "100%"; content = { type = "luks"; - name = "raven-crypt"; + name = "raven_crypt"; settings = { allowDiscards = true; }; diff --git a/machines/raven/hardware-configuration.nix b/machines/raven/hardware-configuration.nix index 27292cd..21f9c9e 100644 --- a/machines/raven/hardware-configuration.nix +++ b/machines/raven/hardware-configuration.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, modulesPath, ... }: +{ modulesPath, ... }: { imports = [ diff --git a/machines/raven/secrets.yaml b/machines/raven/secrets.yaml index 872e6ea..f20282e 100644 --- a/machines/raven/secrets.yaml +++ b/machines/raven/secrets.yaml @@ -4,6 +4,10 @@ asterisk-ari: ENC[AES256_GCM,data:2+X/DRmRlnVraWWEBXWXJ9XpFnRdD0HDlofQ7jaxNpWRKN asterisk-voicemail: ENC[AES256_GCM,data:4/Kbt/XMUGIIVpF9/KIMIi/Gx344dIleieVWch5J5z1gz2o5cLIF73qCj+vApDzSHcz2gTzMEKwEV6H8ZsxJse27dNBIdVq1n18oSWWAMT1iOomxxzqESLhF+HTtBIEpBVi5y5zwMRXGh/72SxKY9TXv/KHxTMp8aBhNvoCn2ze1VOcBjyNxGda4gGgFAa4LNTzxQ1B6XpfgkjsH2uY0zaAd8rrsXPrPY6TNS7JxrBLKfKshTiJCElJJJA1pCcRe4/yMqCm14J5+n3FvEOnHC+BQHX+ohJYaBcrZblWF5rH/l25BnUgP4UC9ydk3LmQiLpH20+sTWZwi/FojeID0BahdrzOk0tNCTKwNtfFp2QzYvlQPdFRCINb5k1Pz9DNLx7bSv1mvkeGNbd1YdHvEnPwYrQmAae96kg+Vl8PVRqY7ZsMsktcOfqlw8k/W4DK0G6LBA5U9G7JryS5OeS3kMMo4vQzcjU8/eZMl/XwHB0806k63wI7j3wL9Z5+DGmdLX3z3RgtJunELTcayAwerRptuwidm69hbOhmWEwkCcrR42QNVuDD8Qxp/CnwnmwUawUFBOFIBjbQApT9miOmo3e7nY5fjbf4JUbJ9/0JbT7YtZOEU9ymACobX6fweOsYUoWTXprJDwZkln8omaAbP85g4XgGGoltdTk71OviSSfN3DCKfPwPop8GZ9UEBQN9rNUyllVRoTeaweqN2VJnD/ApWj8A22i66R1CPm6ebXLOjClahs/hCKTeYHXPiDjWb5xd9c0fQBlnHaWbVYLtGzBpf0p9oU7DE2KskzZE2TDat8qCdMeqBcpEwUVGqcqq4YWDPy593XZzpG91NYDAb6GbkYHiZw+OQStEFA4SbN4YdwPB0fZN0iW+IOQPfWgUiRj2wAUYRXRpxPQ2ZDh7Ie0oZbJvhx6ulEM8nKI4q4e3pkzF7KjT2z9KzinkhvjqlpU0vfCm4BFMUcKXVskQsiDA9gz4w0m7Ei4HbyDHoUGVCUDtv0W6IfjrEUsBasxcYkown20rip/CwKTPmKy26bz6iHgUAB6f71Ms8sdKr7gHdnzOK3OBm5I+gell6SsdDDfGgQdUHJwSu8XwwJdc7Faai7+wN1stfSglm4PwuoFIH9ucgVyXrAwLJIQ==,iv:QzVHcduZhvQalSgRWRDoTpc20cYLFwzqDedET/XnBWQ=,tag:mrkXZ3J3Hiy2Q7Y06LsBuA==,type:str] prometheus-htpasswd: ENC[AES256_GCM,data:kUU0TqnVxQ8jLfjUpBje3eGxJw+ItD/YSNhiny1XPM0PDksnOO8Ecbyqm9W5p3WZIFc+h/FH1AsyNdhXdAhbgMNNxjebq2PNbJr/DeMWTxuf1D9q5iYpDrFGuK6r65DeCPvwN1tlTKkzJnLCqy3LLWbziANplMpmoUL7Ay3S2r5UQNgl4QIL,iv:o23da3kSbMAiF6H3zgja95As89aDK/+jWofvw9ZIjj8=,tag:VPB9YD33Xuk8IKxoBVEXdQ==,type:str] unpoller-password: ENC[AES256_GCM,data:nvbKOzS657tfumP93kNAD2Edw3+BN3xQ,iv:FZ169TIyHrhazji+b2V4o0XvyzqwNelnR4TkKXuNqWg=,tag:62Y1LTlI+2KdSjq8dHiuSQ==,type:str] +nextcloud-adminpass: ENC[AES256_GCM,data:8yX92evqkh5XDuKaPdaOxXX474mE2m5b,iv:2gKYS2s2oW0s4hhug6Y8n+8M9YMxIzcTLAp5gbktfkQ=,tag:eoT892rpSKvReve4Au+uSA==,type:str] +authelia: + jwtSecret: ENC[AES256_GCM,data:SvFGmrW+eYQr3J9xRpo1IT2H54eX58+Li+aT461bwjS0B6cswlLF/l8O2lRduLghXy80bQDYFOzfO8t0ENowhA==,iv:0jODFRL/ic07B8hLY/6LhY/ll+2uYyKbJJZAV2aZ6sw=,tag:oyTdsbRdzheq1VJRg9/PYw==,type:str] + storageEncryptionKey: ENC[AES256_GCM,data:4v2mpLvi3hRfQJCgek7RZmF/y0zb9WjQewckpp8IAOqq+YggFA2QLoDJW1fIINLNe0ACuPBdVCKQlgqt3ecqXQ==,iv:1qOSty0pNXCW5R4vSH4HTSAvQu/YelKVXUQqWfPcFhM=,tag:WZ7oDQSVn44jVyppeMQYUg==,type:str] sops: kms: [] gcp_kms: [] @@ -19,8 +23,8 @@ sops: T2VuTEpzYmhESnJZTW5IS3orRk44ODAK/KBOctiKRH5y/zuI4sIKNK9nze6aDOmc Eg7zjCXX3hvmowFt45rMKODJ56Dy6uJEgu6OWMWV2M87CphyHKA5fg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-08-04T10:58:16Z" - mac: ENC[AES256_GCM,data:yRoKVClRcbqFYM06F+83kU9s0KcoiYEx0fpr4DL39YoDDx3ZdX2aYqOEtPCGHKEccFanDsZSI4Q9jG2NEa9IykI9DDjQtci1pcNkt9VaWgPTTo2KzP086ncQHaKHyy109CjugeC2oQYIOBfSiO5b+/SP5fml2N3rhIGzROz2NRA=,iv:JR2MVuIxVhCDsx8kelTu86x4Snf6yqJ7s9vb/3bj24o=,tag:V9BadPHshitupxnAzYF3Nw==,type:str] + lastmodified: "2024-12-03T21:53:44Z" + mac: ENC[AES256_GCM,data:HFbHfL1i24LyNx+5QYgcMmBUwfQeZscdPFQHlgtJcM9Tsx/Y0wyn2B/veYR30GepQ0CBhC0IKsBDfL4K6AooqkhhBKHTVBINTn4ec9yholIJoepn4OmM4A6CE3xEkyE/PQwTEtABbJkMeUbLuZ1FcLYSo0vXfe4Jvs79o/svivk=,iv:lYZyVlvBuZrP7wzWWh+hJ1nlUXsLKQHpFhOZuXdQtqA=,tag:uxRhOkrjRFVhJYPsahxEFw==,type:str] pgp: - created_at: "2024-09-24T19:30:34Z" enc: |- @@ -54,4 +58,4 @@ sops: -----END PGP MESSAGE----- fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC unencrypted_suffix: _unencrypted - version: 3.7.3 + version: 3.9.1 diff --git a/machines/raven/services/asterisk.nix b/machines/raven/services/asterisk.nix index 075024a..800c766 100644 --- a/machines/raven/services/asterisk.nix +++ b/machines/raven/services/asterisk.nix @@ -111,12 +111,12 @@ in ln -s ${cfg.package}/var/lib/asterisk/static-http/core-en_US.xml /var/lib/asterisk/documentation/core-en_US.xml ''; - sops.secrets = (lib.listToAttrs (map + sops.secrets = lib.listToAttrs (map (name: lib.nameValuePair "asterisk-${name}" { sopsFile = ../secrets.yaml; owner = config.users.users.asterisk.name; }) - secretConfigFiles)); + secretConfigFiles); environment.etc = lib.mapAttrs' (name: _: lib.nameValuePair "asterisk/${name}.conf" diff --git a/machines/raven/services/authelia.nix b/machines/raven/services/authelia.nix new file mode 100644 index 0000000..3834fdb --- /dev/null +++ b/machines/raven/services/authelia.nix @@ -0,0 +1,76 @@ +{ config, ... }: + +let + domain = "authelia.fablab-nea.de"; + cfg = config.services.authelia.instances.default; + port = 9001; +in +{ + sops.secrets = { + "authelia/jwtSecret" = { + sopsFile = ../secrets.yaml; + owner = cfg.user; + }; + "authelia/storageEncryptionKey" = { + sopsFile = ../secrets.yaml; + owner = cfg.user; + }; + }; + + services = { + authelia.instances.default = { + enable = true; + settings = { + server.address = "tcp://127.0.0.1:${toString port}/"; + access_control = { + default_policy = "one_factor"; + }; + notifier.filesystem = { + filename = "/var/lib/authelia-${cfg.name}/notif.txt"; + }; + storage.postgres = { + address = "unix:///run/postgresql"; + database = "authelia-${cfg.name}"; + username = "authelia-${cfg.name}"; + password = "authelia-${cfg.name}"; + }; + authentication_backend = { + file.path = "/var/lib/authelia-${cfg.name}/user.yml"; + }; + session = { + cookies = [ + { + inherit domain; + authelia_url = "https://${domain}"; + name = "authelia_session"; + } + ]; + }; + }; + secrets = { + jwtSecretFile = config.sops.secrets."authelia/jwtSecret".path; + storageEncryptionKeyFile = config.sops.secrets."authelia/storageEncryptionKey".path; + }; + }; + + postgresql = { + ensureUsers = [{ + name = "authelia-${cfg.name}"; + ensureDBOwnership = true; + }]; + ensureDatabases = [ "authelia-${cfg.name}" ]; + }; + + nginx.virtualHosts."${domain}" = { + enableACME = true; + forceSSL = true; + extraConfig = '' + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + ''; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + recommendedProxySettings = true; + }; + }; + }; +} diff --git a/machines/raven/services/colorchord.nix b/machines/raven/services/colorchord.nix index 7194834..e049464 100644 --- a/machines/raven/services/colorchord.nix +++ b/machines/raven/services/colorchord.nix @@ -1,4 +1,4 @@ -{ inputs, lib, pkgs, ... }: +{ lib, pkgs, ... }: let ledDevices = { workbench-1 = { diff --git a/machines/raven/services/default.nix b/machines/raven/services/default.nix index d0b18c3..20effd4 100644 --- a/machines/raven/services/default.nix +++ b/machines/raven/services/default.nix @@ -1,6 +1,7 @@ { imports = [ ./asterisk.nix + ./authelia.nix ./colorchord.nix ./dnsmasq.nix ./dyndns.nix @@ -8,6 +9,7 @@ ./grafana.nix ./labsync ./mailhog.nix + ./nextcloud.nix ./prometheus.nix ./unifi-controller.nix ./wekan.nix diff --git a/machines/raven/services/grafana.nix b/machines/raven/services/grafana.nix index 29558c2..52dac83 100644 --- a/machines/raven/services/grafana.nix +++ b/machines/raven/services/grafana.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, ... }: let domain = "grafana.fablab-nea.de"; diff --git a/machines/raven/services/labsync/default.nix b/machines/raven/services/labsync/default.nix index 8a9250a..be26626 100644 --- a/machines/raven/services/labsync/default.nix +++ b/machines/raven/services/labsync/default.nix @@ -5,39 +5,43 @@ let generator_port = 8695; in { - services.opentracker.enable = true; + services = { + opentracker.enable = true; - services.nginx.virtualHosts."labsync.fablab-nea.de" = { - addSSL = true; - enableACME = true; - locations = { - "/generator/".proxyPass = "http://127.0.0.1:${toString generator_port}/"; + atftpd = { + enable = true; + root = pkgs.runCommand "pxelinux-tftproot" { } '' + mkdir -p $out/pxelinux.cfg + cp ${pkgs.syslinux}/share/syslinux/{ldlinux.c32,libcom32.c32,libutil.c32,lpxelinux.0,vesamenu.c32} $out + cp ${./splash.png} $out/splash.png + cp ${./pxelinux.cfg} $out/pxelinux.cfg/default + # required to serve labsync/labsync.cfg, which is generated dynamically by a docker container + ln -s /opt/docker/tftpgen/data $out/labsync + ''; }; - }; - services.nginx.virtualHosts."labsync.lab.fablab-nea.de" = { - locations = { - "/" = { - root = "/opt/docker/tftpgen/data"; - extraConfig = '' - autoindex on; - ''; + + nginx.virtualHosts = { + "labsync.fablab-nea.de" = { + addSSL = true; + enableACME = true; + locations = { + "/generator/".proxyPass = "http://127.0.0.1:${toString generator_port}/"; + }; + }; + "labsync.lab.fablab-nea.de" = { + locations = { + "/" = { + root = "/opt/docker/tftpgen/data"; + extraConfig = '' + autoindex on; + ''; + }; + "/generator/".proxyPass = "http://127.0.0.1:${toString generator_port}/"; + }; }; - "/generator/".proxyPass = "http://127.0.0.1:${toString generator_port}/"; }; }; - services.atftpd = { - enable = true; - root = pkgs.runCommand "pxelinux-tftproot" { } '' - mkdir -p $out/pxelinux.cfg - cp ${pkgs.syslinux}/share/syslinux/{ldlinux.c32,libcom32.c32,libutil.c32,lpxelinux.0,vesamenu.c32} $out - cp ${./splash.png} $out/splash.png - cp ${./pxelinux.cfg} $out/pxelinux.cfg/default - # required to serve labsync/labsync.cfg, which is generated dynamically by a docker container - ln -s /opt/docker/tftpgen/data $out/labsync - ''; - }; - networking.firewall.allowedTCPPorts = [ 6881 # aria2 6969 # opentracker diff --git a/machines/raven/services/mailhog.nix b/machines/raven/services/mailhog.nix index 8ec4c7b..f86d6a7 100644 --- a/machines/raven/services/mailhog.nix +++ b/machines/raven/services/mailhog.nix @@ -1,4 +1,3 @@ -{ config, ... }: { services.mailhog.enable = true; } diff --git a/machines/raven/services/nextcloud.nix b/machines/raven/services/nextcloud.nix new file mode 100644 index 0000000..8d746bd --- /dev/null +++ b/machines/raven/services/nextcloud.nix @@ -0,0 +1,59 @@ +{ config, pkgs, ... }: + +let + domain = "nextcloud.fablab-nea.de"; +in +{ + sops.secrets.nextcloud-adminpass = { + sopsFile = ../secrets.yaml; + owner = "nextcloud"; + group = "nextcloud"; + }; + services.nextcloud = { + enable = true; + hostName = domain; + #secretFile = + #config.dbpassFile + https = true; + config = { + adminpassFile = config.sops.secrets.nextcloud-adminpass.path; + dbtype = "pgsql"; + }; + settings = { + overwriteprotocol = "https"; + + oidc_login_client_id = "nextcloud"; + oidc_login_provider_url = "https://keycloak.fablab-nea.de"; + oidc_login_attributes = { + id = "preferred_username"; + }; + oidc_login_scope = "openid profile"; + oidc_login_button_text = "Log in with OpenID"; + oidc_login_code_challenge_method = "S256"; + }; + database.createLocally = true; + extraApps = + with config.services.nextcloud.package.packages.apps; + { + inherit + bookmarks + calendar + contacts + deck + tasks + ; + } + // { + oidc_login = pkgs.fetchNextcloudApp { + license = "agpl3Plus"; + url = "https://github.com/pulsejet/nextcloud-oidc-login/releases/download/v3.2.0/oidc_login.tar.gz"; + sha256 = "sha256-DrbaKENMz2QJfbDKCMrNGEZYpUEvtcsiqw9WnveaPZA="; + }; + }; + extraAppsEnable = true; + }; + services.nginx.virtualHosts."${domain}" = { + forceSSL = true; + enableACME = true; + }; +} diff --git a/machines/raven/services/prometheus.nix b/machines/raven/services/prometheus.nix index 5ec4a7a..4ac636b 100644 --- a/machines/raven/services/prometheus.nix +++ b/machines/raven/services/prometheus.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: let domain = "prometheus.fablab-nea.de"; @@ -7,137 +7,139 @@ let mkStaticTarget = target: mkStaticTargets (lib.singleton target); in { - services.prometheus.exporters.node.enable = true; - - services.prometheus = { - enable = true; - listenAddress = "127.0.0.1"; - webExternalUrl = "https://${domain}"; - globalConfig = { - scrape_interval = "15s"; - evaluation_interval = "15s"; - }; - extraFlags = [ - "--storage.tsdb.retention.time=90d" - "--web.enable-admin-api" - ]; - alertmanagers = [ - { - static_configs = mkStaticTarget "${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}"; - path_prefix = "/alertmanager/"; - } - ]; - alertmanager = { - enable = true; - listenAddress = "127.0.0.1"; - webExternalUrl = "https://${domain}/alertmanager"; - configuration = { - global.resolve_timeout = "2m"; - - route = { - receiver = "matrix"; - group_by = [ "alertname" ]; - group_wait = "3m"; - }; - - receivers = [ - { - name = "matrix"; - webhook_configs = lib.singleton { - url = "http://localhost/webhook"; - }; - } - ]; - }; - }; - scrapeConfigs = [ - { - job_name = "prometheus"; - static_configs = mkStaticTargets [ - "localhost:${toString cfg.port}" - "kleinturmbuehne-router:9100" - ]; - } - { - job_name = "node"; - static_configs = mkStaticTargets [ - "127.0.0.1:9100" - ]; - } - { - job_name = "asterisk"; - metrics_path = "/"; - static_configs = mkStaticTargets [ - "127.0.0.1:8088" - ]; - } - { - job_name = "mikrotik"; - static_configs = mkStaticTargets [ - "${cfg.exporters.mikrotik.listenAddress}:${toString cfg.exporters.mikrotik.port}" - ]; - } - { - job_name = "unifi"; - static_configs = mkStaticTargets [ - "${cfg.exporters.unpoller.listenAddress}:${toString cfg.exporters.unpoller.port}" - ]; - } - ]; - rules = - let - mkAlert = { name, expr, for ? "1m", description ? null }: { - alert = name; - inherit expr for; - annotations = lib.optionalAttrs (description != null) { inherit description; }; - }; - in - [ - (lib.generators.toYAML { } { - groups = lib.singleton { - name = "alert.rules"; - rules = map mkAlert [ - { - name = "InstanceDown"; - expr = ''up == 0''; - description = "Instance {{ $labels.instance }} of job {{ $labels.job }} has been down for - more than 1 minutes."; - } - ]; - }; - }) - ]; - }; - sops.secrets.prometheus-htpasswd = { owner = "nginx"; sopsFile = ../secrets.yaml; }; - services.nginx.virtualHosts."${domain}" = { - enableACME = true; - forceSSL = true; + services = { - basicAuthFile = config.sops.secrets.prometheus-htpasswd.path; - - locations = { - "/".proxyPass = "http://${cfg.listenAddress}:${toString cfg.port}"; - - "/alertmanager/".proxyPass = "http://${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}"; - }; - }; - - services.prometheus.exporters.mikrotik = { - enable = true; - listenAddress = "127.0.0.1"; - configuration = { - devices = [ + prometheus = { + exporters.node.enable = true; + enable = true; + listenAddress = "127.0.0.1"; + webExternalUrl = "https://${domain}"; + globalConfig = { + scrape_interval = "15s"; + evaluation_interval = "15s"; + }; + extraFlags = [ + "--storage.tsdb.retention.time=90d" + "--web.enable-admin-api" ]; - features = { - bgp = true; - dhcp = true; - routes = true; - optics = true; + alertmanagers = [ + { + static_configs = mkStaticTarget "${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}"; + path_prefix = "/alertmanager/"; + } + ]; + alertmanager = { + enable = true; + listenAddress = "127.0.0.1"; + webExternalUrl = "https://${domain}/alertmanager"; + configuration = { + global.resolve_timeout = "2m"; + + route = { + receiver = "matrix"; + group_by = [ "alertname" ]; + group_wait = "3m"; + }; + + receivers = [ + { + name = "matrix"; + webhook_configs = lib.singleton { + url = "http://localhost/webhook"; + }; + } + ]; + }; + }; + scrapeConfigs = [ + { + job_name = "prometheus"; + static_configs = mkStaticTargets [ + "localhost:${toString cfg.port}" + "kleinturmbuehne-router:9100" + ]; + } + { + job_name = "node"; + static_configs = mkStaticTargets [ + "127.0.0.1:9100" + ]; + } + { + job_name = "asterisk"; + metrics_path = "/"; + static_configs = mkStaticTargets [ + "127.0.0.1:8088" + ]; + } + { + job_name = "mikrotik"; + static_configs = mkStaticTargets [ + "${cfg.exporters.mikrotik.listenAddress}:${toString cfg.exporters.mikrotik.port}" + ]; + } + { + job_name = "unifi"; + static_configs = mkStaticTargets [ + "${cfg.exporters.unpoller.listenAddress}:${toString cfg.exporters.unpoller.port}" + ]; + } + ]; + rules = + let + mkAlert = { name, expr, for ? "1m", description ? null }: { + alert = name; + inherit expr for; + annotations = lib.optionalAttrs (description != null) { inherit description; }; + }; + in + [ + (lib.generators.toYAML { } { + groups = lib.singleton { + name = "alert.rules"; + rules = map mkAlert [ + { + name = "InstanceDown"; + expr = ''up == 0''; + description = "Instance {{ $labels.instance }} of job {{ $labels.job }} has been down for + more than 1 minutes."; + } + ]; + }; + }) + ]; + }; + + prometheus.exporters.mikrotik = { + enable = true; + listenAddress = "127.0.0.1"; + configuration = { + devices = [ + ]; + features = { + bgp = true; + dhcp = true; + routes = true; + optics = true; + }; + }; + }; + + nginx.virtualHosts."${domain}" = { + enableACME = true; + forceSSL = true; + + basicAuthFile = config.sops.secrets.prometheus-htpasswd.path; + + locations = { + "/".proxyPass = "http://${cfg.listenAddress}:${toString cfg.port}"; + + "/alertmanager/".proxyPass = "http://${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}"; }; }; }; diff --git a/machines/raven/services/unifi-controller.nix b/machines/raven/services/unifi-controller.nix index 6befce2..72b874b 100644 --- a/machines/raven/services/unifi-controller.nix +++ b/machines/raven/services/unifi-controller.nix @@ -1,13 +1,11 @@ { config, pkgs, ... }: -let - promCfg = config.services.prometheus; -in { services.unifi = { enable = true; openFirewall = true; unifiPackage = pkgs.unifi8; + mongodbPackage = pkgs.mongodb-7_0; }; networking.firewall.allowedTCPPorts = [ 8443 ]; diff --git a/machines/raven/services/wekan.nix b/machines/raven/services/wekan.nix index 3b9716d..6c8d3c5 100644 --- a/machines/raven/services/wekan.nix +++ b/machines/raven/services/wekan.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ lib, pkgs, ... }: let serviceName = "wekan"; databaseName = "wekandb"; @@ -62,31 +62,33 @@ in }; # Create the netowrk - systemd.services.init-filerun-network-and-files = { - description = "Create the network bridge ${networkName} for WeKan."; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; + systemd.services = { + init-filerun-network-and-files = { + description = "Create the network bridge ${networkName} for WeKan."; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "oneshot"; - script = - let podmancli = "${pkgs.podman}/bin/podman"; - in '' - if ! ${podmancli} network ls --format '{{ .Name }}' | grep -qFx -- "${networkName}"; then - ${podmancli} network create "${networkName}" - else - echo "network already exists" - fi - ''; - }; - - systemd.services.wekan-restart = { - description = "Restart Wekan services."; - serviceConfig = { - Type = "oneshot"; + serviceConfig.Type = "oneshot"; + script = + let podmancli = "${pkgs.podman}/bin/podman"; + in '' + if ! ${podmancli} network ls --format '{{ .Name }}' | grep -qFx -- "${networkName}"; then + ${podmancli} network create "${networkName}" + else + echo "network already exists" + fi + ''; + }; + + wekan-restart = { + description = "Restart Wekan services."; + serviceConfig = { + Type = "oneshot"; + }; + script = '' + ${pkgs.systemd}/bin/systemctl restart "podman-${databaseName}.service" "podman-${serviceName}.service" + ''; }; - script = '' - ${pkgs.systemd}/bin/systemctl restart "podman-${databaseName}.service" "podman-${serviceName}.service" - ''; }; systemd.timers.wekan-restart = { diff --git a/modules/default.nix b/modules/default.nix index 244c94d..f3fbce0 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,6 +1,7 @@ { imports = [ ./base.nix + ./luksusb.nix ./nix.nix ./pipewire.nix ./pubkeys.nix diff --git a/modules/luksusb.nix b/modules/luksusb.nix new file mode 100644 index 0000000..17b931b --- /dev/null +++ b/modules/luksusb.nix @@ -0,0 +1,121 @@ +{ config, lib, ... }: +let + cfg = config.fablab.luksUsbUnlock; +in +{ + options.fablab.luksUsbUnlock = with lib; with lib.types; { + enable = mkEnableOption "unlock LUKS volumes with a USB device on boot"; + devices = mkOption { + default = { }; + example = { + cryptroot = { + keyPath = "/path/to/the/key"; + usbDevice = "by-label/MY_USB"; + }; + }; + type = types.attrsOf (types.submodule { + options = { + keyPath = mkOption { + example = "/mykey.key"; + description = mdDoc '' + Path to the key file inside the USB device's filesystem. + `/` is relative to the device's filesystem root. + ''; + type = types.str; + }; + + usbDevice = mkOption { + example = "by-label/BOOTKEY"; + description = mdDoc '' + Path to the USB device that contains the keys. (Path relative to `/dev/disk/`) + ''; + type = types.str; + }; + + waitForDevice = mkOption { + default = 5; + example = 10; + description = mdDoc '' + How many seconds to wait for the USB device to be detected by the + kernel. + ''; + type = types.ints.unsigned; + }; + }; + }); + }; + }; + config = lib.mkIf cfg.enable ( + let + makeUsbDevPath = usbDevice: "/dev/disk/" + usbDevice; + makeMountPath = usbDevice: "/key/" + (builtins.hashString "md5" usbDevice); + usbFsType = "vfat"; + + mapAttrsNameValue = f: set: + lib.listToAttrs (map f (lib.attrsToList set)); + in + { + boot.initrd = { + kernelModules = [ "uas" "usbcore" "usb_storage" "vfat" "nls_cp437" "nls_iso8859_1" ]; + systemd.services = + let + makeService = name: { usbDevice, waitForDevice, ... }: + let + usbDevPath = makeUsbDevPath usbDevice; + usbMountPath = makeMountPath usbDevice; + in + { + description = "Mount ${name} key"; + wantedBy = [ "cryptsetup.target" ]; + before = [ "systemd-cryptsetup@${name}.service" ]; + after = [ "systemd-modules-load.service" ]; + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + + script = '' + if awk -v mountpoint="${usbMountPath}" '$2==mountpoint {f=1} END {exit !f}' /proc/mounts; then + exit 0 + fi + + attempts=0 + while [ ! -e ${lib.escapeShellArg usbDevPath} ]; do + sleep 1 + if [ $attempts -ge ${toString waitForDevice} ]; then + break; + fi + attempts=$((attempts+1)) + done + + if [ -e ${lib.escapeShellArg usbDevPath} ]; then + mkdir -m0500 -p ${lib.escapeShellArg usbMountPath} + mount \ + -n \ + -t ${lib.escapeShellArg usbFsType} \ + -o ro,fmask=0137,dmask=0027 \ + ${lib.escapeShellArg usbDevPath} \ + ${lib.escapeShellArg usbMountPath} + fi + ''; + }; + in + mapAttrsNameValue + ({ name, value }: { + name = "luksusb-${name}"; + value = makeService name value; + }) + cfg.devices; + + luks.devices = builtins.mapAttrs + (_: { keyPath, usbDevice, ... }: + let + usbMountPath = makeMountPath usbDevice; + in + { + keyFile = "${usbMountPath}/${keyPath}"; + keyFileTimeout = 1; + }) + cfg.devices; + }; + } + ); +} diff --git a/modules/nix.nix b/modules/nix.nix index fc6d9da..4ba3242 100644 --- a/modules/nix.nix +++ b/modules/nix.nix @@ -27,7 +27,6 @@ in registry = with inputs; { nixpkgs.flake = nixpkgs; - nixpkgs-unstable.flake = nixpkgs-unstable; }; nixPath = [ "nixpkgs=${inputs.nixpkgs}" @@ -51,13 +50,5 @@ in nixpkgs.overlays = with inputs; [ self.overlays.default sbruder-overlay.overlays.default - (final: prev: { - unstable = import nixpkgs-unstable { - inherit (config.nixpkgs) - config - overlays - system; - }; - }) ]; } diff --git a/modules/pipewire.nix b/modules/pipewire.nix index 9531e64..93405ed 100644 --- a/modules/pipewire.nix +++ b/modules/pipewire.nix @@ -1,7 +1,6 @@ { pkgs, ... }: { - sound.enable = true; hardware.pulseaudio.enable = false; services.pipewire = { diff --git a/modules/unfree.nix b/modules/unfree.nix index 3394261..e5f3549 100644 --- a/modules/unfree.nix +++ b/modules/unfree.nix @@ -1,8 +1,8 @@ { lib, ... }: { - nixpkgs.config.allowUnfreePredicate = (pkg: lib.elem (lib.getName pkg) [ + nixpkgs.config.allowUnfreePredicate = pkg: lib.elem (lib.getName pkg) [ "unifi-controller" "mongodb" - ]); + ]; } diff --git a/pkgs/default.nix b/pkgs/default.nix index f9ac13a..4841d89 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,4 +1,4 @@ -final: prev: +_final: prev: let inherit (prev) callPackage recurseIntoAttrs; in diff --git a/shell.nix b/shell.nix index e7b19d8..197dbd6 100644 --- a/shell.nix +++ b/shell.nix @@ -5,7 +5,7 @@ pkgs.mkShell { nativeBuildInputs = with pkgs; [ (pkgs.writeShellScriptBin "nix" '' - exec -a nix ${pkgs.nixUnstable}/bin/nix --experimental-features "nix-command flakes" "$@" + exec -a nix ${pkgs.nixVersions.stable}/bin/nix --experimental-features "nix-command flakes" "$@" '') ]; }