Skip to content

Latest commit

 

History

History
294 lines (219 loc) · 15.9 KB

File metadata and controls

294 lines (219 loc) · 15.9 KB

Appvia Banner

Terraform Registry Latest Release Slack Community Contributors

Github Actions

Terraform AWS DevOps Agent

Description

This module provisions a production-ready AWS DevOps Agent Space with the IAM roles, account associations, and security controls needed to run autonomous SRE investigations across a multi-account AWS estate. It includes:

  • Agent Space Provisioning: Full Agent Space lifecycle managed via the awscc provider
  • IAM Role Management: AgentSpace and Operator App roles with least-privilege AWS-managed policies
  • Primary Account Hardening: Explicit deny policy preventing the agent from indexing resources in the hosting account — defence in depth enforced unconditionally via IAM, not tags
  • Multi-Account Associations: Hub-and-spoke model with one primary (monitor) association and N secondary (source) workload account associations
  • Region Validation: Input validation enforcing deployment only to regions where the aidevops service is available
  • IAM Propagation Safety: 30-second wait injected before Agent Space creation to avoid race conditions

Key Features

🏢 One Agent Space Per Team

Appvia's recommended pattern is one Agent Space per team or per product. An Agent Space is the primary security and operational boundary — it controls which accounts the agent can query, who can view investigations, and which integrations are in scope.

Team Agent Space Account Visibility
Software Dev Team 1 team1-devops-agent Only the accounts and resources that team owns
Software Dev Team 2 team2-devops-agent Only the accounts and resources that team owns
Platform Team platform-devops-agent All platform accounts — full horizontal view

This model avoids cross-team data exposure, keeps investigation noise scoped per team, and means each team has independent service quota headroom (concurrent investigations, evaluations). A single AWS account can host multiple Agent Spaces.

🔗 Hub-and-Spoke Multi-Account Architecture

The module is designed around a dedicated hosting account (hub) that owns all Agent Spaces, and one or more secondary/workload accounts (spokes) that the agent monitors. This mirrors the recommended AWS deployment model and keeps the hosting infrastructure cleanly separated from the workloads being investigated.

flowchart LR
    subgraph Hub["Hosting Account — Hub"]
        AS1["AgentSpace: team1-devops-agent"]
        AS2["AgentSpace: platform-devops-agent"]
    end

    AS1 -->|"cross-account role"| WA["Workload Account A"]
    AS1 -->|"cross-account role"| WB["Workload Account B"]
    AS2 -->|"cross-account role"| WN["Network Account"]
    AS2 -->|"cross-account role"| WS["Security Account"]
Loading

IAM layout per Agent Space:

Account Role Policy Purpose
Hub DevOpsAgentRole-AgentSpace-<prefix> AIDevOpsAgentAccessPolicy + DenyPrimaryAccountDiscovery inline deny Agent investigation role; explicit deny blocks resource indexing of the hosting account itself
Hub DevOpsAgentRole-WebappAdmin-<prefix> AIDevOpsOperatorAppAccessPolicy Operator web app authentication
Each spoke DevOpsAgentCrossAccountRole AIDevOpsAgentAccessPolicy Agent read access to workload resources; trust scoped to the specific AgentSpace ARN

The cross-account trust policy in each spoke references the exact agent_space_arn output from Phase 1 — a wildcard trust across all Agent Spaces in the hosting account is not used. Use the modules/spoke submodule (included in this module) to create this role in each workload account.

Cross-region monitoring: The AgentSpace region does not constrain which AWS regions the agent can query. Workload accounts in eu-west-2 are fully visible from an AgentSpace hosted in eu-west-1.

Note: eu-west-2 (London) is not a supported AgentSpace region. For UK gov, deploy the AgentSpace itself into eu-west-1 (Ireland) or eu-central-1 (Frankfurt) — workloads in eu-west-2 remain fully visible.

🔐 Security — IAM Deny Policies, Not Tag Restrictions

