Skip to main content
By default agent VMs run on Murmur’s infrastructure. To move them into your own GCP or AWS account, set up a customer Placement. The result: each VM runs in your project, on your subnet, billed to you, reachable by your internal services. See placement for the full resource spec. This is advanced. Most teams don’t need it. Common reasons to do it anyway:
  • Compliance: security team requires compute in your own account
  • Data residency: regulations pin you to a specific region
  • VPC-internal access: agents need databases, services, or APIs not on the public internet
  • Custom networking: specific firewall rules, proxy, or VPN
Murmur authenticates into your cloud via OIDC token exchange (Workload Identity Federation). No service-account JSON, no long-lived keys, no rotation burden. The trust policy is scoped to exactly your tenant ID, so no other Murmur tenant can ever reach your resources.

GCP

1. Apply the Terraform module

The customer modules are public at github.com/prassoai/terraform-modules. Consume them via a git source pinned to a release tag with ?ref= — never a branch:
module "murmur_placement" {
  source = "git::https://github.com/prassoai/terraform-modules.git//modules/gcp-wif?ref=v0.2.0"

  project_id          = "your-project-id"
  tenant_id           = "github_app/your-org" # from `murmur tenant whoami` or the dashboard
  vm_service_accounts = ["murmur-vm@your-project-id.iam.gserviceaccount.com"]

  # Placement-shape inputs — set these and the module emits a sync-ready
  # `placement` output you can pipe straight into the CLI (step 2).
  placement_name   = "my-gcp" # must not start with "murmur-"
  placement_zones  = ["us-central1-a", "us-central1-b"]
  placement_subnet = "projects/your-project-id/regions/us-central1/subnetworks/agents"
}
vm_service_accounts lists the runtime service accounts your agents run as; the module grants the WIF service account permission to attach them at VM-create time. The module creates a Workload Identity Federation pool and provider, the VM-creator and read-only service accounts, a tight custom IAM role, and the bindings — all scoped to your tenant. Murmur exchanges its OIDC token for short-lived GCP credentials; nothing long-lived lives on the agent VMs.

2. Sync the Placement

As of v0.2.0 the module assembles the full Placement from its own WIF outputs plus the placement_* inputs and exposes it as the placement output. Pipe it straight into murmur set — no hand-copying WIF resource names:
terraform output -json placement | murmur set placement my-gcp
The output is null until placement_name is set, so the module also works for WIF-only setups. By default every tenant member may spawn agents under the placement; set default_spawn_grant (or spawn_grants_by_sa, keyed by SA email) to scope it to named groups or users.

3. Rebake your Images into your project

GCE images are project-bound. Murmur’s platform Images aren’t visible from your project, so you have to bake fresh ones against the new Placement with murmur bake:
murmur bake my-recipe default my-gcp
This boots a scratch VM in your project, runs your Recipe’s provisioning script there, snapshots the disk, and registers the resulting Image. Parallel bakes are independent workflows and don’t contend.

4. Point a Workspace at the Placement

cat <<EOF | murmur set workspace my-workspace
name: my-workspace
placement: my-gcp
environment_ref: default
image_ref: my-recipe
repos:
  - clone_url: https://github.com/your-org/your-repo
    base_branch: main
EOF
Spawn an agent and verify with murmur status that the project field matches yours. If it doesn’t, double-check that the Image you’re using was baked against my-gcp (different Placements can’t share Images). See Workspaces for the full Workspace model.

AWS

1. Apply the Terraform module

module "murmur_placement" {
  source = "git::https://github.com/prassoai/terraform-modules.git//modules/aws-wif?ref=v0.2.0"

  tenant_id = "github_app/your-org" # from `murmur tenant whoami` or the dashboard

  # Placement-shape inputs — set these and the module emits a sync-ready
  # `placement` output you can pipe straight into the CLI (step 2).
  placement_name              = "my-aws" # must not start with "murmur-"
  placement_region            = "us-east-1"
  placement_vpc_id            = "vpc-0abc123"
  placement_subnet_ids        = ["subnet-0aaa", "subnet-0bbb"]
  placement_security_group_id = "sg-0def456"
}
Creates an OIDC provider with a StringEquals trust policy scoped to your tenant ID, the VM-creator and read-only IAM roles, and the VM runtime instance profile. The sub claim match is what gives you cryptographic isolation: another tenant’s OIDC token cannot assume your role, period. The VPC, subnets, and security group are yours — the module takes them as inputs and never creates them, so point placement_vpc_id / placement_subnet_ids / placement_security_group_id at networking that already exists in your account.

2. Sync the Placement

As of v0.2.0 the module assembles the full Placement — deriving account_id from the VM-creator role ARN and reading the role, instance-profile, and OIDC-provider ARNs from its own resources — and exposes it as the placement output. Pipe it straight into murmur set:
terraform output -json placement | murmur set placement my-aws
The output is null until placement_name is set, so the module also works for federation-only setups. By default every tenant member may spawn agents under the placement; set default_spawn_grant to scope it to named groups or users.

3. Rebake your Images into your account

AMIs are account-bound, same as GCE images are project-bound:
murmur bake my-recipe default my-aws

4. Point a Workspace at the Placement

cat <<EOF | murmur set workspace my-workspace
name: my-workspace
placement: my-aws
environment_ref: default
image_ref: my-recipe
repos:
  - clone_url: https://github.com/your-org/your-repo
    base_branch: main
EOF
Verify with murmur status <slug>; account_id and region should match yours.

What changes operationally

  • Billing splits: cloud spend (VMs, network, storage) bills to your account. Murmur’s per-agent-hour charge is separate.
  • Region pinning: VMs only run where your Placement allows. A Workspace using my-gcp with zones: ["us-central1-a"] can never spawn outside that zone.
  • Networking is yours: your firewall rules, your routes, your egress. Agents reach your internal services as if they lived in your VPC.
  • You own incident response: if a VM misbehaves, it’s in your project; you can grab logs, snapshot disks, or shut it down directly.