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:
@@ -40,6 +40,13 @@ Plans:
|
||||
|
||||
**Requirements:** SEC-01, SEC-02, SEC-03, SEC-04
|
||||
|
||||
**Plans:** 3 plans
|
||||
|
||||
Plans:
|
||||
- [ ] 07-01-PLAN.md — Deploy docker-socket-proxy via Unraid CA
|
||||
- [ ] 07-02-PLAN.md — Migrate workflow curl commands to proxy
|
||||
- [ ] 07-03-PLAN.md — Verify dangerous APIs are blocked
|
||||
|
||||
**Success Criteria:**
|
||||
1. Socket proxy container runs on internal network with Docker socket mounted
|
||||
2. n8n container connects to proxy via TCP instead of mounting docker.sock directly
|
||||
@@ -101,8 +108,8 @@ Plans:
|
||||
|
||||
| Phase | Name | Requirements | Status |
|
||||
|-------|------|--------------|--------|
|
||||
| 6 | n8n API Access | API-01, API-02, API-03, API-04 | Complete ✓ |
|
||||
| 7 | Socket Security | SEC-01, SEC-02, SEC-03, SEC-04 | Pending |
|
||||
| 6 | n8n API Access | API-01, API-02, API-03, API-04 | Complete |
|
||||
| 7 | Socket Security | SEC-01, SEC-02, SEC-03, SEC-04 | Planned |
|
||||
| 8 | Inline Keyboard Infrastructure | KEY-01, KEY-02, KEY-03, KEY-04, KEY-05 | Pending |
|
||||
| 9 | Batch Operations | BAT-01, BAT-02, BAT-03, BAT-04, BAT-05, BAT-06 | Pending |
|
||||
| 10 | Polish & Audit | UNR-01, ENV-01, ENV-02 | Pending |
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user