AWS supports restricting the agent via IAM tag conditions. This module deliberately does not use that approach:

  • Tags are mutable. Anyone with ec2:CreateTags can remove or alter a tag and bring a resource into scope. IAM Deny statements cannot be overridden by any other attached policy — they are enforced unconditionally.
  • The hosting account is hard-excluded. An explicit DenyPrimaryAccountDiscovery inline policy denies all resource-explorer-2:* and tag:Get* actions on the agentspace role, regardless of what AIDevOpsAgentAccessPolicy permits. Resource indexing is only intended for secondary workload accounts.
  • Defence in depth. AIDevOpsAgentAccessPolicy is read-only by design (Describe*, Get*, List* across ~150 services — the only write action is support:CreateCase). The inline deny is a second, independent enforcement layer.

🌍 EU / UK Government Data Residency

At GA (March 2026), AWS confirmed EU-hosted Agent Spaces process inference within the EU — requests do not route through US infrastructure. For UK gov and EU workloads, deploy the AgentSpace into eu-west-1 (Ireland) or eu-central-1 (Frankfurt). Workload accounts in eu-west-2 (London) are fully visible from either region — cross-region monitoring is supported regardless of where the AgentSpace is hosted.

🤖 Read-Only by Design

The agent is a read-and-report system. It cannot start/stop instances, execute shell commands, read S3 object content, read Secrets Manager values, invoke Lambda, or modify any IAM resource. The only outbound writes are support:CreateCase and posting findings to connected third-party tools (PagerDuty, ServiceNow, Slack).

Usage

Basic — Single Hosting Account, No Workloads (Phase 1)

On first apply, leave secondary_accounts empty. This creates the Agent Space and emits agent_space_arn as an output, which you need before configuring cross-account trust policies in secondary workload accounts.

module "devops_agent" {
  source = "appvia/devops-agent/aws"
  version = "0.1.0"

  agent_space_name        = "Platform Team"
  agent_space_description = "DevOps Agent Space for the Platform Engineering team"
  agentspace_region       = "eu-west-1"
  name_prefix             = "platform"

  tags = {
    Team        = "platform"
    Environment = "prod"
    ManagedBy   = "terraform"
  }
}

output "agent_space_arn" {
  value = module.devops_agent.agent_space_arn
}

With Workload Account Associations (Phase 2)

After Phase 1, use the modules/spoke submodule to create the cross-account IAM role in each workload account. Each spoke is called with a provider alias pointing at that account. The agent_space_arn from Phase 1 is passed in directly — the spoke module extracts the hosting account ID from it automatically.

# Configure provider aliases — one per account
provider "aws" {
  alias = "hosting"
  # assume_role or profile for the hosting account
}

provider "aws" {
  alias = "dev"
  # assume_role or profile for the dev workload account
}

provider "aws" {
  alias = "payments"
  # assume_role or profile for the payments workload account
}

# Phase 2a — deploy spoke roles into each workload account
module "spoke_dev" {
  source  = "appvia/devops-agent/aws//modules/spoke"
  version = "0.1.0"
  providers = { aws = aws.dev }

  agent_space_arn = "arn:aws:aidevops:eu-west-1:HOSTING_ACCOUNT_ID:agentspace/AGENT_SPACE_ID"
}

module "spoke_payments" {
  source  = "appvia/devops-agent/aws//modules/spoke"
  version = "0.1.0"
  providers = { aws = aws.payments }

  agent_space_arn = "arn:aws:aidevops:eu-west-1:HOSTING_ACCOUNT_ID:agentspace/AGENT_SPACE_ID"
}

# Phase 2b — re-apply the hub with secondary_accounts populated from spoke outputs
module "devops_agent" {
  source  = "appvia/devops-agent/aws"
  version = "0.1.0"
  providers = {
    aws   = aws.hosting
    awscc = awscc.hosting
  }

  agent_space_name        = "Platform Team"
  agent_space_description = "DevOps Agent Space for the Platform Engineering team"
  agentspace_region       = "eu-west-1"
  name_prefix             = "platform"

  secondary_accounts = {
    dev = {
      account_id             = "111122223333"
      cross_account_role_arn = module.spoke_dev.role_arn
    }
    payments = {
      account_id             = "444455556666"
      cross_account_role_arn = module.spoke_payments.role_arn
    }
  }

  tags = {
    Team        = "platform"
    Environment = "prod"
    ManagedBy   = "terraform"
  }
}

Two-phase apply is required. The spoke trust policy must reference the real agent_space_arn, which only exists after Phase 1 completes. Hardcode the ARN from the Phase 1 output into each spoke module call, then apply Phase 2 — Terraform will create the spoke roles first (they have no dependency on the hub in Phase 2) and then update the hub associations.

