## Description
Extracts boundary installation and wrapper logic into a standalone
`coder/agent-firewall` module, decoupling it from `agentapi`.
### Why
Boundary is currently embedded inside `agentapi` (`scripts/boundary.sh`)
and duplicated in `claude-code`. This couples network isolation to the
AI/Tasks stack, but boundary is a general-purpose primitive — users
running a plain agent with no agentapi or tasks should be able to use it
too.
### What this adds
`registry/coder/modules/agent-firewall/` — a new first-class module
that:
* Installs boundary via one of three strategies:
1. `coder boundary` subcommand (default, zero-install)
2. Direct binary from release (`use_agent_firewall_directly = true`)
3. Compiled from source (`compile_agent_firewall_from_source = true`)
* Ships a comprehensive [default allowlist
config](registry/coder/modules/agent-firewall/config.yaml.tftpl)
(Anthropic, OpenAI, VCS, package managers, cloud platforms, etc.)
* Auto-fills the Coder deployment domain via
`data.coder_workspace.me.access_url`
* Supports inline config (`agent_firewall_config`) or external file
(`agent_firewall_config_path`), mutually exclusive with cross-variable
validation
* Creates a wrapper script at
`$HOME/.coder-modules/coder/agent-firewall/scripts/agent-firewall-wrapper.sh`
* Strips `CAP_NET_ADMIN` from the coder binary (copies to
`coder-no-caps`) to allow execution inside network namespaces without
`sys_admin`
* Supports `pre_install_script` / `post_install_script` hooks
* Exposes `agent_firewall_wrapper_path`, `agent_firewall_config_path`,
and `scripts` outputs for script coordination
* No env vars exported — everything is output-only
### Usage
```tf
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
}
```
Works standalone with any agent — no agentapi dependency required.
### Testing
* 8 Terraform plan tests (`agent-firewall.tftest.hcl`): default outputs,
compile from source, use directly, custom hooks, custom module
directory, inline config, external config path, mutual exclusion
validation
* TypeScript integration tests (`main.test.ts`): state verification,
coder subcommand happy path, inline config, config path skip, custom
hooks, env var absence, wrapper execution, idempotent installation
## Type of Change
- [X] New module
## Module Information
**Path:** `registry/coder/modules/agent-firewall` <br>**New version:**
`v0.0.1` <br>**Breaking change:** No
## Related Issues
Closes coder/registry#844
🤖 Generated by Coder Agents
---------
Co-authored-by: Jay Kumar <jay.kumar@coder.com>
| display_name | description | icon | verified | tags | |||||
|---|---|---|---|---|---|---|---|---|---|
| Agent Firewall | Configures agent-firewall for network isolation in Coder workspaces | ../../../../.icons/coder.svg | true |
|
Agent Firewall
Installs agent-firewall for network isolation in Coder workspaces.
This module:
- Installs agent-firewall (via coder subcommand, direct installation, or compilation from source)
- Creates a wrapper script at
$HOME/.coder-modules/coder/agent-firewall/scripts/agent-firewall-wrapper.sh - Writes a default agent-firewall config to
$HOME/.coder-modules/coder/agent-firewall/config/config.yaml(customizable) - Provides the wrapper path, config path, and script names via outputs
- Uses coder-utils and output
scriptsfor synchronization. https://registry.coder.com/modules/coder/coder-utils?tab=outputs
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
}
Examples
Use the agent_firewall_wrapper_path output to access the wrapper path and agent_firewall_config_path to access config path in Terraform and pass it to scripts that should run commands in network isolation.
With Claude Code
Use agent-firewall alongside the claude-code module to run Claude in a
network-isolated environment.
As an automated task
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
}
resource "coder_script" "claude_with_agent_firewall" {
agent_id = coder_agent.main.id
display_name = "Claude (Agent Firewall)"
run_on_start = true
script = <<-EOT
#!/bin/bash
set -e
coder exp sync want claude-agent-firewall \
${join(" ", module.agent-firewall.scripts)} \
${join(" ", module.claude-code.scripts)}
coder exp sync start claude-agent-firewall
"${module.agent-firewall.agent_firewall_wrapper_path}" --config="${module.agent-firewall.agent_firewall_config_path}" -- claude -p "Fix issue #840 from coder/coder"
EOT
}
As a Coder app
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
}
resource "coder_app" "claude_with_agent_firewall" {
agent_id = coder_agent.main.id
display_name = "Claude Code"
slug = "claude-code"
command = <<-EOT
#!/bin/bash
set -e
exec tmux new-session -A -s claude-code \
'"${module.agent-firewall.agent_firewall_wrapper_path}" --config="${module.agent-firewall.agent_firewall_config_path}" -- claude'
EOT
}
Configuration
The module ships with a comprehensive default config based on the Coder dogfood allowlist. It covers Anthropic services, OpenAI services, version control, package managers, container registries, cloud platforms, and common development tools.
The Coder deployment domain is automatically added to the allowlist using
data.coder_workspace.me.access_url.
By default the config is written to
$HOME/.coder-modules/coder/agent-firewall/config/config.yaml. You can
access the resolved path via the agent_firewall_config_path output. Override
it in two ways:
Inline config
Pass the full YAML content directly:
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
agent_firewall_config = <<-YAML
allowlist:
- domain=your-deployment.coder.com
- domain=api.anthropic.com
- domain=api.openai.com
log_dir: /tmp/agent_firewall_logs
proxy_port: 8087
log_level: warn
YAML
}
External config file
Point to an existing config file in the workspace. The module will not
write any config and the agent_firewall_config_path output will point to
your path. The file must exist on disk before agent-firewall starts.
module "agent-firewall" {
source = "registry.coder.com/coder/agent-firewall/coder"
version = "0.0.1"
agent_id = coder_agent.main.id
agent_firewall_config_path = "/workspace/my-agent-firewall-config.yaml"
}
Note:
agent_firewall_configandagent_firewall_config_pathare mutually exclusive, setting both produces a validation error.
See the Agent Firewall docs for the full config reference.