Skip to content

Commit dc4abd4

Browse files
committed
feat(claude-code): first-class anthropic_base_url, use_bedrock, use_vertex inputs
Rebased onto post-#861 main. - New use_bedrock and use_vertex bool inputs that set CLAUDE_CODE_USE_BEDROCK=1 / CLAUDE_CODE_USE_VERTEX=1 via coder_env. Mutually exclusive with each other and with enable_ai_gateway. - New anthropic_base_url string input. The existing coder_env.anthropic_base_url resource (previously AI Gateway only) is widened to also fire when this is set; AI Gateway keeps precedence for the value. Mutually exclusive with enable_ai_gateway. - configure_standalone_mode now recognizes use_bedrock / use_vertex / anthropic_base_url as valid auth paths: prints a clear backend message and proceeds to write the onboarding-bypass keys instead of printing the misleading 'No authentication configured' note and returning early. - README: Bedrock and Vertex sections rewritten around the new inputs, leading with attached IAM role / Workload Identity over static credentials. New custom-API-gateway section. Prerequisites and mutual-exclusion caution updated. - Tests: 7 new terraform-test runs (env assertions + 4 expect_failures for mutual exclusion); 3 new bun tests. Closes coder/coder#17402 Closes coder/coder#21835
1 parent 4ca251f commit dc4abd4

5 files changed

Lines changed: 307 additions & 102 deletions

File tree

registry/coder/modules/claude-code/README.md

