From 18df45819d4d857b6536a77e86ce6fcde057f03e Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Tue, 28 Apr 2026 15:34:38 +0000 Subject: [PATCH] Add restricted AI worker access with deployment capabilities - New module: modules/nixos/security/ai-worker-restricted.nix - Bind mount for infra repo access (RW) - Whitelisted sudo commands: nh, nixos-rebuild, nixpkgs-fmt, nix - Audit logging for infra changes - Documentation in README-ai-worker.md - Updated users/ai-worker.nix: - Enable services.aiWorkerAccess - Lock password (SSH key only) - Security documentation comments - Updated flake.nix: - Include new security module SECURITY: AI must ask for user confirmation before running nh os switch --- flake.nix | 1 + modules/nixos/security/README-ai-worker.md | 92 +++++++++++++++++++ .../nixos/security/ai-worker-restricted.nix | 57 ++++++++++++ users/ai-worker.nix | 11 +++ 4 files changed, 161 insertions(+) create mode 100644 modules/nixos/security/README-ai-worker.md create mode 100644 modules/nixos/security/ai-worker-restricted.nix diff --git a/flake.nix b/flake.nix index a06b03e..8f8b51a 100644 --- a/flake.nix +++ b/flake.nix @@ -61,6 +61,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 ]; diff --git a/modules/nixos/security/README-ai-worker.md b/modules/nixos/security/README-ai-worker.md new file mode 100644 index 0000000..8600e08 --- /dev/null +++ b/modules/nixos/security/README-ai-worker.md @@ -0,0 +1,92 @@ +# AI Worker Restricted Access + +This module provides restricted access for the AI worker (hermes-agent) to manage the infra repository. + +## Security Model + +The `ai-worker` user has: + +### Filesystem Access +- **Bind mount**: `/home/ai-worker/infra` → `/home/gortium/infra` (read-write) +- **Cannot access**: Any other files outside the bind mount and standard system paths + +### Sudo Access (Whitelist Only) +The following commands are allowed via sudo without password: +- `/run/current-system/sw/bin/nh` - NixOS home manager +- `/run/current-system/sw/bin/nixos-rebuild` - System rebuild +- `/run/current-system/sw/bin/nixpkgs-fmt` - Nix formatter +- `/run/current-system/sw/bin/nix` - Nix package manager + +### Docker Access +- Member of `docker` group - can manage containers +- Cannot modify host system directly + +### Audit Logging +- All changes to `/home/gortium/infra` are logged via Linux audit subsystem +- Audit rule: `-w /home/gortium/infra -p wa -k infra_changes` + +## Workflow: Ask First, Always + +**CRITICAL**: Before running any deployment command (`nh os switch` or `nixos-rebuild`), the AI MUST: + +1. **Show the planned changes** to the user +2. **Explain the impact** of the changes +3. **Wait for explicit confirmation** before executing + +### Example Workflow + +```bash +# AI prepares changes +cd /home/ai-worker/infra +# ... edits files ... +nixpkgs-fmt . + +# AI shows diff to user +git diff + +# AI asks: "Ready to deploy? This will restart the ai_stack service." +# User responds: "Yes, proceed" + +# Only then does AI run: +sudo nh os switch --flake .#lazyworkhorse +``` + +## SSH Access + +Connect as: +```bash +ssh ai-worker@lazyworkhorse +``` + +The working directory will be `/home/ai-worker`, with infra repo accessible at `/home/ai-worker/infra`. + +## Verification + +Check ai-worker permissions: +```bash +# On the host, as root or gortium: +sudo -u ai-worker sudo -l +``` + +Expected output should show only the whitelisted commands. + +## Troubleshooting + +If ai-worker cannot access infra: +```bash +# Check bind mount +mount | grep ai-worker/infra + +# Check permissions +ls -la /home/gortium/infra +ls -la /home/ai-worker/infra +``` + +If sudo commands fail: +```bash +# Check sudo rules +sudo cat /etc/sudoers.d/* | grep ai-worker + +# Check audit logs +sudo ausearch -k infra_changes +``` diff --git a/modules/nixos/security/ai-worker-restricted.nix b/modules/nixos/security/ai-worker-restricted.nix new file mode 100644 index 0000000..a02ec69 --- /dev/null +++ b/modules/nixos/security/ai-worker-restricted.nix @@ -0,0 +1,57 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + options.services.aiWorkerAccess = mkOption { + type = types.bool; + default = false; + description = "Enable restricted AI worker access to infra repo with deployment capabilities"; + }; + + config = mkIf config.services.aiWorkerAccess { + # Bind mount for infra repo access (read-write for editing) + fileSystems."/home/ai-worker/infra" = { + device = "/home/gortium/infra"; + fsType = "none"; + options = [ "bind" ]; + }; + + # Restricted sudo access - only specific commands allowed + security.sudo.extraRules = [ + { + users = [ "ai-worker" ]; + commands = [ + { + command = "/run/current-system/sw/bin/nh"; + options = [ "NOPASSWD" ]; + } + { + command = "/run/current-system/sw/bin/nixos-rebuild"; + options = [ "NOPASSWD" ]; + } + { + command = "/run/current-system/sw/bin/nixpkgs-fmt"; + options = [ "NOPASSWD" ]; + } + { + command = "/run/current-system/sw/bin/nix"; + options = [ "NOPASSWD" ]; + } + ]; + } + ]; + + # Ensure ai-worker has necessary tools available + environment.systemPackages = with pkgs; [ + nh + nixpkgs-fmt + ]; + + # Audit logging for ai-worker actions on infra directory + security.audit.enable = mkDefault true; + security.audit.rules = [ + "-w /home/gortium/infra -p wa -k infra_changes" + ]; + }; +} diff --git a/users/ai-worker.nix b/users/ai-worker.nix index a8f027c..d7df7c0 100644 --- a/users/ai-worker.nix +++ b/users/ai-worker.nix @@ -9,6 +9,17 @@ openssh.authorizedKeys.keys = [ keys.users.ai-worker.main ]; + # No password login - SSH key only + hashedPassword = "!"; }; users.groups.ai-worker = {}; + + # Enable restricted AI worker access with deployment capabilities + # SECURITY: ai-worker can only: + # - Access /home/ai-worker/infra (bind-mounted to /home/gortium/infra) + # - Run: nh, nixos-rebuild, nixpkgs-fmt, nix (via sudo, no password) + # - Manage docker containers (via docker group) + # - All changes to infra/ are logged via audit subsystem + # WORKFLOW: AI must ask for user confirmation before running nh os switch + services.aiWorkerAccess = true; }