fix: shrink workspace privilege and egress surface - #180
Conversation
Three independent problems, all of which weaken or complicate network
enforcement on workspace pods.
realworld ran its workspace container with privileged = true and
allow_privilege_escalation = true. Neither is needed: its image
(coder-aienv) ships no container runtime, and nothing in the template or
any of its modules uses sudo. memorycard runs the same image with both
set to false. A privileged container holds host capabilities and could in
principle tamper with the eBPF maps backing pod network policy, so this
also removed the main caveat on any egress-lockdown claim for the
template. devbox, datasci and universal-sandbox keep privileged: their
image installs podman and symlinks docker to it.
memorycard and realworld passed use_cached = true to vscode-web with no
install_prefix. The module resolves ${INSTALL_PREFIX}/bin/code-server and
falls back to /tmp/vscode-web, which is empty on a fresh pod, so both
templates re-downloaded the VS Code server from Microsoft on every start.
The image already bakes it into /usr/local/lib/vscode-web and symlinks
/usr/local/bin/code-server, so install_prefix = "/usr/local" makes the
cache hit. realworld's launch script hardcoded the old /tmp path, which
would have broken once the prefix moved, so it now calls code-server off
PATH as memorycard already did.
devbox's Boundary post-install script executed the config path as a
command and chmod'd the file before the heredoc created it. Under
/bin/sh with no set -e both failed silently, leaving the config at mode
644. Reordered so the file is written first and then restricted.
782e41e to
6a66832
Compare
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/a47a5bf0-a2c1-4323-98b6-ef5f53bf90a8 |
|
✅ Agent Validation PASSED for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/24e350f6-85f0-44b3-bce2-ecc3eeef39ad |
|
🔍 Build Failure Analysis for template
|
|
✅ Agent Validation PASSED for template
|
|
🔍 Build Failure Analysis for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/f780450b-7589-48a3-a5a9-6cc732a885d7 |
|
🔍 Build Failure Analysis for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/25f6b452-dbb6-4f5e-a5b4-d6d5dcea7c48 |
|
✅ Agent Validation PASSED for template
|
|
✅ Agent Validation PASSED for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/8a7eb680-b721-433c-87a4-bfb836949f7c |
|
✅ Agent Validation PASSED for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/b615cf21-072c-4c58-88ac-aa99903669ff |
|
✅ Agent Validation PASSED for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/ee682dbd-91c7-424b-97ea-33e0e4cf468c |
|
✅ Agent Validation PASSED for template
|
|
Coder Agents Chat: agent finished or is awaiting input Chat: https://ai.coder.com/agents/479974c2-feae-474c-b074-7ed02cb5a242 |
|
✅ Agent Validation PASSED for template
|
Stacked on #179. Prerequisites for adding Cilium egress policy: each of these
either weakens the enforcement claim or enlarges the allowlist Cilium has to permit.
1. Drop unnecessary
privilegedfromrealworldrealworldran its workspace container withprivileged = trueandallow_privilege_escalation = true. Verified unnecessary:public.ecr.aws/f7a1d7a4/coder-aienv, installs no container runtime(
grep podman\|docker images/aws/coder-aienv/Dockerfile.noble→ nothing)sudoanywhere in the template, and none in any of its six registry modulesmemorycardruns the same image with both set tofalse, in productionA privileged container holds host capabilities and can in principle manipulate the
eBPF maps that back pod network policy, so this was the main caveat on any
egress-lockdown claim for the template.
memorycardwas previously the onlydefensible one; now it is two.
Not changed:
devbox,datascianduniversal-sandboxkeepprivileged.Their image (
coder-aidev) doesapt install podman podman-composeand symlinksdocker→podman, anduniversal-sandbox's MongoDB preset runssudo apt-get install, whichallow_privilege_escalation = falsewould break by settingno_new_privs. Also unchanged:envbox(needs it) and selenium'sexectracesidecar.2.
install_prefixon vscode-web: stop re-downloading VS Code every startmemorycardandrealworldsetuse_cached = truewith noinstall_prefix.The module resolves
VSCODE_WEB="${INSTALL_PREFIX}/bin/code-server"and defaultsINSTALL_PREFIXto/tmp/vscode-web, which is empty on a fresh pod, so the cachecheck at
run.sh:83misses and it downloads the server fromvscode.download.prss.microsoft.comon every workspace start.The image already bakes it in and symlinks
/usr/local/bin/code-server, soinstall_prefix = "/usr/local"makes the cache hit, matchingdevboxanddatasci.Also fixes
realworld's launch script, which hardcoded/tmp/vscode-web/bin/code-server --install-extensionand would have broken as soonas the prefix moved. It now calls
code-serveroff PATH, asmemorycardalready did.This matters because the cached path
exit 0s before the module's own extensioninstall, so that loop is the real extension installer.
Removes two Microsoft CDN domains from the eventual allowlist, and cuts startup time.
3.
devboxBoundary config write bugUnder
#!/bin/shwith noset -eboth failed silently, so the Boundary allowlistended up mode 644 instead of 600. Reordered: write, then restrict. This is the L7
half of the enforcement design, so its config needs to actually be protected.
Verification
terraform fmt -check -recursiveclean;terraform validateSuccess on all three.CI builds a real workspace per template, so an agent that fails to start after
losing
privilegedor after thecode-serverpath change will fail the check.Rollback is re-activating the previous template version, per
--activate=false.🤖 Generated with Claude Code