SECURITY CHANGE: Keep ai-worker in docker group but block dangerous docker subcommands via a wrapper script. Approach: - docker group membership preserved (ps, start, stop, compose still work) - Docker binary wrapped with a script that blocks dangerous subcommands - BLOCKED: exec, cp, commit, diff, export, import, load, save, attach, push, tag - ALLOWED: ps, images, inspect, logs, start, stop, restart, rm, rmi, pull, build, run, compose, system, network ls, volume ls The wrapper is installed in both system packages and ai-worker's personal profile to ensure it takes precedence over the real docker. This is effective for the LLM agent threat model — the agent uses CLI commands and blocked subcommands simply return an error. Files modified: - users/ai-worker.nix — restored docker group, kept sudo audit rules - modules/nixos/security/ai-worker-restricted.nix — added docker wrapper script with blacklist logic and NixOS module integration - modules/nixos/security/README-ai-worker.md — documentation update
4.3 KiB
AI Worker Restricted Access
This module provides SSH access for the AI worker (hermes-agent) to run docker commands on the host with restrictions.
Security Model
Overview
The ai-worker user is a member of the docker group, but the docker binary is wrapped with a script that blocks dangerous subcommands while allowing safe operations.
Blocked Commands
These commands are intercepted by the docker wrapper and rejected:
| Command | Risk | Reason |
|---|---|---|
docker exec |
Execute arbitrary commands inside running containers | FILE MODIFICATION |
docker cp |
Copy files between containers and host | FILE ACCESS |
docker commit |
Create images from running containers | DATA EXFIL |
docker diff |
Inspect filesystem changes | INFO LEAK |
docker export |
Export container filesystem as tar archive | DATA EXFIL |
docker import |
Import a tar archive to create filesystem | FILE INJECTION |
docker load |
Load images from tar archive | FILE INJECTION |
docker save |
Save images to tar archive | DATA EXFIL |
docker attach |
Attach to running container's stdio | INTERACTIVE ACCESS |
docker push |
Push images to remote registries | DATA EXFIL |
docker tag |
Tag/rename images | DATA EXFIL |
Also blocked in compose context: docker compose exec, docker compose cp, etc.
Allowed Commands
These commands work normally:
docker ps— list containersdocker images— list imagesdocker inspect— inspect containers/imagesdocker logs— view container logsdocker start— start a stopped containerdocker stop— stop a running containerdocker restart— restart a containerdocker rm— remove a stopped containerdocker rmi— remove an imagedocker pull— pull an imagedocker build— build an imagedocker run— create and start a containerdocker compose— compose orchestration (but notcompose exec)docker system— disk managementdocker network ls— list networksdocker volume ls— list volumes
How It Works
- A wrapper script intercepts
dockercalls in the user's PATH - It parses the first non-flag argument to determine the subcommand
- If the subcommand is in the blocklist, it prints an error and exits
- Otherwise, it passes through to the real Docker binary
The wrapper is installed both as a system package and in ai-worker's personal profile to ensure it takes precedence over the real docker binary.
Why Not Use Docker Authorization Plugins?
Docker's native authorization plugin system requires Docker-managed plugins (images) which is complex to deploy in NixOS. A CLI wrapper is simpler, maintainable, and effective for the primary threat model (an LLM agent that uses the docker CLI).
Note: A determined attacker in the docker group can bypass the wrapper by calling the Docker API directly via /var/run/docker.sock. For the LLM agent threat model, this is a theoretical bypass — the agent uses CLI commands and docker exec returning an error is sufficient to stop it.
Filesystem Access
- Home directory:
/home/ai-worker(standard user home) - No bind mounts: Cannot access
/home/gortium/infraor other host files - Cannot access: Any files outside standard system paths
SSH Access
Connect as:
ssh ai-worker@lazyworkhorse
The working directory will be /home/ai-worker. No infra repo access.
Verification
# Verify wrapper is in PATH
sudo -u ai-worker which docker
# Should show: /home/ai-worker/.nix-profile/bin/docker (wrapped version)
# Test blocked command (should fail)
sudo -u ai-worker docker exec ollama ollama list
# Expected: ERROR: docker 'exec' is blocked by security policy
# Test allowed command (should work)
sudo -u ai-worker docker ps
# Expected: CONTAINER ID IMAGE ...
# Verify docker group membership
groups ai-worker
# Should show: ai-worker docker
Troubleshooting
If docker commands fail unexpectedly:
# Check which docker binary is being used
which docker
# If this shows /run/current-system/sw/bin/docker, the wrapper is not in PATH
# Check if the wrapper is installed
ls -la $(which docker)
# Verify you're running as the right user
whoami
If SSH connection fails:
# Check SSH key is authorized
cat /home/ai-worker/.ssh/authorized_keys
# Check SSH service
systemctl status sshd