diff --git a/devShells.nix b/devShells.nix index ea556eb3..836978c3 100644 --- a/devShells.nix +++ b/devShells.nix @@ -48,6 +48,7 @@ nf-actions-test nf-update nf-tf + (mkWrapper {name = "nf-generate";}) (mkWrapper {name = "nf-deploy";}) (mkWrapper {name = "nf-setup-node";}) (mkWrapper {name = "nf-sops-keyscan";}) diff --git a/generate.nix b/generate.nix new file mode 100644 index 00000000..0a49151b --- /dev/null +++ b/generate.nix @@ -0,0 +1,25 @@ +{ + inputs, + tree, +}: let + nixlib = inputs.nixpkgs.lib; + inherit (nixlib.attrsets) filterAttrs mapAttrsToList; + inherit (nixlib.lists) sortOn; + inherit (inputs.self.lib.lib) userIs; + templateSystem = inputs.self.nixosConfigurations.reimu; + templateUsers = filterAttrs (_: userIs "peeps") templateSystem.config.users.users; + mkNodeUsers = users: let + nodeUsers = mapAttrsToList (_: mkNodeUser) templateUsers; + in sortOn (user: user.uid) nodeUsers; + mkNodeUser = user: { + inherit (user) name uid; + authorizedKeys = user.openssh.authorizedKeys.keys; + }; + mkNode = { + name, + }: { + users = mkNodeUsers templateUsers; + }; +in { + reisen = mkNode { name = "reisen"; }; +} diff --git a/lib.nix b/lib.nix index 226f4829..317fea0e 100644 --- a/lib.nix +++ b/lib.nix @@ -28,11 +28,14 @@ in nibble0 + (fixedWidthString 1 "0" (toHexStringLower nibble1)); in "${part0 (part 0)}${part 1}:${part 2}ff:fe${part 3}:${part 4}${part 5}"; + + userIs = group: user: builtins.elem group (user.extraGroups ++ [ user.group ]); in { inherit tree nixlib inputs; std = inputs.self.lib.Std.Std.compat; Std = inputs.std-fl.lib; lib = { - inherit eui64 toHexStringLower hexCharToInt; + inherit userIs eui64 toHexStringLower hexCharToInt; }; + generate = import ./generate.nix { inherit inputs tree; }; } diff --git a/nixos/kyuuto/mount.nix b/nixos/kyuuto/mount.nix index 4700edda..18c27ebc 100644 --- a/nixos/kyuuto/mount.nix +++ b/nixos/kyuuto/mount.nix @@ -25,9 +25,9 @@ in { config = { systemd.tmpfiles.rules = mkIf cfg.setup [ - "d ${cfg.transferDir} 3775 root kyuuto" - "d ${cfg.libraryDir} 3775 root kyuuto" - "d ${cfg.libraryDir}/unsorted 3775 root kyuuto" + "d ${cfg.transferDir} 3775 guest kyuuto" + "d ${cfg.libraryDir} 3775 kat kyuuto" + "d ${cfg.libraryDir}/unsorted 3775 guest kyuuto" "d ${cfg.libraryDir}/music 7775 sonarr kyuuto" "d ${cfg.libraryDir}/anime 7775 sonarr kyuuto" "d ${cfg.libraryDir}/tv 7775 sonarr kyuuto" diff --git a/nixos/users/groups.nix b/nixos/users/groups.nix index 4edf1160..b6f3fe6d 100644 --- a/nixos/users/groups.nix +++ b/nixos/users/groups.nix @@ -1,11 +1,11 @@ { config, lib, + inputs, ... }: let inherit (lib.attrsets) filterAttrs mapAttrsToList; - inherit (lib.lists) elem; - userIs = group: user: elem group (user.extraGroups ++ [ user.group ]); + inherit (inputs.self.lib.lib) userIs; in { users.groups = { peeps = { diff --git a/packages/default.nix b/packages/default.nix index e9ec1979..58bfb724 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -34,6 +34,7 @@ INPUT_INFRA_SETUP="$(base64 -w0 < ${reisen + "/setup.sh"})" \ INPUT_INFRA_PUTFILE64="$(base64 -w0 < ${reisen + "/bin/putfile64.sh"})" \ INPUT_INFRA_PVE="$(base64 -w0 < ${reisen + "/bin/pve.sh"})" \ + INPUT_INFRA_MKPAM="$(base64 -w0 < ${reisen + "/bin/mkpam.sh"})" \ INPUT_INFRA_CT_CONFIG="$(base64 -w0 < ${reisen + "/bin/ct-config.sh"})" \ "bash -c \"eval \\\"\\\$(base64 -d <<<\\\$INPUT_INFRA_SETUP)\\\"\"" ''; @@ -139,6 +140,13 @@ ls -l $OUTNAME fi ''; + nf-generate = pkgs.writeShellScriptBin "nf-generate" '' + set -eu + + for node in reisen; do + nix eval --json "''${NF_CONFIG_ROOT-${toString ../.}}"#"lib.generate.$node.users" | jq -M . > "$NF_CONFIG_ROOT/systems/$node/users.json" + done + ''; nf-statix = pkgs.writeShellScriptBin "nf-statix" '' set -eu if [[ $# -eq 0 ]]; then diff --git a/systems/hakurei/lxc.json b/systems/hakurei/lxc.json index 277ebf9b..282f3ef5 100644 --- a/systems/hakurei/lxc.json +++ b/systems/hakurei/lxc.json @@ -1,6 +1,7 @@ { "lxc": { "lxc.mount.entry": [ + "/mnt/kyuuto-media mnt/kyuuto-media none bind,optional,create=dir", "/dev/net/tun dev/net/tun none bind,optional,create=file" ], "lxc.idmap": [ diff --git a/systems/hakurei/nixos.nix b/systems/hakurei/nixos.nix index cdd5d7bd..a53ee588 100644 --- a/systems/hakurei/nixos.nix +++ b/systems/hakurei/nixos.nix @@ -17,6 +17,7 @@ in { nixos.sops nixos.base nixos.reisen-ct + nixos.kyuuto nixos.tailscale nixos.cloudflared nixos.ddclient @@ -29,6 +30,7 @@ in { nixos.access.freeipa nixos.access.proxmox nixos.access.plex + nixos.samba ./reisen-ssh.nix ]; @@ -132,6 +134,8 @@ in { services.tailscale.advertiseExitNode = true; + services.samba.openFirewall = true; + systemd.network.networks.eth0 = { name = "eth0"; matchConfig = { diff --git a/systems/reimu/nixos.nix b/systems/reimu/nixos.nix index 7122d280..99374b8b 100644 --- a/systems/reimu/nixos.nix +++ b/systems/reimu/nixos.nix @@ -11,7 +11,6 @@ nixos.kyuuto nixos.tailscale nixos.nfs - nixos.samba ]; kyuuto.setup = true; diff --git a/systems/reisen/bin/mkpam.sh b/systems/reisen/bin/mkpam.sh new file mode 100644 index 00000000..76a4dddc --- /dev/null +++ b/systems/reisen/bin/mkpam.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -eu + +ARG_NAME=$1 +ARG_UID=$2 +shift 2 + +if [[ $ARG_UID != 8??? ]]; then + echo "uid $ARG_UID out of range" >&2 + exit 1 +fi + +id_exists() { + ARG_FILE=$1 + if grep -q "^${ARG_NAME}:x:" "${ARG_FILE}"; then + if ! grep -q "^${ARG_NAME}:x:${ARG_UID}:" "${ARG_FILE}"; then + echo "${ARG_NAME} already exists but with unexpected id" >&2 + exit 1 + fi + return 0 + else + return 1 + fi +} + +if ! id_exists /etc/group; then + echo "creating group $ARG_NAME=$ARG_UID..." >&2 + groupadd \ + -g "$ARG_UID" \ + "$ARG_NAME" +fi + +if ! id_exists /etc/passwd; then + echo "creating user $ARG_NAME=$ARG_UID..." >&2 + useradd -r \ + -M -d /nonexistent -s /usr/sbin/nologin \ + -N -g "$ARG_UID" \ + -u "$ARG_UID" \ + "$ARG_NAME" +fi diff --git a/systems/reisen/setup.sh b/systems/reisen/setup.sh index c675a1da..dd1c9e4b 100644 --- a/systems/reisen/setup.sh +++ b/systems/reisen/setup.sh @@ -66,7 +66,7 @@ WRAPPERBIN=/opt/infra/sbin SUDOERS_INFRABINS= rm -f "$INFRABIN/"* "$WRAPPERBIN/"* mkdir -m 0755 -p "$INFRABIN" "$WRAPPERBIN" -for infrabin in putfile64 pve ct-config; do +for infrabin in putfile64 pve mkpam ct-config; do infrainput="${infrabin//-/_}" infrainput="INPUT_INFRA_${infrainput^^}" printf '%s\n' "${!infrainput}" | base64 -d > "$WRAPPERBIN/$infrabin" diff --git a/systems/reisen/users.json b/systems/reisen/users.json new file mode 100644 index 00000000..910cce80 --- /dev/null +++ b/systems/reisen/users.json @@ -0,0 +1,29 @@ +[ + { + "authorizedKeys": [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCocjQqiDIvzq+Qu3jkf7FXw5piwtvZ1Mihw9cVjdVcsra3U2c9WYtYrA3rS50N3p00oUqQm9z1KUrvHzdE+03ZCrvaGdrtYVsaeoCuuvw7qxTQRbItTAEsfRcZLQ5c1v/57HNYNEsjVrt8VukMPRXWgl+lmzh37dd9w45cCY1QPi+JXQQ/4i9Vc3aWSe4X6PHOEMSBHxepnxm5VNHm4PObGcVbjBf0OkunMeztd1YYA9sEPyEK3b8IHxDl34e5t6NDLCIDz0N/UgzCxSxoz+YJ0feQuZtud/YLkuQcMxW2dSGvnJ0nYy7SA5DkW1oqcy6CGDndHl5StOlJ1IF9aGh0gGkx5SRrV7HOGvapR60RphKrR5zQbFFka99kvSQgOZqSB3CGDEQGHv8dXKXIFlzX78jjWDOBT67vA/M9BK9FS2iNnBF5x6shJ9SU5IK4ySxq8qvN7Us8emkN3pyO8yqgsSOzzJT1JmWUAx0tZWG/BwKcFBHfceAPQl6pwxx28TM3BTBRYdzPJLTkAy48y6iXW6UYdfAPlShy79IYjQtEThTuIiEzdzgYdros0x3PDniuAP0KOKMgbikr0gRa6zahPjf0qqBnHeLB6nHAfaVzI0aNbhOg2bdOueE1FX0x48sjKqjOpjlIfq4WeZp9REr2YHEsoLFOBfgId5P3BPtpBQ== yubikey5", + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDPsu3vNsvBb/G+wALpstD/DnoRZ3fipAs00jtl8rzDuv96RlS7AJr4aNvG6Pt2D9SYn2wVLaiw+76mz2gOycH9/N+VCvL4/0MN9uqj+7XIcxNRo0gHVOblmi2bOXcmGKh3eRwHj1xyDwRxo9WIuBEP2bPpDPz75OXRtEdlTgvky7siSguQxJu03cb0p9hNAYhUoohNXyWW2CjDCLUQVE1+QRVUzsKq3KkPy0cHYgmZC1gRSMQyKpMt72L5tayLz3Tp/zrshucc+QO5IJeZdqMxsNAcvALsysT1J5EqxZoYH9VpWLRhSgVD6Nvn853pycJAlXQxgOCpSD3/v/JbgUe5NE+ci0o7NMy5IiHUv2gQMRIEhwBHlRGwokUPL9upx0lsjaEiPya5xQqqDKRom87xytM778ANS5CuMdQMWg9qVbpHZUHMjA0QmNkjPgq71pUDXHk5L4mZuS8wVjyjnvlw68yIJuHEc8P7QiLcjvRHFS2L9Ck8NRmPDTQXlQi9kk6LmMyu6fdevR/kZL21b+xO1e2DMyxBbNDTot8luppiiL8adgUDMwptpIne7JCWB1o9NFCbXUVgwuCCYBif6pOGSc6bGo1JTAKMflRlcy6Mi3t5H0mR2lj/sCSTWwTlP5FM4aPIq08NvW6PeuK1bFJY9fIgTwVsUnbAKOhmsMt62w== cardno:12 078 454", + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII74JrgGsDQ6r7tD7+k3ykxXV7DpeeFRscPMxrBsDPhz kat@goliath", + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDkeBFF4xxZgeURLzNHcvUFxImmkQ3pxXtpj3mtSyHXB kat@koishi" + ], + "name": "kat", + "uid": 8000 + }, + { + "authorizedKeys": [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8Z6briIboxIdedPGObEWB6QEQkvxKvnMW/UVU9t/ac mew-pgp" + ], + "name": "arc", + "uid": 8001 + }, + { + "authorizedKeys": [], + "name": "kaosubaloo", + "uid": 8002 + }, + { + "authorizedKeys": [], + "name": "connieallure", + "uid": 8003 + } +] diff --git a/tf/cloudflare_records.tf b/tf/cloudflare_records.tf index 29cdf1ea..d735fe22 100644 --- a/tf/cloudflare_records.tf +++ b/tf/cloudflare_records.tf @@ -20,11 +20,13 @@ module "hakurei_system_records" { "id", "ldap", "freeipa", + "smb", ] global_subdomains = [ "plex", "idp", "ldap", + "smb", ] } @@ -38,7 +40,6 @@ module "reimu_system_records" { local_v6 = "fd0a::be24:11ff:fec4:66a8" local_subdomains = [ "nfs", - "smb", ] } diff --git a/tf/proxmox_provider.tf b/tf/proxmox_provider.tf index 1a3910db..f083e860 100644 --- a/tf/proxmox_provider.tf +++ b/tf/proxmox_provider.tf @@ -94,7 +94,7 @@ variable "proxmox_user_arc_last_name" { } resource "proxmox_virtual_environment_user" "arc" { - user_id = "arc@pve" + user_id = "arc@pam" email = var.proxmox_user_arc_email first_name = var.proxmox_user_arc_first_name last_name = var.proxmox_user_arc_last_name @@ -104,6 +104,10 @@ resource "proxmox_virtual_environment_user" "arc" { lifecycle { ignore_changes = [password] } + + depends_on = [ + terraform_data.proxmox_reisen_users, + ] } variable "proxmox_user_kat_email" { @@ -111,7 +115,7 @@ variable "proxmox_user_kat_email" { } resource "proxmox_virtual_environment_user" "kat" { - user_id = "kat@pve" + user_id = "kat@pam" email = var.proxmox_user_kat_email first_name = "Kat" last_name = "Inskip" @@ -121,6 +125,10 @@ resource "proxmox_virtual_environment_user" "kat" { lifecycle { ignore_changes = [password] } + + depends_on = [ + terraform_data.proxmox_reisen_users, + ] } variable "proxmox_user_kaosubaloo_email" { @@ -136,7 +144,7 @@ variable "proxmox_user_kaosubaloo_last_name" { } resource "proxmox_virtual_environment_user" "kaosubaloo" { - user_id = "kaosubaloo@pve" + user_id = "kaosubaloo@pam" email = var.proxmox_user_kaosubaloo_email first_name = var.proxmox_user_kaosubaloo_first_name last_name = var.proxmox_user_kaosubaloo_last_name @@ -157,7 +165,7 @@ variable "proxmox_user_connieallure_last_name" { } resource "proxmox_virtual_environment_user" "connieallure" { - user_id = "connieallure@pve" + user_id = "connieallure@pam" email = var.proxmox_user_connieallure_email first_name = "Connie" last_name = var.proxmox_user_connieallure_last_name @@ -167,4 +175,8 @@ resource "proxmox_virtual_environment_user" "connieallure" { lifecycle { ignore_changes = [password] } + + depends_on = [ + terraform_data.proxmox_reisen_users, + ] } diff --git a/tf/proxmox_reisen.tf b/tf/proxmox_reisen.tf index bd54b7e0..7d0050e6 100644 --- a/tf/proxmox_reisen.tf +++ b/tf/proxmox_reisen.tf @@ -11,6 +11,8 @@ locals { proxmox_reisen_net_vmbr0_ipv6 = file("${path.root}/../systems/reisen/net.50-vmbr0-ipv6.conf") proxmox_reisen_udev_dri = file("${path.root}/../systems/reisen/udev.90-dri.rules") proxmox_reisen_udev_z2m = file("${path.root}/../systems/reisen/udev.90-z2m.rules") + + proxmox_reisen_users = jsondecode(file("${path.root}/../systems/reisen/users.json")) } resource "terraform_data" "proxmox_reisen_etc" { @@ -38,3 +40,23 @@ resource "terraform_data" "proxmox_reisen_etc" { ] } } + +resource "terraform_data" "proxmox_reisen_users" { + triggers_replace = { + users = local.proxmox_reisen_users + } + + connection { + type = local.proxmox_reisen_connection.type + user = local.proxmox_reisen_connection.user + password = local.proxmox_reisen_connection.password + host = local.proxmox_reisen_connection.host + port = local.proxmox_reisen_connection.port + } + + provisioner "remote-exec" { + inline = [for user in local.proxmox_reisen_users : + "mkpam '${user.name}' '${user.uid}'" + ] + } +}