Per-Team Pattern (Multiple Agent Spaces in One Account)

module "devops_agent_team1" {
  source  = "appvia/devops-agent/aws"
  version = "0.1.0"

  agent_space_name  = "Software Dev Team 1"
  agentspace_region = "eu-west-1"
  name_prefix       = "team1"

  secondary_accounts = {
    team1-dev  = { account_id = "111122223333", cross_account_role_arn = "arn:aws:iam::111122223333:role/DevOpsAgentCrossAccountRole" }
    team1-prod = { account_id = "444455556666", cross_account_role_arn = "arn:aws:iam::444455556666:role/DevOpsAgentCrossAccountRole" }
  }

  tags = { Team = "team1", ManagedBy = "terraform" }
}

module "devops_agent_platform" {
  source  = "appvia/devops-agent/aws"
  version = "0.1.0"

  agent_space_name  = "Platform Team"
  agentspace_region = "eu-west-1"
  name_prefix       = "platform"

  secondary_accounts = {
    network  = { account_id = "777788889999", cross_account_role_arn = "arn:aws:iam::777788889999:role/DevOpsAgentCrossAccountRole" }
    security = { account_id = "000011112222", cross_account_role_arn = "arn:aws:iam::000011112222:role/DevOpsAgentCrossAccountRole" }
    dev  = { account_id = "111122223333", cross_account_role_arn = "arn:aws:iam::111122223333:role/DevOpsAgentCrossAccountRole" }
    prod = { account_id = "444455556666", cross_account_role_arn = "arn:aws:iam::444455556666:role/DevOpsAgentCrossAccountRole" }
  }

  tags = { Team = "platform", ManagedBy = "terraform" }
}

Supported Regions

The agentspace_region variable is validated against the regions where the aidevops service is available:

Region Location
us-east-1 US East (N. Virginia)
us-west-2 US West (Oregon)
eu-west-1 Europe (Ireland)
eu-central-1 Europe (Frankfurt)
ap-southeast-2 Asia Pacific (Sydney)
ap-northeast-1 Asia Pacific (Tokyo)

Note: eu-west-2 (London) is not a supported AgentSpace region. For UK gov data residency, deploy into eu-west-1 (Ireland) or eu-central-1 (Frankfurt).

Examples

See the examples directory for complete usage examples:

Requirements

Name Version
terraform >= 1.14.0
aws >= 6.0.0
awscc ~> 1.0
time ~> 0.9

Providers

Name Version
aws >= 6.0.0
awscc ~> 1.0
time ~> 0.9

Update Documentation

The terraform-docs utility is used to generate this README. Follow the below steps to update:

  1. Make changes to the .terraform-docs.yml file
  2. Fetch the terraform-docs binary (https://terraform-docs.io/user-guide/installation/)
  3. Run terraform-docs markdown table --output-file ${PWD}/README.md --output-mode inject .

Inputs

Name Description Type Default Required
agent_space_name Display name of the DevOps Agent Space (shown in the console — spaces allowed) string n/a yes
agentspace_region AWS region where the Agent Space is deployed. Supported regions: us-east-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-2, ap-northeast-1. eu-west-2 (London) is not supported. string n/a yes
agent_space_description Description for the DevOps Agent Space string "AWS DevOps Agent Space" no
name_prefix Short slug used in IAM role names — no spaces or special chars. Defaults to agent_space_name with spaces replaced by hyphens if not set. string "" no
secondary_accounts Map of workload accounts to associate as secondary sources. Key is a short label used in resource names. Leave empty on first apply; populate after capturing agent_space_arn.
map(object({
account_id = string
cross_account_role_arn = string
}))
{} no
tags Tags to apply to all resources map(string) {} no

Outputs

Name Description
agent_space_id ID of the DevOps Agent Space
agent_space_arn ARN of the DevOps Agent Space — use this to scope the workload cross-account role trust policy
agent_space_name Name of the DevOps Agent Space
agentspace_role_arn ARN of the DevOps AgentSpace IAM role (assumed by the agent for resource indexing)
operator_role_arn ARN of the DevOps Operator App IAM role (assumed by the agent to drive the web app)