Connect every Coder workspace to 1Claw so AI coding agents get governed, least-privilege access to secrets—without baking credentials into images, repos, or dotfiles.
What problem this addresses. Regulated teams and security programs (financial services, defense, healthcare, critical infrastructure) need AI-assisted development without turning every IDE into a secret sprawl. Approvers look for strong isolation, provable controls, and auditability—not just “another API integration.”
What sits behind this module — the 1Claw platform
| Concern | How 1Claw addresses it |
|---|---|
| Secrets at rest | Vault secrets are protected with envelope encryption backed by cloud HSM / KMS (not flat files in your cluster). |
| AI traffic & sensitive operations | Shroud runs AI and signing workloads in a confidential-compute (TEE) environment, with inspection and policy enforcement—so model traffic and high-risk flows are not handled like a generic reverse proxy. |
| Who can access what | Policy-based, per-agent scoping: humans grant explicit path patterns and vault bindings; agents do not get org-wide or blanket secret access. JWTs carry derived scopes from those policies. |
| Accountability | Tamper-evident, append-style audit logging (integrity-chained events) for authentication, secret access, and administrative actions—supporting security monitoring and governance reviews. |
| Optional hardening | Enterprise tiers support customer-managed keys (CMEK) and MPC-style secret custody where your security model requires it. |
What this Terraform module does on top. It is the Coder-specific wiring: one module in your template provisions (or binds) a dedicated agent identity per workspace, injects credentials at runtime (not in the image), restricts access to the vaults and glob patterns you define, and— in Terraform-native mode—revokes identities and optionally deletes vaults when workspaces are destroyed. That maps cleanly to least privilege, separation of duties, and lifecycle governance narratives common in DoD and financial procurement conversations.
In one line for a security committee: 1Claw is the control plane for secrets and AI-adjacent operations; this module is how Coder workspaces enroll into that control plane with per-workspace identity and policy—without secrets in golden images.
- No secrets in code or images. API keys, database URLs, and tokens live in 1Claw’s vault and are delivered to agents through scoped credentials—not baked into your repo, container image, or Coder template.
- One module, three modes. Terraform-native provisioning, in-workspace bootstrap, or bring-your-own vault/agent—pick the lifecycle that matches your risk model.
- Works with standard MCP clients. Writes config for Cursor and Claude Code out of the box; agents use MCP streamable HTTP to 1Claw’s hosted MCP.
- Per-workspace agent identity. Each workspace gets its own agent, vault binding, and path-level policy—not shared long-lived keys across the fleet.
- Lifecycle-aware cleanup. In Terraform-native mode,
terraform destroydeletes the agent (revoking tokens) and can optionally remove the vault—reducing orphaned access and drift.
| Mode | You provide | Resources created | Cleanup on destroy | Best for |
|---|---|---|---|---|
| Terraform-native | master_api_key |
At terraform apply (before workspace boots) |
Automatic | Teams, CI/CD, ephemeral workspaces |
| Shell bootstrap | human_api_key |
At first workspace boot (inside the container) | Manual | Persistent workspaces, quick setup |
| Manual | vault_id + api_token |
You create them in the dashboard or CLI | Manual | Existing 1Claw users |
The cleanest path. Credentials are Terraform outputs, and destroy cleans up automatically.
1. Get your API key from the 1Claw dashboard under Settings > API Keys (the key starts with 1ck_).
2. Add the module to your Coder template:
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
master_api_key = var.oneclaw_key
}3. Push the template and start a workspace. The module:
- Authenticates with the 1Claw API using your
1ck_key - Creates a vault named
coder-<workspace>scoped to this workspace - Creates an agent with an
ocv_key and configurable token TTL - Grants the agent read/write access to the vault
- Passes the credentials to
coder_envand writes MCP config files - On
terraform destroy: deletes the agent (and optionally the vault)
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
master_api_key = var.oneclaw_key
provision_vault_name = "team-dev-vault"
provision_agent_name = "my-agent"
provision_policy_path = "dev/**" # restrict to the dev/ path
token_ttl_hours = 24 # agent JWT lives 24 hours
auto_destroy_vault = true # delete vault on terraform destroy
}output "vault_id" {
value = module.oneclaw.vault_id
}
output "scoped_token" {
value = module.oneclaw.scoped_token
sensitive = true
}
output "mode" {
value = module.oneclaw.provisioning_mode # "terraform_native"
}Use this when your workspaces are long-lived and you want credentials provisioned once, then cached inside the workspace for all future starts. Unlike Terraform-native mode, nothing is cleaned up on destroy — the vault and agent persist in your 1Claw account.
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
human_api_key = var.oneclaw_human_key
}On the first boot, a coder_script blocks login while it creates vault/agent/policy and caches credentials in ~/.1claw/bootstrap.json. On subsequent starts, the cached credentials are loaded instantly — the human key is never used again.
The 1ck_ key is delivered to the workspace as a sensitive coder_env variable (_ONECLAW_HUMAN_API_KEY), not templated into the bootstrap script body. This keeps the literal key out of /tmp/coder-agent.log and the Terraform state for the coder_script resource. The bootstrap script reads it from the environment, exchanges it for a JWT via curl --data-binary @- (so the key never hits argv / ps aux), then scrubs both the local variable and the inherited env var before handing control back to the workspace.
If you already have an agent API key (ocv_...) and vault ID from the 1Claw dashboard or CLI:
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
vault_id = var.oneclaw_vault_id
api_token = var.oneclaw_api_token
}terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.12"
}
}
}
variable "oneclaw_key" {
type = string
sensitive = true
description = "1Claw API key (1ck_...) from Dashboard > Settings > API Keys"
}
data "coder_provisioner" "me" {}
resource "coder_agent" "main" {
os = "linux"
arch = data.coder_provisioner.me.arch
dir = "/home/coder"
}
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
master_api_key = var.oneclaw_key
}
output "vault_id" {
value = module.oneclaw.vault_id
}
output "mcp_config" {
value = module.oneclaw.mcp_config_path
}module "cursor" {
source = "registry.coder.com/coder/cursor/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
}
module "oneclaw" {
source = "./packages/1claw-coder-workspace-module"
agent_id = coder_agent.main.id
master_api_key = var.oneclaw_key
}The 1Claw module merges its MCP server entry into any existing mcp.json so it won't overwrite configs written by other modules.
| Name | Type | Description |
|---|---|---|
agent_id |
string |
Coder agent ID to attach to |
| Name | Type | Default | Description |
|---|---|---|---|
master_api_key |
string (sensitive) |
"" |
Human 1ck_ API key — provisions vault + agent at apply time, cleans up on destroy |
token_ttl_hours |
number |
8 |
Agent JWT TTL in hours (0 = platform default) |
auto_destroy_vault |
bool |
false |
Delete the vault on terraform destroy (not just the agent) |
provision_vault_name |
string |
"" |
Vault name (defaults to coder-<workspace>) |
provision_agent_name |
string |
"" |
Agent name (defaults to coder-<workspace>-agent) |
provision_policy_path |
string |
** |
Secret path glob for the access policy |
| Name | Type | Default | Description |
|---|---|---|---|
human_api_key |
string (sensitive) |
"" |
Human 1ck_ API key — triggers in-workspace provisioning on first boot |
bootstrap_vault_name |
string |
coder-workspace |
Name for the auto-created vault |
bootstrap_agent_name |
string |
"" |
Name for the auto-created agent (defaults to coder-<workspace>) |
bootstrap_policy_path |
string |
** |
Secret path glob for the auto-created access policy |
| Name | Type | Default | Description |
|---|---|---|---|
vault_id |
string |
"" |
1Claw vault UUID |
api_token |
string (sensitive) |
"" |
Agent API key (ocv_...) |
agent_id_1claw |
string |
"" |
1Claw agent UUID (auto-resolved from key if omitted) |
| Name | Type | Default | Description |
|---|---|---|---|
mcp_host |
string |
https://mcp.1claw.xyz/mcp |
MCP server URL |
base_url |
string |
https://api.1claw.xyz |
Vault API base URL |
install_cursor_config |
bool |
true |
Write Cursor MCP config (~/.cursor/mcp.json) |
install_claude_config |
bool |
true |
Write Claude Code MCP config (~/.config/claude/mcp.json) |
cursor_config_path |
string |
$HOME/.cursor/mcp.json |
Custom Cursor config path |
claude_config_path |
string |
$HOME/.config/claude/mcp.json |
Custom Claude config path |
icon |
string |
/icon/key.svg |
Script icon in Coder UI |
order |
number |
null |
UI ordering position |
| Name | Description |
|---|---|
mcp_config_path |
Primary MCP config file path (Cursor) |
claude_config_path |
Claude Code config path (empty if disabled) |
vault_id |
The vault ID configured for this workspace |
scoped_token |
Agent API key (ocv_...) — only populated in Terraform-native mode (sensitive) |
agent_id_1claw |
The 1Claw agent UUID for this workspace |
provisioning_mode |
Active mode: terraform_native, bootstrap, or manual |
- On apply:
null_resource.oneclaw_provisionruns alocal-execprovisioner that calls the 1Claw API — authenticates, creates a vault, creates an agent with a scoped token, and creates an access policy. Credentials are saved to.provision-state.json(chmod 600, gitignored). - Wiring: The module reads the state file via
file()+jsondecode()and passesvault_idandagent_api_keytocoder_envand the MCP setup script. - On destroy: A destroy-time provisioner on the same resource re-authenticates with the master key, deletes the agent (which revokes all its tokens), and optionally deletes the vault if
auto_destroy_vault = true.
coder_script.oneclaw_bootstrapruns inside the workspace on first boot, exchanges the human key for a JWT, creates vault/agent/policy, and caches credentials to~/.1claw/bootstrap.json.coder_script.oneclaw_mcp_setupwaits for the bootstrap to complete, reads cached credentials, and writes MCP config files.
coder_envresources setONECLAW_VAULT_IDandONECLAW_AGENT_API_KEYfrom the provided variables.coder_script.oneclaw_mcp_setupreads them and writes MCP config files.
These controls complement the platform properties in For security and compliance reviewers (HSM-backed vault, TEE-backed Shroud, audit chain, policy-scoped agents).
- Provisioning secrets stay off workloads. The human
1ck_key is Terraform-sensitive, used only for provisioning API calls, and — in bootstrap mode — injected at runtime as a sensitivecoder_env(_ONECLAW_HUMAN_API_KEY) rather than templated into the script body, so it does not land in/tmp/coder-agent.log, the renderedcoder_script, or argv (ps aux). The bootstrap script scrubs the key from the environment after the one-time JWT exchange. - Least-privilege agent identity. Each workspace agent is bound to the intended vault(s) and path glob via policy—no implicit org-wide secret access.
- Short-lived agent JWTs. Configurable TTL (
token_ttl_hours) limits blast radius if a token is exposed; destruction revokes the agent and its tokens in Terraform-native mode. - Lifecycle & data retention.
terraform destroyremoves the agent (and optionally the vault withauto_destroy_vault) to support deprovisioning and data-minimization expectations. - Local secret hygiene. MCP configs and bootstrap cache use
chmod 600; Terraform provisioner state (.provision-state.json) is restricted and gitignored. - Non-destructive MCP merge. Existing MCP server entries are preserved when adding 1Claw.
- No credential baking. Agent credentials are injected at runtime, not in container build layers.
For organization-wide assurance (SOC 2, ISO, customer DPAs, etc.), rely on 1Claw’s published security materials and your contractual terms; this module is the integration surface for Coder.
The module ships two kinds of checks: shell tests for scripts/setup.sh (no Coder cluster, no 1Claw API) and an optional Terraform validate for the example root module wiring.
- Bash and Python 3 (used by
tests/test_setup.shfor JSON checks) - Terraform ≥ 1.4 (only if you run
terraform validateundertests/)
From the monorepo root:
cd packages/1claw-coder-workspace-module
bash tests/test_setup.shThis exercises scripts/setup.sh with a temporary HOME, simulating the same templatefile substitution Coder uses. It covers:
| Area | What is asserted |
|---|---|
| Fresh install | Cursor + Claude MCP JSON, 600 permissions, correct URL and headers |
| Merge | Existing mcpServers entries are preserved when adding 1claw |
| Stale entry | An old 1claw block is replaced with new vault/token |
| Malformed JSON | Invalid existing file is repaired and merged |
| Dual-target | Both Cursor and Claude paths when both enabled |
| Skip targets | Claude file omitted when Claude install is disabled |
| Token edge cases | Special characters in bearer tokens |
| Bootstrap | Loading ~/.1claw/bootstrap.json when env token is empty; skip when no creds; chmod 600 on bootstrap file; direct env vars override bootstrap |
The script prints per-test PASS/FAIL and exits non-zero if anything fails.
The tests/ directory contains a minimal Coder + module example (manual mode by default). After terraform init:
cd packages/1claw-coder-workspace-module/tests
terraform init
terraform validateUse terraform plan only if you intend to apply against a real Coder workspace; it is not required for CI-style validation.
Apache-2.0