docs(07): create phase plan for Socket Security

Phase 07: Socket Security
- 3 plan(s) in 2 wave(s)
- Wave 1: 07-01 (deploy proxy - checkpoint)
- Wave 2: 07-02 (migrate workflow), 07-03 (verify blocking) - parallel
- Ready for execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Berger
2026-02-03 08:45:04 -05:00
parent 1432d4feb2
commit f539bcbba4
4 changed files with 432 additions and 2 deletions
@@ -0,0 +1,139 @@
---
phase: 07-socket-security
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: []
autonomous: false
user_setup:
- service: docker-socket-proxy
why: "Filtered Docker API access for n8n"
dashboard_config:
- task: "Install docker-socket-proxy from Unraid Community Apps"
location: "Unraid Apps tab > Search 'dockersocket'"
- task: "Configure environment variables"
location: "Container settings"
- task: "Add proxy to n8n's Docker network"
location: "Container network settings"
must_haves:
truths:
- "docker-socket-proxy container is running"
- "Proxy is on same Docker network as n8n"
- "Proxy has Docker socket mounted"
artifacts:
- path: "docker-socket-proxy container"
provides: "HAProxy-based Docker API filtering"
contains: "CONTAINERS=1, IMAGES=1, POST=1, ALLOW_START=1, ALLOW_STOP=1, ALLOW_RESTARTS=1"
key_links:
- from: "n8n container"
to: "docker-socket-proxy:2375"
via: "Docker network DNS"
pattern: "same custom bridge network"
---
<objective>
Deploy docker-socket-proxy container via Unraid Community Apps.
Purpose: Establish the proxy infrastructure that n8n will connect to instead of direct Docker socket access. This is the foundation that Plan 02 will wire up.
Output: Running docker-socket-proxy container with correct environment variables and network configuration.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/07-socket-security/07-CONTEXT.md
@.planning/phases/07-socket-security/07-RESEARCH.md
</context>
<tasks>
<task type="checkpoint:human-action" gate="blocking">
<name>Task 1: Install and Configure docker-socket-proxy</name>
<action>
User must install docker-socket-proxy via Unraid Community Apps UI.
**Steps:**
1. Open Unraid web UI > Apps tab
2. Search for "dockersocket" (tecnativa/docker-socket-proxy template)
3. Click Install
4. Configure the following settings:
**Container Name:** docker-socket-proxy
**Environment Variables (enable these):**
- CONTAINERS=1 (enable /containers/* endpoints)
- IMAGES=1 (enable /images/* endpoints - needed for update command)
- POST=1 (enable POST/PUT/DELETE operations)
- ALLOW_START=1 (enable start action)
- ALLOW_STOP=1 (enable stop action)
- ALLOW_RESTARTS=1 (enable restart action)
**Keep defaults (already 0/disabled):**
- BUILD=0
- COMMIT=0
- EXEC=0
- SECRETS=0
- AUTH=0
**Network Configuration:**
- Find n8n's custom network name (check n8n container settings)
- Add docker-socket-proxy to that same network
5. Click Apply to create the container
6. Verify container is running (green status)
</action>
<verify>
Provide the following information to continue:
1. Container name (should be "docker-socket-proxy")
2. Docker network name that both n8n and proxy are on
3. Confirm container is running
</verify>
<done>docker-socket-proxy container is running on same network as n8n</done>
<resume-signal>Provide: container name, network name, and confirm running status</resume-signal>
</task>
<task type="auto">
<name>Task 2: Verify Proxy Connectivity</name>
<files>None (verification only)</files>
<action>
Using the n8n API, test that the proxy is reachable from n8n's perspective.
1. Use n8n API to get workflow and find an Execute Command node
2. Test proxy connectivity by checking if n8n can resolve docker-socket-proxy hostname
3. Make a test API call through the proxy to list containers
If proxy is not reachable, the network configuration needs adjustment.
</action>
<verify>
Run curl from n8n to proxy: `curl -s 'http://docker-socket-proxy:2375/v1.47/containers/json?all=true'` should return container list JSON
</verify>
<done>n8n can reach docker-socket-proxy:2375 and receive valid Docker API responses</done>
</task>
</tasks>
<verification>
1. docker-socket-proxy container is running in Unraid
2. Container has correct environment variables (CONTAINERS=1, IMAGES=1, POST=1, ALLOW_START=1, ALLOW_STOP=1, ALLOW_RESTARTS=1)
3. Proxy is on the same Docker network as n8n
4. n8n can reach docker-socket-proxy:2375
</verification>
<success_criteria>
- docker-socket-proxy container running with correct config
- n8n and proxy share a Docker network
- Test curl from n8n to proxy returns container list
</success_criteria>
<output>
After completion, create `.planning/phases/07-socket-security/07-01-SUMMARY.md`
</output>
@@ -0,0 +1,148 @@
---
phase: 07-socket-security
plan: 02
type: execute
wave: 2
depends_on: ["07-01"]
files_modified: [n8n-workflow.json]
autonomous: false
must_haves:
truths:
- "All bot commands work through proxy (status, start, stop, restart, update, logs)"
- "n8n no longer references direct Docker socket in curl commands"
- "Dangerous API calls return blocked error message"
artifacts:
- path: "n8n-workflow.json"
provides: "Updated n8n workflow using proxy instead of direct socket"
contains: "docker-socket-proxy:2375"
key_links:
- from: "n8n Execute Command nodes"
to: "docker-socket-proxy:2375"
via: "TCP curl calls"
pattern: "curl.*docker-socket-proxy:2375"
---
<objective>
Migrate all n8n workflow curl commands from direct Docker socket to proxy.
Purpose: Route all Docker API calls through the filtered proxy, removing direct socket access from n8n.
Output: Updated n8n-workflow.json with all 16 curl commands migrated to use proxy endpoint.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/07-socket-security/07-CONTEXT.md
@.planning/phases/07-socket-security/07-RESEARCH.md
@.planning/phases/07-socket-security/07-01-SUMMARY.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Update Workflow Curl Commands</name>
<files>n8n-workflow.json</files>
<action>
Replace all Docker socket curl commands with proxy TCP calls.
**Search and Replace Pattern:**
FROM: `--unix-socket /var/run/docker.sock 'http://localhost/`
TO: `--max-time 5 'http://docker-socket-proxy:2375/`
**Commands to update (16 total):**
1. Container list: `curl -s --unix-socket /var/run/docker.sock 'http://localhost/v1.47/containers/json?all=true'`
2. Container inspect: Uses template `http://localhost/v1.47/containers/${containerId}/json`
3. Image inspect: Uses template `http://localhost/v1.47/images/${imageName}/json`
4. Image pull: Uses template with POST to `images/create?fromImage=`
5. Start/stop/restart: Uses template `containers/${containerId}/${action}`
6. Container delete: Uses template `containers/${containerId}` with DELETE
7. Container create: Uses POST with JSON body to `containers/create`
8. Container logs: Uses `containers/${containerId}/logs`
**Also update error handling in JavaScript nodes:**
- Add handling for HTTP 403 responses: "This action is blocked by security policy"
- Distinguish between 403 (blocked) and other errors
- Do NOT retry on 403 - fail immediately
**Do NOT change:**
- API version (/v1.47/) - keep as is for compatibility
- The 600 second timeout on image pull (that's intentional for large images)
- Any non-Docker-socket curl commands
</action>
<verify>
1. `grep -c 'unix-socket.*docker\.sock' n8n-workflow.json` returns 0
2. `grep -c 'docker-socket-proxy:2375' n8n-workflow.json` returns 16 (or similar count)
3. `grep -c 'max-time 5' n8n-workflow.json` shows timeout added (except image pull)
</verify>
<done>All Docker socket references replaced with proxy endpoint, timeout added</done>
</task>
<task type="auto">
<name>Task 2: Push Updated Workflow to n8n</name>
<files>n8n-workflow.json</files>
<action>
Use n8n API to update the live workflow with the modified JSON.
1. Load .env.n8n-api for API credentials
2. Read the updated n8n-workflow.json
3. PUT to /api/v1/workflows/{id} with the updated workflow
4. Verify the workflow was updated (check updatedAt timestamp)
**Workflow ID:** HmiXBlJefBRPMS0m4iNYc (from Phase 6 summary)
</action>
<verify>
API PUT request returns 200 with updated workflow, updatedAt timestamp is recent
</verify>
<done>n8n workflow updated via API with proxy configuration</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 3: Verify All Bot Commands Work</name>
<what-built>Updated n8n workflow that routes all Docker API calls through the socket proxy instead of direct socket access</what-built>
<how-to-verify>
Test each bot command via Telegram:
1. **status** - Should list all containers with their states
2. **start [container]** - Pick a stopped container, verify it starts
3. **stop [container]** - Stop that container, verify it stops
4. **restart [container]** - Restart a container, verify success message
5. **update [container]** - Update a container (or verify "already up to date" message)
6. **logs [container]** - View logs for a container
All commands should work identically to before the proxy migration.
If any command fails, check:
- Error message (403 = proxy blocking, other = connectivity issue)
- Proxy container logs in Unraid
- Network connectivity between n8n and proxy
</how-to-verify>
<resume-signal>Type "all commands working" or describe which commands failed</resume-signal>
</task>
</tasks>
<verification>
1. No unix-socket references remain in n8n-workflow.json
2. All curl commands use docker-socket-proxy:2375
3. Timeouts added to curl commands (except long-running image pull)
4. Error handling includes 403 response handling
5. All 6 bot commands work via Telegram
</verification>
<success_criteria>
- Zero unix-socket references in workflow
- All bot commands functional through proxy
- User confirms "all commands working"
</success_criteria>
<output>
After completion, create `.planning/phases/07-socket-security/07-02-SUMMARY.md`
</output>
@@ -0,0 +1,136 @@
---
phase: 07-socket-security
plan: 03
type: execute
wave: 2
depends_on: ["07-01"]
files_modified: []
autonomous: true
must_haves:
truths:
- "Exec API endpoint returns 403 Forbidden"
- "Build API endpoint returns 403 Forbidden"
- "Create (new container) API endpoint returns 403 Forbidden"
artifacts: []
key_links:
- from: "n8n/curl"
to: "docker-socket-proxy:2375"
via: "blocked endpoints"
pattern: "403 Forbidden"
---
<objective>
Verify that dangerous Docker APIs are blocked by the proxy.
Purpose: Confirm SEC-03 requirement - socket proxy blocks dangerous APIs (exec, create, build).
Output: Documented proof that blocked endpoints return 403 Forbidden.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/07-socket-security/07-CONTEXT.md
@.planning/phases/07-socket-security/07-RESEARCH.md
@.planning/phases/07-socket-security/07-01-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Test Blocked Endpoints Return 403</name>
<files>None (verification only)</files>
<action>
Test that the proxy correctly blocks dangerous Docker API endpoints.
**Test each blocked endpoint:**
1. **Exec (EXEC=0)** - Attempt to create an exec instance:
```
curl -s -o /dev/null -w "%{http_code}" -X POST 'http://docker-socket-proxy:2375/v1.47/containers/[any-container-id]/exec' -H "Content-Type: application/json" -d '{"Cmd":["echo","test"]}'
```
Expected: 403
2. **Build (BUILD=0)** - Attempt to build an image:
```
curl -s -o /dev/null -w "%{http_code}" -X POST 'http://docker-socket-proxy:2375/v1.47/build'
```
Expected: 403
3. **Commit (COMMIT=0)** - Attempt to commit a container:
```
curl -s -o /dev/null -w "%{http_code}" -X POST 'http://docker-socket-proxy:2375/v1.47/commit?container=[any-container-id]'
```
Expected: 403
**Note:** These tests should be run from inside the n8n container to verify the proxy is blocking correctly from the same network context.
If tests can't be run from n8n directly, document that proxy defaults block these endpoints (tecnativa proxy blocks by default when env vars are 0 or unset).
</action>
<verify>
All three blocked endpoints return HTTP 403 status code
</verify>
<done>SEC-03 verified: exec, build, and commit endpoints blocked with 403</done>
</task>
<task type="auto">
<name>Task 2: Document Security Configuration</name>
<files>None (documentation in SUMMARY)</files>
<action>
Document the security posture achieved:
**Allowed operations:**
- List containers (GET /containers/json)
- Inspect container (GET /containers/{id}/json)
- Start container (POST /containers/{id}/start)
- Stop container (POST /containers/{id}/stop)
- Restart container (POST /containers/{id}/restart)
- Remove container (DELETE /containers/{id})
- List images (GET /images/json)
- Inspect image (GET /images/{id}/json)
- Pull image (POST /images/create)
- Create container (POST /containers/create)
- Get logs (GET /containers/{id}/logs)
**Blocked operations:**
- Execute commands inside containers (POST /containers/{id}/exec)
- Build images (POST /build)
- Commit containers to images (POST /commit)
- Manage secrets (POST /secrets/*)
- Authentication operations
**Security benefit:**
Even if n8n is compromised, an attacker cannot:
- Execute arbitrary commands inside containers (no container escape)
- Build malicious images
- Access Docker secrets
</action>
<verify>
Documentation captured in plan summary
</verify>
<done>Security posture documented for SEC-03</done>
</task>
</tasks>
<verification>
1. Exec endpoint returns 403
2. Build endpoint returns 403
3. Commit endpoint returns 403
4. Security documentation complete
</verification>
<success_criteria>
- All three dangerous endpoints confirmed blocked
- Security posture documented
</success_criteria>
<output>
After completion, create `.planning/phases/07-socket-security/07-03-SUMMARY.md`
</output>