diff --git a/external/netbox/default.nix b/external/netbox/default.nix new file mode 100644 index 0000000..46ffb8c --- /dev/null +++ b/external/netbox/default.nix @@ -0,0 +1,28 @@ +{ pkgs, lib, config, ... }: +{ + imports = [ + ./secrets + ]; + services.netbox = { + enable = true; + secretKeyFile = config.age.secrets."netbox".path; + listenAddress = "127.0.0.1"; + settings = { + ALLOWED_HOSTS = [ "netbox.dgnum.sinavir.fr" ]; + }; + }; + # my server is slow sorry + systemd.services.netbox.serviceConfig.TimeoutStartSec = 600; + services.nginx = { + enable = true; + virtualHosts."netbox.dgnum.sinavir.fr" = { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "http://${config.services.netbox.listenAddress}:${builtins.toString config.services.netbox.port}"; + locations."/static/".alias = "${config.services.netbox.dataDir}/static/"; + }; + }; + users.users.nginx.extraGroups = ["netbox"]; + networking.firewall.allowedTCPPorts = [ 443 80 ]; + services.postgresql.package = pkgs.postgresql_14; +} diff --git a/external/netbox/secrets/default.nix b/external/netbox/secrets/default.nix new file mode 100644 index 0000000..bc72dc4 --- /dev/null +++ b/external/netbox/secrets/default.nix @@ -0,0 +1,14 @@ +{ + pkgs, + config, + lib, + ... +}: { + age.secrets = { + "netbox" = { + file = ./netbox.age; + group = "netbox"; + owner = "netbox"; + }; + }; +} diff --git a/external/netbox/secrets/maurice.keys b/external/netbox/secrets/maurice.keys new file mode 100644 index 0000000..15b2d82 --- /dev/null +++ b/external/netbox/secrets/maurice.keys @@ -0,0 +1,3 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAFZvpOfsBhbz9IvBj4akFr48VIuIrzSTP/6xUC0fyyF +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEpwF+XD3HgX64kqD42pcEZRNYAWoO4YNiOm5KO4tH6o maurice@polaris +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMtlR7TN69GgD5q0b+/DXC2aOKiNN8TiempaEZkfngut maurice@sirius \ No newline at end of file diff --git a/external/netbox/secrets/netbox.age b/external/netbox/secrets/netbox.age new file mode 100644 index 0000000..c6b541e --- /dev/null +++ b/external/netbox/secrets/netbox.age @@ -0,0 +1,32 @@ +age-encryption.org/v1 +-> ssh-ed25519 6J6ApA Rw8khLEeN2Vc0ogKS37PVt8RtkX/AUIPvrEl1Y4o33s +WfbB+OJWjer4p4c5WJ5/wWGTfzaP+ioSVICaWeN7v8Y +-> ssh-ed25519 JGx7Ng XPQNnVJUQnW4m6VRD5IvQLkI7M6ePLnh7I6qVmXkZUI +iDE+Po4QpuesYyyLOx5jGurDBK4PVSqCyjTiLO8tIE4 +-> ssh-ed25519 Ih+Lhw opXAdU106hSmF4j9w9QVs1PTtGFYqODit/Jzqnnm9hc +oHW0aA3rR4ix+mp/XpH7ufKC6CDVgwojRAli0Rt0umY +-> ssh-ed25519 jIXfPA UpS2FGuwL08jjS7VtMlWuIKHzpVLDIHLCeDBUyzYaDk +ekm1yEUuoxEsOhtmp0SvBeTCNEXfTlgCaS6i4OsyNkI +-> ssh-ed25519 QlRB9Q sJNeXiglN1YONRXpAknOkG7BCHTVq0eLVX/ulr/zuy8 +kZY5j2ilKr1eAxAB4eo8ku/068L8K9MGfywyQiwcGHk +-> ssh-ed25519 r+nK/Q 1AonFSikttoFe4bqaULTcTPWQxwig3VBmkEBSVqAwXg +Y2CZAeaKG+z0Qc2wjkdJC+/TvEe4ZXwwmwg34mF1drI +-> ssh-rsa krWCLQ +YA2SfssUpCkBkQ7eSQw7w9bCou04rvvSItcfYA4md41txuJ9pCKuEdAbPtBbxCBU +UqPyUCor7abyVgsIqmYR5zSCLw5yfZqynwilLC5wx7DMYGWEs0OW1jBEP0Nj6ISD +2zWLilvfiq1LPV1eKWlPUFb+STCha24LybDgNlo4O4a4AttQ5g7YgeFy3EAK4aN5 +/NTLn3Yn40WUB9XfiesL9OFiGVF2nPujyCYXBxGOL425cevVkpFpQTOrThKC3RzH +vvkUCpdP8vOd8uEsy5qHxGrJGUwc4clrbLKBg4BZ9jbAPTpFj533aF71/qiJuwMH +mhOZQzDTO3KWHSAM750HAA +-> ssh-ed25519 /vwQcQ L6Tpwg8hsUigry1IL2EbCjh+zR3AmZ8V6bPF8MgFcVs +iy2o3Ci9CmmZ4YwEvIHOOXXJT+UXNQU45faL+ulPFGk +-> ssh-ed25519 0R97PA 0Pjmquwj5A7UkMl1aUYz8AEdGiDA9B402l9B47isXwg +VM1wJWw6I7rDQkRiut2MMugRrYANgBFFAnoMhgPyBvI +-> ssh-ed25519 JGx7Ng gRZY4yXgZiftpgadbg+X9k9qF0wmSDywrk5N2Z1P4DU +el60vd0Kq5Gx0Qm+k9AQNeWvVUUobI4KjMoHkmLzPaM +-> ')tE-grease +7uJeStX+hLwArPoxtFWKhHI/p1uDPpJ2IhdEc0uNhEIbcVfthSkbQCbT7cLwHlKL +LT0tC0FcYsoS/VMu+A +--- PglFR+GxbWtTM1/wHZOz1kF7VaSjgBhJopb01kJQKCk +8}lh-*u`-X + ^ƏplrDy}|q8Dd,l=aV8ytJ0)'eJ; \ No newline at end of file diff --git a/external/netbox/secrets/secrets.nix b/external/netbox/secrets/secrets.nix new file mode 100644 index 0000000..db1cf88 --- /dev/null +++ b/external/netbox/secrets/secrets.nix @@ -0,0 +1,15 @@ +let + sources = import ../../../npins; + + inherit ((import sources.nixpkgs { })) lib; + nix-lib = import ../../../lib { }; + + groups = (import ../../../meta).members.groups; +in { + "netbox.age".publicKeys = + lib.splitString "\n" (builtins.readFile (./maurice.keys)) # maurice servers' keys + ++ nix-lib.getAllKeys ( + groups.netbox ++ + groups.root + ); +} diff --git a/meta/members.nix b/meta/members.nix index 3ea5c7e..4c3f3c2 100644 --- a/meta/members.nix +++ b/meta/members.nix @@ -31,6 +31,9 @@ let # members of this group will have root access on the installation isos iso = [ "thubrecht" "mdebray" "raito" ]; + # members of this group can access netbox's secret + netbox = []; + bureau = [ "gdd" ]; }; diff --git a/scripts/check-deployment.sh b/scripts/check-deployment.sh new file mode 100644 index 0000000..d07d522 --- /dev/null +++ b/scripts/check-deployment.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +#!@bash@/bin/bash +# shellcheck shell=bash + +set -o errexit +set -o nounset +set -o pipefail +shopt -s lastpipe + +usage="$(basename "$0") [-h] [--diff] [NODE] +Check if deployed config is actually the one on master +By default check all nodes + +where: + -h Show this help text + --dryrun Print the nixos-anywhere invocation + +Exemple: + check-deployment web01" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help|-h) + echo "$usage" + exit 0 + ;; + + --diff) + diff=y + ;; + + *) + if [[ -z ${node-} ]]; then + node="$1" + else + echo "Too many arguments. Help:" + echo "$usage" + exit 1 + fi + ;; + esac + shift +done + +############# +# go to tmp # +############# + +TMP=$(mktemp -d) +GIT_TOP_LEVEL=$(git rev-parse --show-toplevel) + +echo "Cloning local main..." +git clone -q --branch main --single-branch "$GIT_TOP_LEVEL" "$TMP" +pushd "$TMP" > /dev/null || exit 2 + +#################### +# Evaluate configs # +#################### + +colmena_failed () { + >&2 echo "Colmena failed. Check your config. Logs:" + >&2 cat "$COLMENA_LOGS" + exit 3 +} + +COLMENA_LOGS=$(mktemp) + +echo "Evaluating configs..." +# Disable warning because of '${}' +# shellcheck disable=SC2016 +RESULTS=$(colmena eval -E '{ nodes, lib, ...}: lib.mapAttrsToList (k: v: { machine = k; path = v.config.system.build.toplevel; drv = v.config.system.build.toplevel.drvPath; domain = "${v.config.networking.hostName}.${v.config.networking.domain}"; }) nodes' 2> "$COLMENA_LOGS" || colmena_failed) + +rm "$COLMENA_LOGS" +echo "Evaluation finished" + +##################################### +# retrieve and check current-system # +##################################### + +retrieve_current_system () { + # TODO implement a less invasive method + ssh -n "root@$1" "readlink -f /run/current-system" +} + + +return_status=0 +echo "$RESULTS" | @jq@/bin/jq -c '.[]' | +while IFS=$'\n' read -r c; do + + machine=$(echo "$c" | @jq@/bin/jq -r '.machine') + expected_path=$(echo "$c" | @jq@/bin/jq -r '.path') + domain=$(echo "$c" | @jq@/bin/jq -r '.domain') + drv_path=$(echo "$c" | @jq@/bin/jq -r '.drv') + + current_path=$(retrieve_current_system "$domain") + + if [ "$expected_path" == "$current_path" ] ; then + echo "$machine -> OK" + elif [[ -z ${diff-} ]] ; then + nix-store -r "$drv_path" + nix-copy-closure --from "root@$domain" "$current_path" + echo "$machine -> error. nvd output:" + @nvd@/bin/nvd diff "$expected_path" "$current_path" + return_status=1 + else + echo "$machine -> error:" + echo " - Expected system: $expected_path" + echo " - Current system: $current_path" + return_status=1 + fi +done + +popd > /dev/null || exit 2 +rm -r "$TMP" + +exit $return_status diff --git a/scripts/default.nix b/scripts/default.nix index 9a1f9b4..0929d2a 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -22,6 +22,7 @@ let } // substitutions)); scripts = [ + "check-deployment" "ns-update" "launch-vm" # "mk-backup-key"