Lines changed: 52 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Install and configure the [Claude Code](https://docs.anthropic.com/en/docs/agent
1313
```tf
1414
module "claude-code" {
1515
source = "registry.coder.com/coder/claude-code/coder"
16-
version = "5.2.0"
16+
version = "5.3.0"
1717
agent_id = coder_agent.main.id
1818
anthropic_api_key = "xxxx-xxxxx-xxxx"
1919
}
@@ -29,6 +29,9 @@ Provide exactly one authentication method:
2929
- **Anthropic API key**: get one from the [Anthropic Console](https://console.anthropic.com/dashboard) and pass it as `anthropic_api_key`.
3030
- **Claude.ai OAuth token** (Pro, Max, or Enterprise accounts): generate one by running `claude setup-token` locally and pass it as `claude_code_oauth_token`.
3131
- **Coder AI Gateway** (Coder Premium, Coder >= 2.30.0): set `enable_ai_gateway = true`. The module authenticates against the gateway using the workspace owner's session token. Do not combine with `anthropic_api_key` or `claude_code_oauth_token`.
32+
- **Amazon Bedrock**: set `use_bedrock = true`. Authentication uses the workspace's AWS credential chain. See [Usage with AWS Bedrock](#usage-with-aws-bedrock).
33+
- **Google Vertex AI**: set `use_vertex = true`. Authentication uses Google Application Default Credentials inside the workspace. See [Usage with Google Vertex AI](#usage-with-google-vertex-ai).
34+
- **Custom API gateway**: set `anthropic_base_url` to a self-hosted gateway that speaks the Anthropic Messages API. See [Usage with a custom API gateway](#usage-with-a-custom-api-gateway).
3235

3336
## workdir
3437

@@ -47,7 +50,7 @@ locals {
4750
4851
module "claude-code" {
4952
source = "registry.coder.com/coder/claude-code/coder"
50-
version = "5.2.0"
53+
version = "5.3.0"
5154
agent_id = coder_agent.main.id
5255
workdir = local.claude_workdir
5356
anthropic_api_key = "xxxx-xxxxx-xxxx"
@@ -78,7 +81,7 @@ resource "coder_app" "claude" {
7881
```tf
7982
module "claude-code" {
8083
source = "registry.coder.com/coder/claude-code/coder"
81-
version = "5.2.0"
84+
version = "5.3.0"
8285
agent_id = coder_agent.main.id
8386
workdir = "/home/coder/project"
8487
enable_ai_gateway = true
@@ -102,7 +105,7 @@ The `managed_settings` input writes a policy file to `/etc/claude-code/managed-s
102105
```tf
103106
module "claude-code" {
104107
source = "registry.coder.com/coder/claude-code/coder"
105-
version = "5.2.0"
108+
version = "5.3.0"
106109
agent_id = coder_agent.main.id
107110
workdir = "/home/coder/project"
108111
anthropic_api_key = "xxxx-xxxxx-xxxx"
@@ -129,7 +132,7 @@ This example shows version pinning, a pre-installed binary path, a custom model,
129132
```tf
130133
module "claude-code" {
131134
source = "registry.coder.com/coder/claude-code/coder"
132-
version = "5.2.0"
135+
version = "5.3.0"
133136
agent_id = coder_agent.main.id
134137
workdir = "/home/coder/project"
135138
@@ -193,7 +196,7 @@ Downstream `coder_script` resources can wait for this module's install pipeline
193196
```tf
194197
module "claude-code" {
195198
source = "registry.coder.com/coder/claude-code/coder"
196-
version = "5.2.0"
199+
version = "5.3.0"
197200
agent_id = coder_agent.main.id
198201
workdir = "/home/coder/project"
199202
anthropic_api_key = "xxxx-xxxxx-xxxx"
@@ -218,39 +221,31 @@ resource "coder_script" "post_claude" {
218221
219222
### Usage with AWS Bedrock
220223

221-
#### Prerequisites
222-
223-
AWS account with Bedrock access, Claude models enabled in Bedrock console, and appropriate IAM permissions.
224-
225-
Configure Claude Code to use AWS Bedrock for accessing Claude models through your AWS infrastructure.
224+
Set `use_bedrock = true` to route Claude Code through Amazon Bedrock. The module sets `CLAUDE_CODE_USE_BEDROCK=1` and skips Anthropic API key setup; authentication is handled by the AWS SDK [credential chain](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html) inside the workspace.
226225

227226
```tf
228-
resource "coder_env" "bedrock_use" {
229-
agent_id = coder_agent.main.id
230-
name = "CLAUDE_CODE_USE_BEDROCK"
231-
value = "1"
227+
module "claude-code" {
228+
source = "registry.coder.com/coder/claude-code/coder"
229+
version = "5.3.0"
230+
agent_id = coder_agent.main.id
231+
workdir = "/home/coder/project"
232+
use_bedrock = true
233+
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
232234
}
233235
234236
resource "coder_env" "aws_region" {
235237
agent_id = coder_agent.main.id
236238
name = "AWS_REGION"
237-
value = "us-east-1" # Choose your preferred region
239+
value = "us-east-1"
238240
}
241+
```
239242

240-
# Option 1: Using AWS credentials
241-
242-
variable "aws_access_key_id" {
243-
type = string
244-
description = "Your AWS access key ID. Create this in the AWS IAM console under 'Security credentials'."
245-
sensitive = true
246-
}
243+
> [!TIP]
244+
> Prefer attaching an IAM role to the workspace (EKS [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html), EC2 instance profile, or ECS task role) over passing static `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` through Terraform variables. Claude Code picks up the role via the standard AWS credential chain with no additional configuration.
247245
248-
variable "aws_secret_access_key" {
249-
type = string
250-
description = "Your AWS secret access key. This is shown once when you create an access key in the AWS IAM console."
251-
sensitive = true
252-
}
246+
If you cannot use an attached role, set static credentials via `coder_env` resources:
253247

248+
```tf
254249
resource "coder_env" "aws_access_key_id" {
255250
agent_id = coder_agent.main.id
256251
name = "AWS_ACCESS_KEY_ID"
@@ -262,52 +257,33 @@ resource "coder_env" "aws_secret_access_key" {
262257
name = "AWS_SECRET_ACCESS_KEY"
263258
value = var.aws_secret_access_key
264259
}
260+
```
265261

266-
# Option 2: Using Bedrock API key (simpler)
267-
268-
variable "aws_bearer_token_bedrock" {
269-
type = string
270-
description = "Your AWS Bedrock bearer token. This provides access to Bedrock without needing separate access key and secret key."
271-
sensitive = true
272-
}
262+
Or use a [Bedrock API key](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html) instead of access-key/secret-key:
273263

264+
```tf
274265
resource "coder_env" "bedrock_api_key" {
275266
agent_id = coder_agent.main.id
276267
name = "AWS_BEARER_TOKEN_BEDROCK"
277268
value = var.aws_bearer_token_bedrock
278269
}
279-
280-
module "claude-code" {
281-
source = "registry.coder.com/coder/claude-code/coder"
282-
version = "5.2.0"
283-
agent_id = coder_agent.main.id
284-
workdir = "/home/coder/project"
285-
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
286-
}
287270
```
288271

289272
> [!NOTE]
290-
> For additional Bedrock configuration options (model selection, token limits, region overrides, etc.), see the [Claude Code Bedrock documentation](https://docs.claude.com/en/docs/claude-code/amazon-bedrock).
273+
> Prerequisites: AWS account with Bedrock access, Claude models enabled in the Bedrock console, and IAM permission `bedrock:InvokeModelWithResponseStream`. For additional configuration (token limits, region overrides), see the [Claude Code Bedrock documentation](https://docs.claude.com/en/docs/claude-code/amazon-bedrock).
291274
292275
### Usage with Google Vertex AI
293276

294-
#### Prerequisites
295-
296-
GCP project with Vertex AI API enabled, Claude models enabled through Model Garden, service account with Vertex AI permissions, and appropriate IAM permissions (Vertex AI User role).
297-
298-
Configure Claude Code to use Google Vertex AI for accessing Claude models through Google Cloud Platform.
277+
Set `use_vertex = true` to route Claude Code through Google Vertex AI. The module sets `CLAUDE_CODE_USE_VERTEX=1` and skips Anthropic API key setup; authentication uses [Google Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials) inside the workspace.
299278

300279
```tf
301-
variable "vertex_sa_json" {
302-
type = string
303-
description = "The complete JSON content of your Google Cloud service account key file. Create a service account in the GCP Console under 'IAM & Admin > Service Accounts', then create and download a JSON key. Copy the entire JSON content into this variable."
304-
sensitive = true
305-
}
306-
307-
resource "coder_env" "vertex_use" {
308-
agent_id = coder_agent.main.id
309-
name = "CLAUDE_CODE_USE_VERTEX"
310-
value = "1"
280+
module "claude-code" {
281+
source = "registry.coder.com/coder/claude-code/coder"
282+
version = "5.3.0"
283+
agent_id = coder_agent.main.id
284+
workdir = "/home/coder/project"
285+
use_vertex = true
286+
model = "claude-sonnet-4@20250514"
311287
}
312288
313289
resource "coder_env" "vertex_project_id" {
@@ -321,52 +297,30 @@ resource "coder_env" "cloud_ml_region" {
321297
name = "CLOUD_ML_REGION"
322298
value = "global"
323299
}
300+
```
324301

325-
resource "coder_env" "vertex_sa_json" {
326-
agent_id = coder_agent.main.id
327-
name = "VERTEX_SA_JSON"
328-
value = var.vertex_sa_json
329-
}
330-
331-
resource "coder_env" "google_application_credentials" {
332-
agent_id = coder_agent.main.id
333-
name = "GOOGLE_APPLICATION_CREDENTIALS"
334-
value = "/tmp/gcp-sa.json"
335-
}
336-
337-
module "claude-code" {
338-
source = "registry.coder.com/coder/claude-code/coder"
339-
version = "5.2.0"
340-
agent_id = coder_agent.main.id
341-
workdir = "/home/coder/project"
342-
model = "claude-sonnet-4@20250514"
343-
344-
pre_install_script = <<-EOT
345-
#!/bin/bash
346-
# Write the service account JSON to a file
347-
echo "$VERTEX_SA_JSON" > /tmp/gcp-sa.json
348-
349-
# Install prerequisite packages
350-
sudo apt-get update
351-
sudo apt-get install -y apt-transport-https ca-certificates gnupg curl
302+
> [!TIP]
303+
> Prefer GKE [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) or an attached service account over shipping a service-account JSON key through Terraform. Claude Code picks up Application Default Credentials automatically. If you must use a key file, mount it and set `GOOGLE_APPLICATION_CREDENTIALS` via a `coder_env` resource.
352304
353-
# Add Google Cloud public key
354-
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
305+
> [!NOTE]
306+
> Prerequisites: GCP project with Vertex AI API enabled, Claude models enabled through Model Garden, and the `Vertex AI User` role on the workspace identity. For additional configuration, see the [Claude Code Vertex AI documentation](https://docs.claude.com/en/docs/claude-code/google-vertex-ai).
355307
356-
# Add Google Cloud SDK repo to apt sources
357-
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list
308+
### Usage with a custom API gateway
358309

359-
# Update and install the Google Cloud SDK
360-
sudo apt-get update && sudo apt-get install -y google-cloud-cli
310+
Set `anthropic_base_url` to point Claude Code at a self-hosted gateway or proxy that speaks the Anthropic Messages API. The module sets `ANTHROPIC_BASE_URL` and skips its built-in Anthropic authentication setup; provide whatever credentials your gateway requires via separate `coder_env` resources.
361311

362-
# Authenticate gcloud with the service account
363-
gcloud auth activate-service-account --key-file=/tmp/gcp-sa.json
364-
EOT
312+
```tf
313+
module "claude-code" {
314+
source = "registry.coder.com/coder/claude-code/coder"
315+
version = "5.3.0"
316+
agent_id = coder_agent.main.id
317+
workdir = "/home/coder/project"
318+
anthropic_base_url = "https://llm-gateway.example.com/anthropic"
365319
}
366320
```
367321

368-
> [!NOTE]
369-
> For additional Vertex AI configuration options (model selection, token limits, region overrides, etc.), see the [Claude Code Vertex AI documentation](https://docs.claude.com/en/docs/claude-code/google-vertex-ai).
322+
> [!CAUTION]
323+
> `anthropic_base_url` is mutually exclusive with `enable_ai_gateway`, which sets `ANTHROPIC_BASE_URL` to the Coder AI Gateway endpoint. `use_bedrock` and `use_vertex` are likewise mutually exclusive with `enable_ai_gateway` and with each other.
370324
371325
### Telemetry export (OpenTelemetry)
372326

@@ -377,7 +331,7 @@ The module automatically tags every span and metric with `coder.workspace_id`, `
377331
```tf
378332
module "claude-code" {
379333
source = "registry.coder.com/coder/claude-code/coder"
380-
version = "5.2.0"
334+
version = "5.3.0"
381335
agent_id = coder_agent.main.id
382336
workdir = "/home/coder/project"
383337
anthropic_api_key = "xxxx-xxxxx-xxxx"

registry/coder/modules/claude-code/main.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,4 +518,70 @@ describe("claude-code", async () => {
518518
expect(coderEnvVars["OTEL_EXPORTER_OTLP_HEADERS"]).toBeUndefined();
519519
expect(coderEnvVars["OTEL_RESOURCE_ATTRIBUTES"]).toBeUndefined();
520520
});
521+
522+
test("use-bedrock-no-api-key", async () => {
523+
const { id, coderEnvVars, scripts } = await setup({
524+
moduleVariables: {
525+
use_bedrock: "true",
526+
},
527+
});
528+
expect(coderEnvVars["CLAUDE_CODE_USE_BEDROCK"]).toBe("1");
529+
expect(coderEnvVars["ANTHROPIC_API_KEY"]).toBeUndefined();
530+
531+
await runScripts(id, scripts, coderEnvVars);
532+
const installLog = await readFileContainer(
533+
id,
534+
"/home/coder/.coder-modules/coder/claude-code/logs/install.log",
535+
);
536+
expect(installLog).toContain(
537+
"Using Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK=1)",
538+
);
539+
expect(installLog).not.toContain("No authentication configured");
540+
expect(installLog).toContain("Standalone mode configured successfully");
541+
542+
// Onboarding bypass should still be written so the CLI starts headlessly.
543+
const claudeConfig = await readFileContainer(
544+
id,
545+
"/home/coder/.claude.json",
546+
);
547+
expect(JSON.parse(claudeConfig).hasCompletedOnboarding).toBe(true);
548+
});
549+
550+
test("use-vertex-no-api-key", async () => {
551+
const { id, coderEnvVars, scripts } = await setup({
552+
moduleVariables: {
553+
use_vertex: "true",
554+
},
555+
});
556+
expect(coderEnvVars["CLAUDE_CODE_USE_VERTEX"]).toBe("1");
557+
558+
await runScripts(id, scripts, coderEnvVars);
559+
const installLog = await readFileContainer(
560+
id,
561+
"/home/coder/.coder-modules/coder/claude-code/logs/install.log",
562+
);
563+
expect(installLog).toContain(
564+
"Using Google Vertex AI (CLAUDE_CODE_USE_VERTEX=1)",
565+
);
566+
expect(installLog).not.toContain("No authentication configured");
567+
});
568+
569+
test("anthropic-base-url-custom", async () => {
570+
const baseUrl = "https://llm-gateway.example.com/anthropic";
571+
const { id, coderEnvVars, scripts } = await setup({
572+
moduleVariables: {
573+
anthropic_base_url: baseUrl,
574+
},
575+
});
576+
expect(coderEnvVars["ANTHROPIC_BASE_URL"]).toBe(baseUrl);
577+
578+
await runScripts(id, scripts, coderEnvVars);
579+
const installLog = await readFileContainer(
580+
id,
581+
"/home/coder/.coder-modules/coder/claude-code/logs/install.log",
582+
);
583+
expect(installLog).toContain("Using custom ANTHROPIC_BASE_URL");
584+
expect(installLog).toContain(baseUrl);
585+
expect(installLog).not.toContain("No authentication configured");
586+
});
521587
});

0 commit comments

Comments
 (0)