Compare commits
64 Commits
feat/wireg
...
local_chan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e236581f0 | ||
|
|
65587809aa | ||
|
|
2b1df578ac | ||
|
|
1c806e6390 | ||
|
|
78ab440727 | ||
|
|
ab7da92626 | ||
|
|
e3f7d18d8e | ||
| 5aca97e057 | |||
| a51e095717 | |||
| 9ebbb1c0c6 | |||
| 7f11da1878 | |||
| 29cc20bb04 | |||
| 1617ac9149 | |||
| 24f15c98cd | |||
| bdd6d03739 | |||
| a0a6663793 | |||
| b66ffadb79 | |||
| db2bd1d157 | |||
| 36359de6aa | |||
|
|
10b8565fd6 | ||
|
|
f672696b8e | ||
| 0980dca455 | |||
| 96bc20ab70 | |||
| 670ae4f002 | |||
| f785abfd49 | |||
| 6f44aa7f76 | |||
| 8d40f1691f | |||
|
|
2dd2e64986 | ||
|
|
23fc5e0597 | ||
| 0c9c33d735 | |||
| 0bb6890f1c | |||
| 9d5434425f | |||
| 1fb4320dd1 | |||
| 51e9f47fd4 | |||
| 06b3eb840f | |||
| 28ab52209c | |||
|
|
e6f7f0c263 | ||
|
|
5c136e0765 | ||
|
|
f722af7803 | ||
|
|
c07debf088 | ||
| 6806898f04 | |||
| 96e77c5ef2 | |||
| ff7303cf6a | |||
| 9e42f5d2cc | |||
| 614883f3c3 | |||
| 374d022593 | |||
| 9679846cdb | |||
| 4056f91ec6 | |||
| 1ba7d31d2f | |||
| c7e9f8a1e0 | |||
| bbe1a4a850 | |||
| 2b8316060c | |||
| cc2c62faf7 | |||
| 47f1ba6cf2 | |||
| db89881d75 | |||
| 0bb0a270e6 | |||
| 41256ccbde | |||
| e551f0e5c5 | |||
| b11d599f37 | |||
| 782f2fa9ed | |||
| 2e14069584 | |||
|
|
7d3d072961 | ||
| f0e21d95e4 | |||
| 18df45819d |
Submodule assets/compose updated: 434b2835ff...e525145057
188
flake.lock
generated
188
flake.lock
generated
@@ -23,6 +23,38 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"argononed": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1729566243,
|
||||
"narHash": "sha256-DPNI0Dpk5aym3Baf5UbEe5GENDrSmmXVdriRSWE+rgk=",
|
||||
"owner": "nvmd",
|
||||
"repo": "argononed",
|
||||
"rev": "16dbee54d49b66d5654d228d1061246b440ef7cf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"repo": "argononed",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"argononed_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1729566243,
|
||||
"narHash": "sha256-DPNI0Dpk5aym3Baf5UbEe5GENDrSmmXVdriRSWE+rgk=",
|
||||
"owner": "nvmd",
|
||||
"repo": "argononed",
|
||||
"rev": "16dbee54d49b66d5654d228d1061246b440ef7cf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"repo": "argononed",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -37,6 +69,36 @@
|
||||
"url": "https://git.lix.systems/lix-project/flake-compat/archive/main.tar.gz"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"locked": {
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"locked": {
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -144,6 +206,130 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-images": {
|
||||
"inputs": {
|
||||
"nixos-stable": [
|
||||
"nixos-raspberrypi",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixos-unstable": [
|
||||
"nixos-raspberrypi",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747747741,
|
||||
"narHash": "sha256-LUOH27unNWbGTvZFitHonraNx0JF/55h30r9WxqrznM=",
|
||||
"owner": "nvmd",
|
||||
"repo": "nixos-images",
|
||||
"rev": "cbbd6db325775096680b65e2a32fb6187c09bbb4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"ref": "sdimage-installer",
|
||||
"repo": "nixos-images",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-images_2": {
|
||||
"inputs": {
|
||||
"nixos-stable": [
|
||||
"nixos-uconsole",
|
||||
"nixos-raspberrypi",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixos-unstable": [
|
||||
"nixos-uconsole",
|
||||
"nixos-raspberrypi",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747747741,
|
||||
"narHash": "sha256-LUOH27unNWbGTvZFitHonraNx0JF/55h30r9WxqrznM=",
|
||||
"owner": "nvmd",
|
||||
"repo": "nixos-images",
|
||||
"rev": "cbbd6db325775096680b65e2a32fb6187c09bbb4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"ref": "sdimage-installer",
|
||||
"repo": "nixos-images",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-raspberrypi": {
|
||||
"inputs": {
|
||||
"argononed": "argononed",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"nixos-images": "nixos-images",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1779023229,
|
||||
"narHash": "sha256-MInilg7B/06c34SwOuGSBho4l0H1EZcmvxTkSWCs5pE=",
|
||||
"owner": "nvmd",
|
||||
"repo": "nixos-raspberrypi",
|
||||
"rev": "06c6e3513e1ee64b651913193fc6ac38aa4963f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"ref": "v1.20260517.0",
|
||||
"repo": "nixos-raspberrypi",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-raspberrypi_2": {
|
||||
"inputs": {
|
||||
"argononed": "argononed_2",
|
||||
"flake-compat": "flake-compat_3",
|
||||
"nixos-images": "nixos-images_2",
|
||||
"nixpkgs": [
|
||||
"nixos-uconsole",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1779023229,
|
||||
"narHash": "sha256-MInilg7B/06c34SwOuGSBho4l0H1EZcmvxTkSWCs5pE=",
|
||||
"owner": "nvmd",
|
||||
"repo": "nixos-raspberrypi",
|
||||
"rev": "06c6e3513e1ee64b651913193fc6ac38aa4963f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nvmd",
|
||||
"ref": "v1.20260517.0",
|
||||
"repo": "nixos-raspberrypi",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-uconsole": {
|
||||
"inputs": {
|
||||
"nixos-raspberrypi": "nixos-raspberrypi_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1780333979,
|
||||
"narHash": "sha256-yjp/gWRqWCxalYLe2+27gbxhttL+46Ozm7qvccpFbv4=",
|
||||
"owner": "nixos-uconsole",
|
||||
"repo": "nixos-uconsole",
|
||||
"rev": "1e6a8dc51c7b26e15850688a0b01121c3fea4b30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos-uconsole",
|
||||
"repo": "nixos-uconsole",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1705033721,
|
||||
@@ -212,6 +398,8 @@
|
||||
"inputs": {
|
||||
"agenix": "agenix",
|
||||
"lix": "lix",
|
||||
"nixos-raspberrypi": "nixos-raspberrypi",
|
||||
"nixos-uconsole": "nixos-uconsole",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
}
|
||||
},
|
||||
|
||||
29
flake.nix
29
flake.nix
@@ -12,10 +12,18 @@
|
||||
url = "git+https://git.lix.systems/lix-project/lix?ref=main";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nixos-uconsole = {
|
||||
url = "github:nixos-uconsole/nixos-uconsole";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nixos-raspberrypi = {
|
||||
url = "github:nvmd/nixos-raspberrypi/v1.20260517.0";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
self.submodules = true;
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, agenix, lix, ... }@inputs:
|
||||
outputs = { self, nixpkgs, agenix, lix, nixos-uconsole, nixos-raspberrypi, ... }@inputs:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
keys = import ./lib/keys.nix;
|
||||
@@ -26,7 +34,7 @@
|
||||
"/etc/ssh/ssh_host_ed25519_key"
|
||||
"/root/.age/bootstrap.key" ];
|
||||
};
|
||||
overlays = [ agenix.overlays.default ];
|
||||
overlays = [ agenix.overlays.default (import ./overlays/reticulum.nix) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
config.allowUnfree = true;
|
||||
@@ -61,6 +69,7 @@
|
||||
./modules/nixos/services/open_code_server.nix
|
||||
./modules/nixos/services/ollama_init_custom_models.nix
|
||||
./modules/nixos/services/openclaw_node.nix
|
||||
./modules/nixos/security/ai-worker-restricted.nix
|
||||
./users/gortium.nix
|
||||
./users/ai-worker.nix
|
||||
];
|
||||
@@ -79,6 +88,22 @@
|
||||
./hosts/cyt-pi/hardware-configuration.nix
|
||||
];
|
||||
};
|
||||
|
||||
uConsole = nixos-raspberrypi.lib.nixosSystem {
|
||||
specialArgs = { inherit self keys paths inputs nixos-raspberrypi; };
|
||||
modules = [
|
||||
{
|
||||
nixpkgs.overlays = overlays;
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
nixpkgs.hostPlatform = "aarch64-linux";
|
||||
nix.package = lix.packages."aarch64-linux".default;
|
||||
}
|
||||
nixos-raspberrypi.nixosModules.raspberry-pi-5.base
|
||||
nixos-uconsole.nixosModules.uconsole-cm5
|
||||
./hosts/uConsole/configuration.nix
|
||||
./hosts/uConsole/hardware-configuration.nix
|
||||
];
|
||||
};
|
||||
};
|
||||
devShells.${system}.default = devShell;
|
||||
};
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
# Flakesss
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" "flake-self-attrs" ];
|
||||
nix.settings.trusted-users = [ "root" "gortium" ];
|
||||
nix.settings.extra-platforms = [ "aarch64-linux" ];
|
||||
|
||||
# QEMU binfmt for cross-building aarch64 NixOS targets
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
# Garbage collection
|
||||
nix.gc = {
|
||||
@@ -140,6 +144,7 @@
|
||||
# You can use https://Search.nixos.org/ to find more packages (and options).
|
||||
environment.systemPackages = with pkgs; [
|
||||
neovim
|
||||
tmux
|
||||
docker-compose
|
||||
wget
|
||||
age
|
||||
@@ -207,6 +212,7 @@
|
||||
ai = {
|
||||
path = self + "/assets/compose/ai";
|
||||
envFile = config.age.secrets.containers_env.path;
|
||||
ports = [ 22000 ]; # Syncthing TCP sync
|
||||
};
|
||||
|
||||
cloudstorage = {
|
||||
@@ -251,12 +257,6 @@
|
||||
# };
|
||||
};
|
||||
|
||||
services.opencode = {
|
||||
enable = true;
|
||||
port = 4099;
|
||||
ollamaUrl = "http://127.0.0.1:11434/v1";
|
||||
};
|
||||
|
||||
# Private host ssh key managed by agenix
|
||||
age = {
|
||||
identityPaths = paths.identities;
|
||||
@@ -306,16 +306,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
# OpenClaw Node service (host-side execution for Docker gateway)
|
||||
services.openclaw-node = {
|
||||
enable = true;
|
||||
user = "ai-worker";
|
||||
gatewayHost = "127.0.0.1";
|
||||
gatewayPort = 18789;
|
||||
gatewayTokenFile = "/run/secrets/openclaw_gateway_token";
|
||||
displayName = "lazyworkhorse-host";
|
||||
};
|
||||
|
||||
# Public host ssh key (kept in sync with the private one)
|
||||
environment.etc."ssh/ssh_host_ed25519_key.pub".text =
|
||||
"${keys.hosts.lazyworkhorse.main}";
|
||||
@@ -474,7 +464,7 @@
|
||||
services.openssh.settings = {
|
||||
PermitRootLogin = "no";
|
||||
MaxAuthTries = 3;
|
||||
MaxSessions = 10;
|
||||
MaxSessions = 20;
|
||||
LoginGraceTime = 30;
|
||||
ClientAliveInterval = 300;
|
||||
ClientAliveCountMax = 2;
|
||||
|
||||
171
hosts/uConsole/configuration.nix
Normal file
171
hosts/uConsole/configuration.nix
Normal file
@@ -0,0 +1,171 @@
|
||||
{ config, lib, pkgs, paths, self, keys, ... }:
|
||||
|
||||
{
|
||||
# Basic Host Info
|
||||
networking.hostName = "uConsole";
|
||||
time.timeZone = "America/Montreal";
|
||||
i18n.defaultLocale = "en_CA.UTF-8";
|
||||
|
||||
# System State
|
||||
system.stateVersion = "25.05";
|
||||
|
||||
# Boot & Hardware (migrated to kernel bootloader per nixos-raspberrypi deprecation notice)
|
||||
boot.loader.raspberry-pi.bootloader = "kernel";
|
||||
# kernel managed by nixos-raspberrypi module — don't override, patches are version-specific
|
||||
# boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
|
||||
# Networking
|
||||
networking.networkmanager.enable = true;
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PermitRootLogin = lib.mkForce "prohibit-password";
|
||||
settings.PasswordAuthentication = lib.mkForce false;
|
||||
};
|
||||
|
||||
# User
|
||||
users.users.gortium = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ];
|
||||
openssh.authorizedKeys.keys = [
|
||||
keys.users.gortium.main
|
||||
keys.users.gortium.gitea
|
||||
];
|
||||
};
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = [ "gortium" ];
|
||||
commands = [
|
||||
{
|
||||
command = "ALL";
|
||||
options = [ "NOPASSWD" ];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# ============================================================
|
||||
# Package groups
|
||||
# ============================================================
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
# ===== Base =====
|
||||
emacs-pgtk
|
||||
git
|
||||
ripgrep
|
||||
fd
|
||||
htop
|
||||
tmux
|
||||
neovim
|
||||
|
||||
# ===== HAM Radio =====
|
||||
js8call
|
||||
wsjtx
|
||||
fldigi
|
||||
pat # Winlink client
|
||||
direwolf # AX.25 packet modem
|
||||
chirp # Radio programming tool
|
||||
hamlib # Ham radio control libraries
|
||||
trustedqsl # Logbook of the World (LoTW)
|
||||
|
||||
# ===== SDR / RF =====
|
||||
sdrpp # SDR++ spectrum analyzer
|
||||
gqrx # SDR receiver GUI
|
||||
rtl-sdr # RTL-SDR drivers & utilities
|
||||
inspectrum # Offline signal analysis
|
||||
soapysdr-with-plugins # SoapySDR + hardware support plugins
|
||||
|
||||
# ===== Mesh / LoRa =====
|
||||
meshtastic # Python CLI for Meshtastic devices
|
||||
reticulumStack # Reticulum Network Stack (rnsd, rnsh, rncp, rnx, rnpath, etc.)
|
||||
lxmf # LXMF messaging protocol
|
||||
nomadnet # Nomad Network client
|
||||
|
||||
# ===== Security =====
|
||||
nmap
|
||||
aircrack-ng
|
||||
kismet # Wi-Fi monitor / IDS
|
||||
bettercap # MITM/network attack framework
|
||||
wireshark # Packet analyzer
|
||||
hashcat # GPU password cracker
|
||||
john # John the Ripper
|
||||
sqlmap # SQL injection tool
|
||||
|
||||
# ===== GPS / Maps =====
|
||||
foxtrotgps
|
||||
viking # GPS map editor
|
||||
gpsbabel # GPS data conversion
|
||||
];
|
||||
|
||||
# Packages noted but not in unstable nixpkgs:
|
||||
# - metasploit: unfree; install manually via Git clone
|
||||
# - burpsuite: unfree Java app (Community Edition available for download)
|
||||
# - sidechannel: not a distinct PyPI package; functionality covered by
|
||||
# the Reticulum stack. For LXMF GUI client, install Sideband manually
|
||||
# from github.com/markqvist/Sideband
|
||||
|
||||
# ============================================================
|
||||
# Reticulum Service (rnsd)
|
||||
# ============================================================
|
||||
systemd.services.rnsd = {
|
||||
description = "Reticulum Network Stack Daemon";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
User = "gortium";
|
||||
Group = "gortium";
|
||||
ExecStart = "${pkgs.reticulumStack}/bin/rnsd";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
LimitNOFILE = 65536;
|
||||
};
|
||||
};
|
||||
|
||||
# ============================================================
|
||||
# Kismet Service (Wi-Fi monitoring / mesh node)
|
||||
# ============================================================
|
||||
systemd.services.kismet = {
|
||||
description = "Kismet Wi-Fi Monitor & IDS";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
User = "gortium";
|
||||
Group = "kismet";
|
||||
ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
|
||||
# ============================================================
|
||||
# Kernel modules for SDR and radio
|
||||
# ============================================================
|
||||
boot.kernelModules = [
|
||||
"88x2bu" # Realtek 8812/8821BU USB WiFi (common adapter)
|
||||
"rtl8xxxu" # RTL8188/8192/8723 USB WiFi
|
||||
"rtl2832_sdr" # RTL-SDR kernel module
|
||||
"dvb_usb_rtl28xxu" # RTL-SDR DVB-T
|
||||
];
|
||||
|
||||
boot.blacklistedKernelModules = [ ];
|
||||
|
||||
# ============================================================
|
||||
# Extra udev rules for SDR and HAM radio devices
|
||||
# ============================================================
|
||||
services.udev.packages = with pkgs; [ rtl-sdr ];
|
||||
|
||||
# ============================================================
|
||||
# Enable IPv6 for Reticulum mesh
|
||||
# ============================================================
|
||||
networking.enableIPv6 = true;
|
||||
|
||||
# ============================================================
|
||||
# Firewall: open ports for Reticulum (optional)
|
||||
# ============================================================
|
||||
networking.firewall.allowedTCPPorts = [ 22 ]; # SSH only
|
||||
networking.firewall.allowedUDPPorts = [ ];
|
||||
# Reticulum uses its own encryption and doesn't need open ports
|
||||
# for basic mesh operations (peer-to-peer discovery).
|
||||
# For TCP interfaces, open additional ports as needed.
|
||||
}
|
||||
26
hosts/uConsole/hardware-configuration.nix
Normal file
26
hosts/uConsole/hardware-configuration.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "usbhid" "usb_storage" "sdhci_pci" "nvme" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# uConsole CM5 uses NVMe or eMMC for boot storage
|
||||
# The uconsole-cm5 module sets up /boot/firmware and default /
|
||||
# Override device label here if using different storage
|
||||
fileSystems."/" = lib.mkDefault {
|
||||
device = "/dev/disk/by-label/NIXOS_UCM5";
|
||||
fsType = "ext4";
|
||||
options = [ "noatime" ];
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
|
||||
}
|
||||
105
modules/nixos/security/README-ai-worker.md
Normal file
105
modules/nixos/security/README-ai-worker.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# AI Worker Restricted Access
|
||||
|
||||
This module provides SSH access for the AI worker (hermes-agent) to run ollama benchmarks on the host.
|
||||
|
||||
## Security Model
|
||||
|
||||
The `ai-worker` user has:
|
||||
|
||||
### Filesystem Access
|
||||
- **Home directory**: `/home/ai-worker` (standard user home)
|
||||
- **No bind mounts**: Cannot access `/home/gortium/infra` or other host files
|
||||
- **Cannot access**: Any files outside standard system paths
|
||||
|
||||
### Sudo Access
|
||||
- **NONE**: ai-worker has no sudo privileges
|
||||
- Cannot run `nh`, `nixos-rebuild`, `nixpkgs-fmt`, or `nix` with elevated permissions
|
||||
|
||||
### Docker Access
|
||||
- Member of `docker` group - can run `docker` and `docker exec` commands
|
||||
- Primary use: `docker exec ollama ollama ...` for benchmarking
|
||||
- Can run `docker exec --privileged ollama rocm-smi ...` for VRAM monitoring
|
||||
|
||||
## Workflow: SSH + Docker Benchmarking
|
||||
|
||||
The AI worker connects from the Hermes container to the host via SSH, runs ollama benchmarks, then returns to save results.
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```bash
|
||||
# From Hermes container, SSH to host
|
||||
ssh -i /path/to/ssh/key ai-worker@host.docker.internal
|
||||
|
||||
# On host, run ollama benchmarks via docker
|
||||
docker exec ollama ollama pull devstral-small-2:24b
|
||||
|
||||
# Create test modelfile
|
||||
docker exec ollama bash -c 'cat <<EOF > /root/.ollama/test.modelfile
|
||||
FROM devstral-small-2:24b
|
||||
PARAMETER num_ctx 65536
|
||||
PARAMETER num_gpu 99
|
||||
PARAMETER flash_attn true
|
||||
EOF'
|
||||
|
||||
# Create and test model
|
||||
docker exec ollama ollama create test-model -f /root/.ollama/test.modelfile
|
||||
docker exec ollama ollama run test-model "Write a Python async function"
|
||||
|
||||
# Check VRAM usage
|
||||
docker exec --privileged ollama rocm-smi --showmeminfo vram
|
||||
|
||||
# Cleanup
|
||||
docker exec ollama ollama rm test-model
|
||||
|
||||
# Exit SSH, return to Hermes container
|
||||
exit
|
||||
|
||||
# Save results in Hermes container
|
||||
# /opt/data/ai-optimizer/state.json
|
||||
# /opt/data/ai-optimizer/results.csv
|
||||
```
|
||||
|
||||
## SSH Access
|
||||
|
||||
Connect as:
|
||||
```bash
|
||||
ssh ai-worker@lazyworkhorse
|
||||
```
|
||||
|
||||
The working directory will be `/home/ai-worker`. No infra repo access.
|
||||
|
||||
## Verification
|
||||
|
||||
Check ai-worker permissions:
|
||||
```bash
|
||||
# On the host, as root or gortium:
|
||||
sudo -u ai-worker sudo -l
|
||||
# Should show: no sudo access
|
||||
|
||||
# Check docker group membership
|
||||
groups ai-worker
|
||||
# Should show: ai-worker docker
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If ai-worker cannot run docker commands:
|
||||
```bash
|
||||
# Check docker group membership
|
||||
groups ai-worker
|
||||
|
||||
# Verify ollama container is running
|
||||
docker ps | grep ollama
|
||||
|
||||
# Test docker access
|
||||
sudo -u ai-worker docker exec ollama ollama list
|
||||
```
|
||||
|
||||
If SSH connection fails:
|
||||
```bash
|
||||
# Check SSH key is authorized
|
||||
cat /home/ai-worker/.ssh/authorized_keys
|
||||
|
||||
# Check SSH service
|
||||
systemctl status sshd
|
||||
```
|
||||
17
modules/nixos/security/ai-worker-restricted.nix
Normal file
17
modules/nixos/security/ai-worker-restricted.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.services.aiWorkerAccess = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable AI worker SSH access with docker group membership for ollama benchmarking";
|
||||
};
|
||||
|
||||
config = mkIf config.services.aiWorkerAccess {
|
||||
# ai-worker is member of docker group - can run docker commands via SSH
|
||||
# No bind mounts, no sudo access - docker-only for ollama benchmarking
|
||||
users.groups.docker.members = [ "ai-worker" ];
|
||||
};
|
||||
}
|
||||
@@ -1,49 +1,70 @@
|
||||
{ pkgs, ... }: {
|
||||
systemd.services.init-ollama-model = {
|
||||
description = "Initialize LLM models with extra context in Ollama Docker";
|
||||
after = [ "docker-ollama.service" ];
|
||||
|
||||
# On s'assure que Docker tourne avant de lancer ce script
|
||||
after = [ "docker.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
script = ''
|
||||
# Wait for Ollama
|
||||
while ! ${pkgs.curl}/bin/curl -s http://localhost:11434/api/tags > /dev/null; do
|
||||
sleep 2
|
||||
# Fonction de création asynchrone pour ne pas bloquer le démarrage
|
||||
(
|
||||
echo "Starting asynchronous Ollama initialization..."
|
||||
|
||||
# Attente d'Ollama (maximum 120 secondes pour éviter une boucle infinie)
|
||||
TIMEOUT=60
|
||||
COUNT=0
|
||||
while ! ${pkgs.curl}/bin/curl -s -f http://127.0.0.1:11434/api/tags > /dev/null; do
|
||||
if [ $COUNT -ge $TIMEOUT ]; then
|
||||
echo "Ollama did not become ready in time. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting for Ollama API to be reachable..."
|
||||
sleep 5
|
||||
COUNT=$((COUNT + 5))
|
||||
done
|
||||
|
||||
create_model_if_missing() {
|
||||
local model_name=$1
|
||||
local base_model=$2
|
||||
if ! ${pkgs.docker}/bin/docker exec ollama ollama list | grep -q "$model_name"; then
|
||||
|
||||
# Vérification robuste via l'API HTTP d'Ollama plutôt que docker exec (évite les conflits de tty)
|
||||
if ! ${pkgs.curl}/bin/curl -s http://127.0.0.1:11434/api/tags | ${pkgs.jq}/bin/jq -e ".models[] | select(.name == \"$model_name\")" > /dev/null; then
|
||||
echo "$model_name not found, creating from $base_model..."
|
||||
|
||||
# We use a custom TEMPLATE block to strip the 'currentDate' function
|
||||
# which is unsupported in Ollama 0.5.7 but present in Devstral's default manifest.
|
||||
${pkgs.docker}/bin/docker exec ollama sh -c "cat <<EOF > /root/.ollama/$model_name.modelfile
|
||||
# Utilisation d'un fichier temporaire sur l'hôte pour l'injecter proprement dans Docker
|
||||
TMP_FILE=$(mktemp)
|
||||
cat <<EOF > "$TMP_FILE"
|
||||
FROM $base_model
|
||||
TEMPLATE \"\"\"{{- if .System }}
|
||||
TEMPLATE """{{- if .System }}
|
||||
[SYSTEM_PROMPT]
|
||||
{{ .System }}
|
||||
[/SYSTEM_PROMPT]
|
||||
{{- end }}
|
||||
{{- range .Messages }}
|
||||
{{- if eq .Role \"user\" }}
|
||||
{{- if eq .Role "user" }}
|
||||
[INST]
|
||||
{{ .Content }}
|
||||
[/INST]
|
||||
{{- else if eq .Role \"assistant\" }}
|
||||
{{- else if eq .Role "assistant" }}
|
||||
{{ .Content }}
|
||||
{{- end }}
|
||||
{{- end }}\"\"\"
|
||||
{{- end }}"""
|
||||
PARAMETER num_ctx 131072
|
||||
PARAMETER num_predict 4096
|
||||
PARAMETER num_keep 1024
|
||||
PARAMETER repeat_penalty 1.1
|
||||
PARAMETER top_k 40
|
||||
PARAMETER stop \"[INST]\"
|
||||
PARAMETER stop \"[/INST]\"
|
||||
PARAMETER stop \"</s>\"
|
||||
EOF"
|
||||
${pkgs.docker}/bin/docker exec ollama ollama create "$model_name" -f "/root/.ollama/$model_name.modelfile"
|
||||
${pkgs.docker}/bin/docker exec ollama rm "/root/.ollama/$model_name.modelfile"
|
||||
PARAMETER stop "[INST]"
|
||||
PARAMETER stop "[/INST]"
|
||||
PARAMETER stop "</s>"
|
||||
EOF
|
||||
|
||||
# Copie et création dans le conteneur
|
||||
${pkgs.docker}/bin/docker cp "$TMP_FILE" ollama:/tmp/model.modelfile
|
||||
${pkgs.docker}/bin/docker exec ollama ollama create "$model_name" -f /tmp/model.modelfile
|
||||
${pkgs.docker}/bin/docker exec ollama rm /tmp/model.modelfile
|
||||
rm -f "$TMP_FILE"
|
||||
else
|
||||
echo "$model_name already exists, skipping."
|
||||
fi
|
||||
@@ -55,13 +76,12 @@ EOF"
|
||||
# Create Devstral
|
||||
create_model_if_missing "devstral-small-2:24b-128k" "devstral-small-2:24b"
|
||||
|
||||
# create_model_if_missing "qwen2.5-coder:32b-128k" "qwen2.5-coder:32b"
|
||||
|
||||
# create_model_if_missing "mistral-large-planner:123b" "mistral-large:123b-instruct-v2407-q4_K_S"
|
||||
) &
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
Type = "forking"; # Permet à systemd de savoir que le script passe en arrière-plan via '&'
|
||||
User = "root";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
81
overlays/reticulum.nix
Normal file
81
overlays/reticulum.nix
Normal file
@@ -0,0 +1,81 @@
|
||||
final: prev: let
|
||||
python3 = final.python3;
|
||||
pyPkgs = python3.pkgs;
|
||||
in {
|
||||
reticulumStack = python3.pkgs.buildPythonApplication rec {
|
||||
pname = "reticulum";
|
||||
version = "1.2.9";
|
||||
format = "setuptools";
|
||||
src = pyPkgs.fetchPypi {
|
||||
pname = "rns";
|
||||
inherit version;
|
||||
sha256 = "554814231c237b9caacf8df669312e57dd7d3f84b6d4810125087d1a79a75d75";
|
||||
};
|
||||
propagatedBuildInputs = with pyPkgs; [ cryptography pyserial ];
|
||||
doCheck = false;
|
||||
pythonImportsCheck = [ "RNS" ];
|
||||
meta = with final.lib; {
|
||||
description = "Self-configuring, encrypted and resilient mesh networking stack";
|
||||
homepage = "https://reticulum.network/";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
};
|
||||
|
||||
lxmf = python3.pkgs.buildPythonApplication rec {
|
||||
pname = "lxmf";
|
||||
version = "0.9.8";
|
||||
format = "setuptools";
|
||||
src = pyPkgs.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "30f39f3a975a049c12ee2cfceb3261d24cb5adec881c6821f7354464b3f3650c";
|
||||
};
|
||||
propagatedBuildInputs = [ final.reticulumStack ];
|
||||
doCheck = false;
|
||||
pythonImportsCheck = [ "LXMF" ];
|
||||
meta = with final.lib; {
|
||||
description = "Lightweight Extensible Message Format for Reticulum";
|
||||
homepage = "https://github.com/markqvist/lxmf";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
};
|
||||
|
||||
nomadnet = python3.pkgs.buildPythonApplication rec {
|
||||
pname = "nomadnet";
|
||||
version = "1.1.1";
|
||||
format = "setuptools";
|
||||
src = pyPkgs.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "fa13b64a10e75b705a58024815ab72451700aa726af96d415ba99dec28dfc40a";
|
||||
};
|
||||
propagatedBuildInputs = with pyPkgs; [ final.reticulumStack final.lxmf urwid qrcode ];
|
||||
doCheck = false;
|
||||
pythonImportsCheck = [ "nomadnet" ];
|
||||
meta = with final.lib; {
|
||||
description = "Nomad Network — resilient mesh communications platform";
|
||||
homepage = "https://github.com/markqvist/NomadNet";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
};
|
||||
|
||||
rnsh = python3.pkgs.buildPythonApplication rec {
|
||||
pname = "rnsh";
|
||||
version = "0.1.7";
|
||||
format = "setuptools";
|
||||
src = pyPkgs.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "9cb72f25abb1c6d300f8014b264184ff78f592fe88e36094938012990b797c93";
|
||||
};
|
||||
propagatedBuildInputs = [ final.reticulumStack ];
|
||||
doCheck = false;
|
||||
pythonImportsCheck = [ "rnsh" ];
|
||||
meta = with final.lib; {
|
||||
description = "Remote shell over Reticulum";
|
||||
homepage = "https://github.com/acehoss/rnsh";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
};
|
||||
}
|
||||
19
secrets/ai.age
Normal file
19
secrets/ai.age
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSA2QUFR
|
||||
RmlnY2pYUFBHZGN3dzNpNVc0UW14V2NaVWZHWDJmcU1iWStsSHpJCnRYQUtEalNt
|
||||
SzFYWUF6VWRyYWF5VCtsSGduRU96MHA0WlI0b0lpUGFram8KLT4gM0stZ3JlYXNl
|
||||
IC5DPExhJQpCMlZRR0E1NGdsYlhNRXZUTVJqTTNHZUZQVUJoYkhheWd3TktvVEFp
|
||||
WnFqbS9xWUxJSmI0U0hqQkdzQU1EVy9BCkhWc3A0Mk45YVBxcnJFWU5qa01LRTVw
|
||||
WlNoWm40cjgyb1RXS3hGdlpRSEs5V0x0cHNvcVBOek0KLS0tIFhiOFExNnRSbEgz
|
||||
M3FmS1owQUdHSXpiWVhLQ0R6emtuK2hZSkkrSTFtTTAKi2hXxTslGLlneDJlvHUm
|
||||
OFsvgsHmiADRaiwDC/iCfWyEFzHyupXKX79B6rjt4Up2yUWHLHy4pyCvJiezAh1J
|
||||
uxvtVmUYrqYOUoUHCEMLjjVydh5tt+22yXezV0ecU2ePiAgb0gv9EwH8t+70An6Z
|
||||
fgvtZZqJ1hK6dTyTf4oROUjPD8RgfjDnRTTvTM1COMvwgpK+cboYAvJ4BhUsn70V
|
||||
B3Gveg7++1U2ECF8YHKZGfSuWn0ajT5RzdgRXTveGAINiW4G98oyXnOVhRHmXo9i
|
||||
8T/41afy4xhUbNCRsaAApFjS6y8xrpGtrOcpw0u3y3T/bjYHq8VDi4ttYWIF8hJD
|
||||
HPo44+SDj0g9lr/UPQDWXaiZjdD6xdioUqnHnaAdyOPPf5D6C5I7WIQPPIjnJ1yc
|
||||
PmQkIV4rtb+e7cWrGbnd9stCBZ2F+HcORfjgnJzKI5asy9rmdWPIIHkcZoPFZ/K8
|
||||
2ZWXUVgAZvwzcFxSjh5uXKvkOgYixdVLRfa88+KM++vwz0y3O5naq3d1SaLxV4dk
|
||||
mRifLNhF9y2MKjX0bZ86Wm74NlhGGQSnUuUHpPLSA6McVOfleN/yJ9gMsosxUc9U
|
||||
xIsKHYn8gN0lPVtyTSBTomK6kxoKJXxia50x/XAhJwI9X3ydLg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
10
secrets/cloudstorage.age
Normal file
10
secrets/cloudstorage.age
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBaT3h1
|
||||
K28zWlE3N3BMdHRFaldkZ0F2YVZjT3kxK2dpV1RxZUVOSElsbkdJCnF2M1ZkUWky
|
||||
cGtPaXdzMmU1cllsWWtQK3R4Z0xhUExxSW9xUVh3eUo5RjQKLT4geHEtZ3JlYXNl
|
||||
IEQ5JWBWM0QKS1N5WlpnbEtLTFNxQVFvbkVEa1BOTDhQRDV0SDhsdWFEdE5xMDRa
|
||||
b3loMDZEeGZTZ1NzaFM5UlZYT0NjMHVvWAordjh4cFhnb2pOc3JPZlFLbFU0eC9O
|
||||
WWFFVlUKLS0tIEJnMm9LM09KQ3VXNXpNNU1kS3V5VDNOTGozdDdGdWQxcFc3Mk5j
|
||||
R0p0WVkKIX6p7MGDZOxS5qVgYs5K5sKC31IPIEMaWAqA5Gygegj5rVnKtN/jn7+9
|
||||
L5CBbzaSXzNwRce0WPVi0mQp56lL12mRlXXamOx/E9Q+r2rznFYdQA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
@@ -1,36 +1,42 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBWNEpt
|
||||
cGFNeVBBaDRqb3pLSEZGQW0wb3VmVnBoZCswUFkzbnBLUnJ0QTNrClRqVkk4RUVO
|
||||
d29KYjd5YUcwankvaTFmVHUxQVpDT2ZYWHRaY3JXTUtQMU0KLT4gKXBtQ3UsXi1n
|
||||
cmVhc2UgNnwxYCBXVyA/KCQmIHt9NAo3OTZVUHR2UXkvaEFwY0ZBdEJsaFpsbHJ0
|
||||
cklKcDVHcEdWMEdPSkpnN0FiRU43RW5hUWFMdjR3WFRRSFBLSGlmClM3cTNJWlNM
|
||||
TExkdHdXUHJISkNIaE1TTUxUc1NUWkV1a09HeFU3bVZwQXMKLS0tIGhOcXFTUElS
|
||||
azJJNnEreUhMWTJBaVZGSTJPRUFqQkVYS01KRENUVVpZSDgK8+8onFejroBo7MeO
|
||||
dW+so4lOsq4zJKn3f0cxmCFg1f0X8zt6h4Uc3A5Cvr1uU+6yw1FWmJ7xa3jJz3lO
|
||||
EEaKQJXYC+xIIKGcA7qILa0SFp4a/4OuYjcg27HrlPhg7u5wDhQrd0LdVEe1Xngp
|
||||
ZivX7P7HwIna3X8C+TL+K2v/AG2N/z86cdKfRvxyMKNbHhYw+CfHEnWgh8tJ++4h
|
||||
G9evNniuNqte6cQaRe7jODfPNW4FuY/Sb7barlJ/M9iAQdYAdyLAzU1LABeHeUfD
|
||||
wtHjxy9DUZ55Vg8bB8M2JJU9MkoRT4ewiVd9LeC1GWeVmKsm93wsmrov714i7U2j
|
||||
wHtDkjqEF2MmzuQc18sjNaAHiwz8j6o5xU2L/Q4+Q707yISWG7RGZYh389Cr1rnw
|
||||
siUq/Vunqw2wk13+J/4vu9nqt5mMktBaCtp+QiWIurjwB5LUAyChrSm+dg5lb0Mt
|
||||
UhSc0lq1+E3vxAXM2Hmk+vP86VD+6WJvAU82VFApF1s6zG2FU1/AcOVVf54nan/q
|
||||
f+rgSFfASHQCYSblUJHyEtwLNsWEmTGmOEn1buUKD/H0zatPQnc0rYpjlx2V0Sjd
|
||||
6yB5+wPrZ0AkN1pjcsPKOv8Kaog2DzqIjib+SaSTaRxWHQEb9uzvaReAcYI5HOpE
|
||||
gkC040HN33BItATbo4+hz70Im8Ni/VXD+g6yzM6Hj1hJL+PinTKeg5keQRFIZjMx
|
||||
grzievB2wVBBgLgN3qMdTFmpplaL7iL702JjXZUTTK9Izp+9wiCsV1fTa53FWDht
|
||||
ylFL5SWElqXjK+QBXxAe+Jk6VQov5HI21YDXL67S554ABeRok23wxrQ31TCI4xq9
|
||||
PQV7VtNRjyVud7S29m3OwpWOsgTZhn+JclHj2v4bNJzJkJnZRTmcvGPktzRI5+R4
|
||||
e5vxVhGnJDzI71txaHl8+xS1lu9VzCQUrxX6TXyTRV4KjIOz0g06JOBgmBRBvJca
|
||||
7MZbC65xpisl/gyLRbgkVga3t94dPV+dpZsn8eq6427IyRbKslJefatggR9//c6I
|
||||
5N5fl0fR3gJQMB+HRbipBH2YsdbdWJyb4Nn6STZxIfrqoG/xC6C1raF0xK7hUx6i
|
||||
4DUDSPohM8fOIswQPfE+FH3eygfzu/Ln5+ghsgHTEhgFvmgMvyxaAt6kHIzIUhMX
|
||||
M3dASr4VPDpIXuXsRWwYLEifhzxsuvwVxfwtsnCaR6XKijsYECWGDdYOWHdleeqx
|
||||
wDPhxEesfFVhKxhrKY9Ir8k9/FFBKQU/3GjW4+SMAg5Al1YEzxshP9vKuVcsei7W
|
||||
JDwAwotNXaCm6NBckiyZJE53ou6+gckPY7V9cOfnuH74Z9ywkFzB3HW3ZlonaGyM
|
||||
oGmLGcccavFtyhg5s/As4i6X8ARIpDiwe59Pn3GNXMctySqIrrr2ogUoXgrfFCie
|
||||
6GOTdeMW7GeOSdJUxCofghlspS/nq01Og77VI/beWYrIwLubSka6Zaltww9zgObk
|
||||
/FGEMgFkEpq7iyCvYSPA8F46pJKvnMP3S84AWCPmcTcHeg4lwGPvs6btexXBGdoz
|
||||
nkCyq7wdH5Nngm7jUbl88LtaLZPAQkuqXphBVTnrF9Ofbnb4iRZ2Op4xpx9rGyvx
|
||||
mO6UEhL6V1i2YZFNkNMg/W8aoMiUgBdqbkxaxblT9L0aNdlFU9+LbWYolURVEadd
|
||||
Qjv0Z1gMA+tsuBbVszwsMfneZ5+B9Q==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBMNTFJ
|
||||
N1Q3eXhyZFliWXRhbStOQW1SZTR5UWlIcFVtS3FEUWFLWlpnbGwwCkoxUzZhckNV
|
||||
aUlpYUZTYU1wd0dtMy9Malo1ZmxvTXFMeU4yemYydmtNKzAKLT4gJn53LDswXzQt
|
||||
Z3JlYXNlIG4oRW0gPE5cWiBaaVpkWSUgO1xTSGkKenhuUGpxV0xpUTFZNlRqeWlF
|
||||
N1JaSUd5a0hWVgotLS0gQnZ6U2RjZHcvWTRTYklYd0tjNEJjc2xUYXNOMEFodm9t
|
||||
NmZFcXhLQmxmZwp99f6PvpVh5VdcZvY56M0W/wCT9yWAGwV5kAJo625aFKUEDiDL
|
||||
gybuE9ycCJ6Yk708YMRuCo8wlUF5Gd8uJuaXl2BX4450yVG7CQQbfK+zMpawvvmN
|
||||
5caZW+s3SjtlxR76qQP4UbrAmnrUnXSR3HGqwNSoYjWRg7vdLuUFam+un+B/auew
|
||||
g26RbsTC3CtBu3m7ELj61atZ2xBmx8KNrBFyzpy2HN/gZcys9IYxd8dU+M98yK1s
|
||||
BvavfZqr2nH30iYZ68RsCpO6Tu0Si8OIXFIOVF4EYZukZMkpfVlm8dwDgDF/qh9v
|
||||
cOJ3DE4SS+/iweu7/3KmsaSf+1Pz1J2g517foisJsEJ2AeSdSCeLFBa+hPM1nJmr
|
||||
uBuTzFv4UrCsT+WszLkrQwktyOGKMDD7EOmhqGZyB3qu9/Tt0uQAAOG8voXYxaIM
|
||||
CtxcyUSTfv+D3scporNYtRsF1wt/kIiqnTKWD4x4rUvaA1ik74Dk8VRGd/vesPDM
|
||||
MkaUadb8NhNbZRUcbaqWrM7Op/WhcwwnmL05FznAkjFf0ub9k1idbHRuLrtYq0eZ
|
||||
m/GMINkKnrwkx3A0tYOSHZBpCg70p6U1uzXHUdatZ56K+0OrQMWRwqsMzosQGEpS
|
||||
Yjw4Kta4iDkgI6lqNnpFWm8E0lfA2SOP3LL6R0MIj0Jj3MrEzOspXyJHjlfJapNN
|
||||
3kV4iWpXfbsEYDSVMuk5K2BUCV+fXQ9Ns9XaCu3uySzFeIIFZ0YKJ1guGZ/hInPn
|
||||
HRbyB2dIC6Nkrh2BozJxiS8Z5/hnWOPGP3EYP5U4DoKlNynUISZSDlUs9Be06Oc0
|
||||
MATCFCt5SjfbfMOrZwvl8HQTHJVuF4r48pUS9XrkWD0JxYIpMJk+jicCRk6VJf2K
|
||||
QbbMxOKgU3Dvl+OdIo8DogwITVI0kyDsWsmmFPs9UWMi5z+aq+FEwEN8BBXUCtKa
|
||||
0IEmuO/kWBf8qMfo9CxUL6AgBxRKAw691IYgF+vTsBtneyKwJdUiYEOu6AVe87SY
|
||||
gCEDxGct762aVE+ZDDEYkL4WBiKpT+JJTXvTe2S9T1lObU/25vX4FiWGOUDcBxT9
|
||||
VgoByZ2Ld+FueUgSZ1VMWxd+zkA6IrQetcL/Puumx7kBIiS+1hjxc/DMOAUy/lA5
|
||||
JmjjulYAOL0K8HbE/oEYP9JM9YyR2eIMJGocsEmonzECPPENqmQZV6vT1zjxegay
|
||||
xrkjXXbGMun28z9CrLuE2Tv5VNiGJkdB2SQbk0n2MV8Pmt7CsvQS0pT+mYsvejV+
|
||||
K+9U3+YnHXiVMK0YbRJWVpnSyEQAAjASb85N5yi8ygN+V4JfTMxZDGvDUF8d4HtT
|
||||
TXaXlQ4FoIRtbsN90SZCkYYIKIiZDQiZiK5yZ/Tw4slyZgZvG+zEG7kjMkWmqY2j
|
||||
lirzxRoRAc1tSFmb4KNST5ZEzZMdUVkoOZqBTXCxCPfhcJhMedtQP/cGJSz6kDBS
|
||||
2Mpd9oZDeL0SiJMWKB28Qvb/OnZzmfRG/8iWP5P1Tv9NzMg3nvc8w4WzjVeSFz7j
|
||||
J59wd+4BJFmHITNfklrgxTx6ODHBvJX61+6098DzBjIJetxd+Vtpgypp2lazh2b2
|
||||
TUH0BeTO7qtS7tbunXk4fVGm/LfeoPvlNf+LP8Jof0v5BPoQWkG2xS1Yvzbiz4/q
|
||||
kkm1NF8kYW4ldi16rCCeAfBr7md5jDtP7YJxykey882aCe4CZunhRaDDgnySg82g
|
||||
4hiWRmXPeuonGIHhtDPSb5CEzF9Bq6/lpDCPb2hu1mtZW2wvJv5Zf8WyopEPvBKy
|
||||
YrOzh2HNvp0e2/fKkYi7LwnPNn3Wrevp4+3aK+BztaJ7JWFFVdx8C30rt0hIMfDu
|
||||
2uc08RLuGBlcbPgLFzj+60OG+M+P+Ib8uCcPGfPnovft2Y2OSUf6yS1GylPSORDP
|
||||
wsNEwCMd/q1cUKy263SBqypPOwViFBItT8fkpXrm+aBhjse9NDQ3r0LLwaLtN0r+
|
||||
+PCvnVa2pjx4EBudYdkahWlCBEHVYFpgR9It/rXyRxJbL3lB6UvrMv+CQeu78MYW
|
||||
Mk1M0uPchpXvLG3AHVF5hReYOjsi//76Fw9Mvl9uRJwja3swKw3sjFlovnnREGbm
|
||||
Lj0KqyiJ7rh0rDNywYyq2PsVk7LjyQXwFq5J/8azo06oXG8FvNGkJ5R5n2hiEshM
|
||||
dBBnVsOXpRqK/EZnKjb/Rfg=
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
|
||||
19
secrets/homeautomation.age
Normal file
19
secrets/homeautomation.age
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBOSk9J
|
||||
RDF0bk4zNmdWRXhFTU1xUlVKeDJkTU51UDRiNjcvWlVKT3cxNzBvCk00ZEtMdlI2
|
||||
L2xiS3BnT1g0aEd3VmgydCtSVERrTjNraHNmSHZicENLODAKLT4gI0crX0A0Zmst
|
||||
Z3JlYXNlIE8wNCBfPz5uSy4KSGxzcnJlM1FRamI0VWlZbTJvRnRuanlwSjN0eisy
|
||||
bnlHSDZZbHpIbGNZUngvS1Fqb2dzd1p6UjZKZGowOUhONgoKLS0tIE1NMUV3QlpV
|
||||
dEFXMUVOTFBGSlpVSjFzRlpjVTk2dkx1VURUaFl3R014a2cKTnWIRQg4txvZZ4A5
|
||||
XdwnXZqmYzOX7l2UrjmP/TJA++EURZzYtTS+q3FV9QTIj+7k0DOLf9nKq7XHlGM8
|
||||
Ptkaf/s1Ly7ke+v9l9C2uf9oNI6b+m3d7QqZC5WWvRXWvl9ImaJ3xVi9AM5f5NWH
|
||||
Likn6GZDir4ihAec8pAi3H2SCCjkhqF/TlLe99tp+7AAUiOjNuNlej1OUOmJNxEr
|
||||
GnHePwZZqa6/F9YnYQ0tKKRsZH5whxUPYUwhHSuWa/NidBK7lqKqdaPBevfdqWLg
|
||||
59gkaL9BeGG5FUXg1cPEWAvOQ5Ajae/kVH6aRi5LXJPZfA/DetWgm9mmxJ2qPpFD
|
||||
/n/JCsQUOnpk66j38bWMW5uok51s61oG1OZWGpPYstoLtivKOlVpG7xgioGqIIuc
|
||||
c2ZsKK/iCauwX3sGQtpX9DbILrtOnzxU2B/dclcXe2EDfSJH0u2RrefxcqPG87pI
|
||||
BAosRdq7GUUISSCTccaswwG555a7/Z5gzXOwXeQYNlK1HRnkF9oBsKTUoAI2b+VO
|
||||
Hdv1uw9u5JLcZt+5qSB6AxJuk8yDF0KXIqkaCiwl2fV3bBkehPru7oCJFTtVMFVZ
|
||||
u0A0h+n8KJCvyRKe/Tl+lT+JHM6Mk7SkFrmsaepZPnAtfLht+bP6b0oHrUsVx/iI
|
||||
r7o=
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
12
secrets/network.age
Normal file
12
secrets/network.age
Normal file
@@ -0,0 +1,12 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBVMEhO
|
||||
RWdybFg4VWJaMjRWYm1ac2pzZ3R5aFZEM1o4dUtFZ0M4QnVKRzIwCnNGRFRjb01X
|
||||
QU5mQTRSb21MV3lMMERIMGI1RHFQVFFZNlVlMnk4aTdna1kKLT4gM24xLWdyZWFz
|
||||
ZSA/bVhubQplcXNVN3kxOEpqY2hUbkV3MG5PNVJtRGhORVVLdFVCRnFFVjRneEFI
|
||||
VWFyZTRNS280RXlnckJpdFR4V1NBSTUzCjlxZkZ3UllpZXUwczR0T3JGRzUzMEhV
|
||||
U1hobC84eWtEWWZOYyt6M2c3OUZIUTlKTm41dVp5UEZVSmVwWHBmR00KCi0tLSBF
|
||||
ZnJ5QzN2VXpsY3JQQ3lmbklxcldydm1MSlFlejJ2S3hVVUtka0hTM044CvqhtnFn
|
||||
pZsgP6w5uKh9CtVQpcyST8hA9P24e1opfu1JN3m/8g9XiJrMT5qVYtUXkV+pr4s6
|
||||
pVGsp9KScaS0T8TpLxvZoUAAdvVtdHh6GSbbszR6gZbStbWXmb6THYKHOghpK9HD
|
||||
cDEoRmzcmFdwi3m26Xppmi2R6NmeKI4S6pbY95bfh2E6jn+7
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
@@ -11,4 +11,8 @@ in
|
||||
"lazyworkhorse_host_ssh_key.age".publicKeys = authorizedKeys;
|
||||
"n8n_ssh_key.age".publicKeys = authorizedKeys;
|
||||
"openclaw_gateway_token.age".publicKeys = authorizedKeys;
|
||||
"ai.age".publicKeys = authorizedKeys;
|
||||
"cloudstorege.age".publicKeys = authorizedKeys;
|
||||
"homeautomation.age".age".publicKeys = authorizedKeys;
|
||||
"network.age".age".publicKeys = authorizedKeys;
|
||||
}
|
||||
|
||||
12
secrets/tak.age
Normal file
12
secrets/tak.age
Normal file
@@ -0,0 +1,12 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSBsYXVu
|
||||
Sk5CSjNsbHBRZkNXUGZVeGNva3FKMUdHV0RiQzJLNHVvSHZzd0dRClNnbzZvUFFR
|
||||
Ty96OXZ4R2lCMHpnclpVaEZ1TEYvb0tTSVRwdWV1amdIL0UKLT4gYTtvOmAtZ3Jl
|
||||
YXNlICk5WkE7USUgSyRLCjBmTWRTdEJJV2lNbVRlL3VidmZza1NTTWhIcG1vVFY5
|
||||
OUUxcG4ycTMraUUKLS0tIEVlaUdlcUFPMkZSMUpJVEFzTksrVC9lZGlMNEJ1SFBv
|
||||
SFNtc0wwQ05nQ0EKYlRGYGeKlfW0lTPdpCtcTfh2NWUuyZnDFe6VAWLYL3PW42od
|
||||
a+bhlgxTi9KF5FLjVA3IIdQSsKiMya+PI0VfOLWkA24ZN+4uilsQkicxnnRR1z8o
|
||||
hv9G8N3eYqBsLylg8rW2Xkn4RzT/S5TyJZPFG4HsUYWtHS+iomg4HbQrgIrpIde9
|
||||
Th3V8WQB1HfKs9ilg8Q/DvDckFjevWYz2OXMYx4ZHWS53huQfE/oWPZfQid6Dd06
|
||||
NXcvCHPVDUszhWvcoOsSpK6vaOnuY1B32/qExw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
9
secrets/wireguard_preshared_key.age
Normal file
9
secrets/wireguard_preshared_key.age
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSA3VG9Z
|
||||
MVFPVFc2VVJ3d0h0dmtBUnI3WHl2SzUxTkRZbjFCaGloWmV3dnd3ClcxdnVPeGd6
|
||||
SU4zR0Q0K1dtVjRRVHd0VW5XSFI0dVFpTjZnYk1DNjRxTVEKLT4gQzlgRy1ncmVh
|
||||
c2UKeUozOWgyUytSTVF0NjY2STBEb2VadwotLS0gblI3bmJCUWxxU3QrYTEyVFBI
|
||||
Snc4NC9rTkh0NnZYbUtxUE9hRWRkelpmMAq58fmH6cK13GeD7wGLxKmx10hmJeW4
|
||||
b7KqnCD1ZP7uG85s32xzVRwRG8RrG4xZo5nR9Mrtg1CoTSFfUGeFnf5xveN+Ej0X
|
||||
wDVB1LwC+Q==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
11
secrets/wireguard_private_key.age
Normal file
11
secrets/wireguard_private_key.age
Normal file
@@ -0,0 +1,11 @@
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSA5dzVG
|
||||
WUNvT3NlRmcrWS81bzJqSWlTekVYaDFFTE10SkI2dEgzaGpxcUI4Cmk5Y0FGYTRZ
|
||||
K0NGYzY3VUp4aS9ZZGRmWTgybDJFUURva2pZNmVOS3QxdEUKLT4gPnVRTCtldGMt
|
||||
Z3JlYXNlCk04OTJZeFRNeDI5aGpMVTk1ZTE0Y2FMMnFEMjlJalJpMHRlaTE4ZWIx
|
||||
d2lCRGQ5RHVjcktOMGJCb1VERlNWcTYKaSt0L1Z6dVJ0QWIyZkhsYzFEVjZSQWUr
|
||||
ZWpwVlo1TmhoUFJZdkEvR0gxNlVhcXF2ZTRnCi0tLSBLcmM2MThNVkdWclpHUXRr
|
||||
VTF6QVk2WUZlTXpZMVNLMlpBOFc3M1o5WjZzCs9xbPlIX+u5vRSQ/z9utu+I9S2c
|
||||
02DOsIb1kzxzb1OK91b8Kh4JucQSq3qkyEvRucsNn5QW8hIHDnRuND6EbPyN7p4S
|
||||
YB/F0dxSqgnq
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
@@ -9,9 +9,21 @@
|
||||
openssh.authorizedKeys.keys = [
|
||||
keys.users.ai-worker.main
|
||||
];
|
||||
# No password login - SSH key only
|
||||
hashedPassword = "!";
|
||||
};
|
||||
users.groups.ai-worker = {};
|
||||
|
||||
# Enable restricted AI worker SSH access for ollama benchmarking
|
||||
# SECURITY: ai-worker can only:
|
||||
# - SSH into host from Hermes container
|
||||
# - Run docker commands (docker exec ollama ...) via docker group
|
||||
# - Run specific security audit commands
|
||||
# - NO access to infra repo (no bind mount)
|
||||
# - NO sudo access (no nh, nixos-rebuild, nixpkgs-fmt, nix)
|
||||
# WORKFLOW: SSH from Hermes container, run docker benchmarks, return and save results to /opt/data/ai-optimizer/
|
||||
services.aiWorkerAccess = true;
|
||||
|
||||
# Restricted sudo for ai-worker - security checks only
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user