feat: support multiple agents with shared instance-identity auth (#24325)

> This PR was authored by Mux on behalf of Mike.

## Summary

Adds support for multiple peer root workspace agents sharing the same
`auth_instance_id`, so AWS, Azure, and GCP instance-identity auth can
issue the correct session token for a selected agent instead of assuming
a
single root agent per instance.

## Problem

When a Terraform template attaches two or more `coder_agent` resources
(with `auth = "aws-instance-identity"`) to a single compute instance,
every agent shares the same cloud instance ID. The existing singular
lookup picks whichever agent was created most recently, silently
ignoring
the others.

## Solution

Introduce an optional pre-auth agent selector (`CODER_AGENT_NAME`) and
make the server-side lookup ambiguity-aware.

**Database layer:**
- `GetWorkspaceAgentsByInstanceID` (`:many`): returns all matching root
  agents for an instance ID.
- `GetWorkspaceAgentByInstanceIDAndName` (`:one`): returns the named
root
  agent for disambiguation.

**SDK and CLI:**
- `agent_name` field added to AWS, Azure, and GCP request structs
  (`omitempty` for backward compatibility).
- `CODER_AGENT_NAME` env var and `--agent-name` flag wired into the
agent
  bootstrap before instance-identity auth runs.

**Server handler (`handleAuthInstanceID`):**
- When `agent_name` is present: direct lookup by (instance ID, name).
- When absent: legacy lookup, then resource-scoped ambiguity check.
  Returns 409 with available agent names if multiple root agents match.
- Whitespace-only names are trimmed and treated as unspecified.
- Sub-agents remain excluded (`parent_id IS NULL` filter).

**Verification template:**
- `examples/templates/aws-multi-agent/` provisions one EC2 instance with
  two agents (`main` and `dev`), both using instance-identity auth with
  `CODER_AGENT_NAME` set in the cloud-init user data.

## Backward compatibility

Existing single-agent deployments work unchanged. The `agent_name` field
is optional with `omitempty`, and the unnamed path preserves today's
behavior when only one root agent matches.
This commit is contained in:
Michael Suchacz
2026-04-16 13:59:09 +02:00
committed by GitHub
parent 1cf0354f72
commit e5707a13d6
29 changed files with 1563 additions and 286 deletions
+12 -9
View File
@@ -58,6 +58,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/aws-instance-identi
```json
{
"agent_name": "string",
"document": "string",
"signature": "string"
}
@@ -65,9 +66,9 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/aws-instance-identi
### Parameters
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------------------------------------------|----------|-------------------------|
| `body` | body | [agentsdk.AWSInstanceIdentityToken](schemas.md#agentsdkawsinstanceidentitytoken) | true | Instance identity token |
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------|
| `body` | body | [agentsdk.AWSInstanceIdentityToken](schemas.md#agentsdkawsinstanceidentitytoken) | true | Instance identity token. The optional agent_name field disambiguates when multiple agents share the same instance ID. |
### Example responses
@@ -105,6 +106,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/azure-instance-iden
```json
{
"agent_name": "string",
"encoding": "string",
"signature": "string"
}
@@ -112,9 +114,9 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/azure-instance-iden
### Parameters
| Name | In | Type | Required | Description |
|--------|------|--------------------------------------------------------------------------------------|----------|-------------------------|
| `body` | body | [agentsdk.AzureInstanceIdentityToken](schemas.md#agentsdkazureinstanceidentitytoken) | true | Instance identity token |
| Name | In | Type | Required | Description |
|--------|------|--------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------|
| `body` | body | [agentsdk.AzureInstanceIdentityToken](schemas.md#agentsdkazureinstanceidentitytoken) | true | Instance identity token. The optional agent_name field disambiguates when multiple agents share the same instance ID. |
### Example responses
@@ -152,15 +154,16 @@ curl -X POST http://coder-server:8080/api/v2/workspaceagents/google-instance-ide
```json
{
"agent_name": "string",
"json_web_token": "string"
}
```
### Parameters
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------------------------------------------------|----------|-------------------------|
| `body` | body | [agentsdk.GoogleInstanceIdentityToken](schemas.md#agentsdkgoogleinstanceidentitytoken) | true | Instance identity token |
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------|
| `body` | body | [agentsdk.GoogleInstanceIdentityToken](schemas.md#agentsdkgoogleinstanceidentitytoken) | true | Instance identity token. The optional agent_name field disambiguates when multiple agents share the same instance ID. |
### Example responses
+17 -11
View File
@@ -4,6 +4,7 @@
```json
{
"agent_name": "string",
"document": "string",
"signature": "string"
}
@@ -11,10 +12,11 @@
### Properties
| Name | Type | Required | Restrictions | Description |
|-------------|--------|----------|--------------|-------------|
| `document` | string | true | | |
| `signature` | string | true | | |
| Name | Type | Required | Restrictions | Description |
|--------------|--------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `agent_name` | string | false | | Agent name optionally selects a specific agent when multiple agents share the same instance identity. An empty string is treated as unspecified. |
| `document` | string | true | | |
| `signature` | string | true | | |
## agentsdk.AuthenticateResponse
@@ -34,6 +36,7 @@
```json
{
"agent_name": "string",
"encoding": "string",
"signature": "string"
}
@@ -41,10 +44,11 @@
### Properties
| Name | Type | Required | Restrictions | Description |
|-------------|--------|----------|--------------|-------------|
| `encoding` | string | true | | |
| `signature` | string | true | | |
| Name | Type | Required | Restrictions | Description |
|--------------|--------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `agent_name` | string | false | | Agent name optionally selects a specific agent when multiple agents share the same instance identity. An empty string is treated as unspecified. |
| `encoding` | string | true | | |
| `signature` | string | true | | |
## agentsdk.ExternalAuthResponse
@@ -90,15 +94,17 @@
```json
{
"agent_name": "string",
"json_web_token": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|------------------|--------|----------|--------------|-------------|
| `json_web_token` | string | true | | |
| Name | Type | Required | Restrictions | Description |
|------------------|--------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `agent_name` | string | false | | Agent name optionally selects a specific agent when multiple agents share the same instance identity. An empty string is treated as unspecified. |
| `json_web_token` | string | true | | |
## agentsdk.Log
+9
View File
@@ -77,3 +77,12 @@ URL for an agent to access your deployment.
| Default | <code>token</code> |
Specify the authentication type to use for the agent.
### --agent-name
| | |
|-------------|--------------------------------|
| Type | <code>string</code> |
| Environment | <code>$CODER_AGENT_NAME</code> |
The name of the agent to authenticate as (only applicable for instance identity).