{ pkgs, inputs, config, keys, ... }: { users.users.ai-worker = { isSystemUser = true; group = "ai-worker"; home = "/home/ai-worker"; createHome = true; # SECURITY: ai-worker is NOT in the docker group. # Docker access is restricted via sudo whitelist — only specific subcommands allowed. # extraGroups = [ "docker" ]; — REMOVED: docker group gives unrestricted docker daemon access shell = pkgs.bashInteractive; 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 via sudo (whitelist below — no exec/cp/commit) # - Run specific security audit commands # - NO access to infra repo (no bind mount) # - NO nix/nixos-rebuild/nh commands # WORKFLOW: SSH from Hermes container, run docker commands via sudo, return and save results services.aiWorkerAccess = true; # Restricted sudo for ai-worker # IMPORTANT: ai-worker is NOT in docker group. All docker access goes through sudo. # Only the subcommands listed below are allowed — everything else is denied. # This prevents: docker exec, docker cp, docker commit, and other file-modifying operations. security.sudo.extraRules = [ { users = [ "ai-worker" ]; commands = [ # === Docker commands: lifecycle management (NO file modification) === # ps/inspect/logs — read-only status checks { command = "/run/current-system/sw/bin/docker ps"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker inspect *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker logs *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker images"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker info"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker version"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker stats *"; options = [ "NOPASSWD" ]; } # start/stop/restart — container lifecycle { command = "/run/current-system/sw/bin/docker start *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker stop *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker restart *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker rm *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker rmi *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker wait *"; options = [ "NOPASSWD" ]; } # pull/build/run — image management and container creation { command = "/run/current-system/sw/bin/docker pull *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker build *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/docker run *"; options = [ "NOPASSWD" ]; } # compose — orchestration { command = "/run/current-system/sw/bin/docker compose *"; options = [ "NOPASSWD" ]; } # system — disk cleanup { command = "/run/current-system/sw/bin/docker system *"; options = [ "NOPASSWD" ]; } # network — list only (create/modify not needed) { command = "/run/current-system/sw/bin/docker network ls"; options = [ "NOPASSWD" ]; } # volume — list only (create/modify not needed) { command = "/run/current-system/sw/bin/docker volume ls"; options = [ "NOPASSWD" ]; } # === EXPLICITLY DENIED docker commands (not in whitelist — sudo rejects them) === # docker exec — executes arbitrary commands inside running containers (FILE MODIFICATION) # docker cp — copies files between containers and host (FILE ACCESS) # docker commit — creates images from running containers (DATA EXFIL) # docker diff — inspects filesystem changes (INFO LEAK) # docker export — exports container filesystem (DATA EXFIL) # docker import — imports filesystem archives # docker load — loads docker images # docker save — saves docker images to tar (DATA EXFIL) # docker attach — attaches to running containers (INTERACTIVE ACCESS) # docker push — pushes images to registries (DATA EXFIL) # docker tag — renames images # docker create — creates containers (use 'docker run' instead) # docker plugin — manages plugins # docker network create/rm — network management # docker volume create/rm — volume management # === Firewall checks === { command = "/run/wrappers/bin/sudo iptables -L -n -v"; options = [ "NOPASSWD" ]; } { command = "/run/wrappers/bin/sudo iptables -S"; options = [ "NOPASSWD" ]; } # === Fail2ban status === { command = "/run/current-system/sw/bin/fail2ban-client status"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/fail2ban-client status *"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/fail2ban-client get * banned"; options = [ "NOPASSWD" ]; } # === Log inspection === { command = "/run/current-system/sw/bin/journalctl -t kernel -n 100"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/journalctl -u fail2ban -n 50"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/journalctl -u firewall -n 50"; options = [ "NOPASSWD" ]; } # === SSH config verification === { command = "/run/current-system/sw/bin/sshd -T"; options = [ "NOPASSWD" ]; } # === Network diagnostics === { command = "/run/current-system/sw/bin/ss -tlnp"; options = [ "NOPASSWD" ]; } { command = "/run/current-system/sw/bin/cat /proc/net/tcp"; options = [ "NOPASSWD" ]; } ]; } ]; }