DEV Community

Cover image for Deploying AWS DevOps Agent using Terraform
Haytham Mostafa
Haytham Mostafa

Posted on

Deploying AWS DevOps Agent using Terraform

About AWS DevOps Agent

AWS DevOps Agent is an AI-powered operational service designed to investigate production incidents, correlate telemetry and infrastructure changes, identify likely root causes, and recommend preventive improvements.

The service can work with AWS resources, observability platforms, code repositories, CI/CD systems, runbooks, and ticketing systems.

AWS DevOps Agent acts as an operational assistant for DevOps and Site Reliability Engineering teams.

It can:

  • Discover AWS resources and their relationships
  • Build an application topology
  • Correlate logs, metrics, traces, deployments, and configuration changes
  • Investigate incidents
  • Produce root-cause analysis
  • Recommend remediation and preventive actions
  • Integrate with external observability and engineering tools

AWS defines an Agent Space as the logical boundary controlling what the agent can access. Each Agent Space has its own AWS account access, external integrations, operator permissions, investigation data, and chat history.

An Agent Space should normally align with an application, business service, platform, or on-call ownership boundary.

Supported AWS Regions

AWS DevOps Agent can investigate resources across Regions after an AWS account is associated with the Agent Space. You do not need to create a separate Agent Space in every workload Region.

However, the Agent Space itself must be created in a supported Region.

At the time of writing, supported Regions include:

us-east-1
us-west-2
ca-central-1
sa-east-1
ap-south-1
ap-southeast-1
ap-southeast-2
ap-northeast-1
eu-central-1
eu-west-1
eu-west-2
Enter fullscreen mode Exit fullscreen mode

Production operations are available in all supported Regions, while some preview capabilities can have more limited Regional availability.

For European workloads, eu-west-1 or eu-central-1 may be appropriate depending on latency, data residency, and organizational requirements.

Deployment requirements

Before starting, ensure you have:

  • Terraform 1.0 or later
  • AWS CLI installed
  • AWS CLI credentials configured
  • Permission to create IAM roles and policies
  • Permission to create AWS DevOps Agent resources
  • One AWS account for the Agent Space
  • Optionally, one or more additional workload accounts

Check the installed tools:

1) terraform version

terraform version
Terraform v1.15.8
Enter fullscreen mode Exit fullscreen mode

2) AWS CLI version

aws --version
aws-cli/2.24.0 Python/3.12.6 Windows/11 exe/AMD64
Enter fullscreen mode Exit fullscreen mode

3) Verify AWS identity:

aws sts get-caller-identity`
Expected output:
{
  "UserId": "AIDAXXXXXXXXXXXXXXXX",
  "Account": "123456789876",
  "Arn": "arn:aws:iam::123456789876:user/terraform-admin"
}
Enter fullscreen mode Exit fullscreen mode

For local testing, an AWS CLI profile can be used:
aws configure --profile devops-agent-admin

For production CI/CD, use temporary credentials through OpenID Connect or an AWS role instead of storing long-lived access keys.

Terraform project structure

A small environment, can use the following structure:

aws-devops-agent-terraform/
├── backend.tf
├── versions.tf
├── providers.tf
├── variables.tf
├── locals.tf
├── data.tf
├── iam-agent.tf
├── iam-operator.tf
├── devops-agent.tf
├── associations.tf
├── outputs.tf
├── terraform.tfvars.example
└── README.md
Enter fullscreen mode Exit fullscreen mode

For a larger environment, extract the deployment into a reusable module:

aws-devops-agent-terraform/
├── modules/
│   └── devops-agent/
│       ├── main.tf
│       ├── iam.tf
│       ├── variables.tf
│       └── outputs.tf
└── environments/
    ├── production/
    └── non-production/
Enter fullscreen mode Exit fullscreen mode

Steps

Step 1: Configure the Terraform versions

Create versions.tf:

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }

    awscc = {
      source  = "hashicorp/awscc"
      version = "~> 1.0"
    }

    time = {
      source  = "hashicorp/time"
      version = "~> 0.13"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The awscc provider is important because AWS DevOps Agent resources are exposed through AWS Cloud Control.

The time provider can be used to handle IAM propagation delays before creating the Agent Space.

Step 2: Configure the providers

Create providers.tf:

provider "aws" {
  region  = var.aws_region
  profile = var.aws_profile

  default_tags {
    tags = local.common_tags
  }
}

provider "awscc" {
  region  = var.aws_region
  profile = var.aws_profile
}
Enter fullscreen mode Exit fullscreen mode

For local development, profile is acceptable. In CI/CD, remove the profile and let the provider obtain temporary credentials from the pipeline environment:

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = local.common_tags
  }
}

provider "awscc" {
  region = var.aws_region
}
Enter fullscreen mode Exit fullscreen mode

Avoid putting access keys directly inside the provider, as shown below:

provider "aws" {
  access_key = "AKIA..."
  secret_key = "..."
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Define variables

Create variables.tf:

variable "aws_region" {
  description = "AWS Region in which the Agent Space will be created."
  type        = string
  default     = "eu-west-1"

  validation {
    condition = contains([
      "us-east-1", 
      "us-west-2", 
      "ca-central-1", 
      "sa-east-1",
      "ap-south-1", 
      "ap-southeast-1", 
      "ap-southeast-2", 
      "ap-northeast-1",
      "eu-central-1", 
      "eu-west-1", 
      "eu-west-2"
    ], var.aws_region)
    error_message = "The selected Region is not currently supported by AWS DevOps Agent."
  }
}

variable "aws_profile" {
  description = "Optional AWS CLI profile for local deployment."
  type        = string
  default     = null
}

variable "agent_space_name" {
  description = "Name of the AWS DevOps Agent Space."
  type        = string

  validation {
    condition     = length(trimspace(var.agent_space_name)) > 2
    error_message = "The Agent Space name must contain at least three characters."
  }
}

variable "agent_space_description" {
  description = "Description of the Agent Space and its operational boundary."
  type        = string
}

variable "environment" {
  description = "Deployment environment."
  type        = string
  default     = "production"

  validation {
    condition     = contains(["development", "test", "staging", "production"], var.environment)
    error_message = "Environment must be development, test, staging, or production."
  }
}

variable "application_name" {
  description = "Application or platform monitored by the Agent Space."
  type        = string
}

variable "additional_tags" {
  description = "Additional tags applied to supported resources."
  type        = map(string)
  default     = {}
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create common tags

Create locals.tf:

locals {
  common_tags = merge(
    {
      Application = var.application_name
      Environment = var.environment
      ManagedBy   = "Terraform"
      Repository  = "aws-devops-agent-terraform"
      Service     = "AWS-DevOps-Agent"
    },
    var.additional_tags
  )
}
Enter fullscreen mode Exit fullscreen mode

Tags help with:

  • Ownership
  • Cost allocation
  • Incident routing
  • Compliance
  • Terraform resource discovery
  • Operational governance

Step 5: Retrieve the current AWS account

Create data.tf:

data "aws_caller_identity" "current" {}

data "aws_partition" "current" {}

data "aws_region" "current" {}
Enter fullscreen mode Exit fullscreen mode

These data sources prevent hardcoding the AWS account ID, partition, and Region.

Step 6: Create the DevOps Agent IAM role

AWS DevOps Agent needs an IAM role that the service can assume.

Create iam-agent.tf:

data "aws_iam_policy_document" "devops_agent_assume_role" {
  statement {
    sid     = "AllowAWSDevOpsAgent"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["aidevops.amazonaws.com"]
    }

    condition {
      test     = "StringEquals"
      variable = "aws:SourceAccount"
      values   = [data.aws_caller_identity.current.account_id]
    }
  }
}

resource "aws_iam_role" "devops_agent" {
  name_prefix        = "DevOpsAgentRole-AgentSpace-"
  description        = "Role assumed by AWS DevOps Agent for ${var.application_name}"
  assume_role_policy = data.aws_iam_policy_document.devops_agent_assume_role.json

  tags = local.common_tags
}

# Attach the AWS-managed DevOps Agent access policy
resource "aws_iam_role_policy_attachment" "devops_agent_access" {
  role       = aws_iam_role.devops_agent.name
  policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AIDevOpsAgentAccessPolicy"
}

# AWS DevOps Agent can also require permission to create or use the AWS Resource Explorer service-linked role.
# Create a narrowly scoped inline policy:
data "aws_iam_policy_document" "resource_explorer_service_linked_role" {
  statement {
    sid    = "AllowResourceExplorerServiceLinkedRole"
    effect = "Allow"

    actions = [
      "iam:CreateServiceLinkedRole"
    ]

    resources = ["*"]

    condition {
      test     = "StringEquals"
      variable = "iam:AWSServiceName"
      values   = ["resource-explorer-2.amazonaws.com"]
    }
  }
}

resource "aws_iam_role_policy" "resource_explorer_service_linked_role" {
  name   = "AllowResourceExplorerServiceLinkedRole"
  role   = aws_iam_role.devops_agent.id
  policy = data.aws_iam_policy_document.resource_explorer_service_linked_role.json
}
Enter fullscreen mode Exit fullscreen mode

Check the current AWS-managed policy names in the official AWS documentation before deployment. Service policies can evolve as capabilities are added.

Step 7: Create the operator web application role

The operator role controls what engineers can do through the AWS DevOps Agent web application.

Create iam-operator.tf:

data "aws_iam_policy_document" "operator_assume_role" {
  statement {
    sid     = "AllowAWSDevOpsAgentOperatorApp"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["aidevops.amazonaws.com"]
    }

    condition {
      test     = "StringEquals"
      variable = "aws:SourceAccount"
      values   = [data.aws_caller_identity.current.account_id]
    }
  }
}

resource "aws_iam_role" "operator" {
  name_prefix        = "DevOpsAgentRole-WebappAdmin-"
  description        = "Operator web application role for ${var.application_name}"
  assume_role_policy = data.aws_iam_policy_document.operator_assume_role.json

  tags = local.common_tags
}

resource "aws_iam_role_policy_attachment" "operator_access" {
  role       = aws_iam_role.operator.name
  policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AIDevOpsOperatorAppAccessPolicy"
}
Enter fullscreen mode Exit fullscreen mode

Separating the agent role from the operator role is important:

  • The agent role controls what infrastructure and telemetry the agent can inspect.
  • The operator role controls what human operators can do in the Agent Space web application.

Do not combine these responsibilities into a single role.

Step 8: Handle IAM propagation

IAM is eventually consistent. The DevOps Agent service validates the role trust policies while the Agent Space is being created.

Add a small delay:

resource "time_sleep" "wait_for_iam_propagation" {
  create_duration = "30s"

  depends_on = [
    aws_iam_role_policy_attachment.devops_agent_access,
    aws_iam_role_policy_attachment.operator_access,
    aws_iam_role_policy.resource_explorer_service_linked_role
  ]
}
Enter fullscreen mode Exit fullscreen mode

The official AWS Terraform example also accounts for IAM propagation. If role validation still fails, waiting briefly and rerunning terraform apply can allow Terraform to continue from the existing IAM resources.

Step 9: Create the Agent Space

Create devops-agent.tf:

resource "awscc_devopsagent_agent_space" "this" {
  name        = var.agent_space_name
  description = var.agent_space_description

  operator_app = {
    enabled  = true
    role_arn = aws_iam_role.operator.arn
  }

  depends_on = [
    time_sleep.wait_for_iam_propagation
  ]
}
Enter fullscreen mode Exit fullscreen mode

The exact resource schema can change as the AWS Cloud Control resource evolves. Validate the current arguments with:

terraform providers schema -json

You can also inspect the resource documentation:

terraform init
terraform providers
Enter fullscreen mode Exit fullscreen mode

Step 10: Associate the monitoring account

The account association connects the current AWS account to the Agent Space.

Create associations.tf:

resource "awscc_devopsagent_association" "monitoring_account" {
  agent_space_id = awscc_devopsagent_agent_space.this.agent_space_id

  association_type = "AWS"

  configuration = {
    account_id = data.aws_caller_identity.current.account_id
    role_arn   = aws_iam_role.devops_agent.arn
    source_type = "MONITOR"
  }

  depends_on = [
    awscc_devopsagent_agent_space.this
  ]
}
Enter fullscreen mode Exit fullscreen mode

Because AWS Cloud Control schemas can differ between provider releases, compare the property names with the current Terraform Registry schema before publishing or applying the configuration.

The official AWS sample is the safest baseline for the exact awscc_devopsagent_association configuration. AWS confirms that this association links the monitoring account to the Agent Space.

Step 11: Define outputs

Create outputs.tf:

output "agent_space_id" {
  description = "AWS DevOps Agent Space ID."
  value       = awscc_devopsagent_agent_space.this.agent_space_id
}

output "agent_space_arn" {
  description = "AWS DevOps Agent Space ARN."
  value       = awscc_devopsagent_agent_space.this.agent_space_arn
}

output "agent_space_name" {
  description = "AWS DevOps Agent Space name."
  value       = var.agent_space_name
}

output "devops_agent_role_arn" {
  description = "IAM role assumed by AWS DevOps Agent."
  value       = aws_iam_role.devops_agent.arn
}

output "operator_role_arn" {
  description = "Operator web application IAM role."
  value       = aws_iam_role.operator.arn
}

output "monitoring_account_id" {
  description = "AWS monitoring account ID."
  value       = data.aws_caller_identity.current.account_id
}
Enter fullscreen mode Exit fullscreen mode

Step 12: Configure the environment

Create terraform.tfvars.example:

aws_region = "eu-west-1"
aws_profile = "devops-agent-admin"

agent_space_name = "payments-production"
agent_space_description = "AWS DevOps Agent Space for the production payments platform"

application_name = "payments-platform"
environment      = "production"

additional_tags = {
  Owner       = "Platform-Engineering"
  CostCenter  = "CC-1234"
  Criticality = "High"
}
Enter fullscreen mode Exit fullscreen mode

Copy the file:

cp terraform.tfvars.example terraform.tfvars

Never commit terraform.tfvars when it contains account-specific or sensitive data.

Add it to .gitignore:

.terraform/
*.tfstate
*.tfstate.*
*.tfplan
terraform.tfvars
crash.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json
Enter fullscreen mode Exit fullscreen mode

Commit .terraform.lock.hcl so that the same provider versions are used across development and CI/CD environments.

Step 13: Deploy the Agent Space

Format the code:

terraform fmt -recursive

Initialize Terraform:

terraform init
Enter fullscreen mode Exit fullscreen mode

Validate the configuration:

terraform validate
Enter fullscreen mode Exit fullscreen mode

Create a saved plan:

terraform plan \
  -out=tfplan
Enter fullscreen mode Exit fullscreen mode

Review the plan carefully and apply it:

terraform apply tfplan
Enter fullscreen mode Exit fullscreen mode

After deployment, inspect the outputs:

terraform output
Enter fullscreen mode Exit fullscreen mode

Example:

agent_space_id     = "abc123"
agent_space_arn    = "arn:aws:aidevops:eu-west-1:123456789876:agentspace/abc123"
agent_space_name   = "payments-production"
operator_role_arn  = "arn:aws:iam::123456789876:role/DevOpsAgentRole-WebappAdmin-.
Enter fullscreen mode Exit fullscreen mode

Step 14: Verify the deployment

Use the AWS CLI:

aws devops-agent get-agent-space \
  --agent-space-id "$(terraform output -raw agent_space_id)" \
  --region "$(terraform output -raw aws_region 2>/dev/null || echo eu-west-1)"
Enter fullscreen mode Exit fullscreen mode

Alternatively:

AGENT_SPACE_ID=$(terraform output -raw agent_space_id)

aws devops-agent get-agent-space \
  --agent-space-id "$AGENT_SPACE_ID" \
  --region eu-west-1
Enter fullscreen mode Exit fullscreen mode

You can also verify that the IAM roles exist:

aws iam get-role \
  --role-name "$(terraform output -raw devops_agent_role_arn | awk -F/ '{print $NF}')"
Enter fullscreen mode Exit fullscreen mode

Then open the AWS DevOps Agent console and confirm:

  • The Agent Space is active.
  • The operator app is enabled.
  • The current AWS account is associated.
  • Resource discovery has started.
  • Application topology is being populated.

Deployment Best Practices

1) Use a remote Terraform backend

Do not store production Terraform state only on an engineer’s laptop.

Example S3 backend:

terraform {
  backend "s3" {
    bucket       = "company-terraform-state-prod"
    key          = "platform/aws-devops-agent/terraform.tfstate"
    region       = "eu-west-1"
    encrypt      = true
    use_lockfile = true
  }
}
Enter fullscreen mode Exit fullscreen mode

The backend bucket should have:

  • Versioning enabled
  • Encryption enabled
  • Public access blocked
  • Strict bucket policy
  • Access logging where required
  • State locking enabled
  • Backup and recovery procedures

Bootstrap the backend separately because Terraform cannot use a backend that does not yet exist.

2) Protect observability data

The agent can process logs, metrics, traces, ticket metadata, resource tags, and other operational information.

Do not place:

  • Passwords
  • API keys
  • Authentication tokens
  • Customer personal information
  • Payment card information
  • Private certificates

inside logs, tags, or incident descriptions.

AWS notes that personally identifiable information is not automatically removed when data is summarized. Sensitive information should therefore be redacted before it enters observability systems.

Common Terraform issues

1) Resource type not found

Example:

Error: Invalid resource type

The provider hashicorp/aws does not support resource type
"aws_devopsagent_agent_space".
Enter fullscreen mode Exit fullscreen mode

Cause:
AWS DevOps Agent resources use the AWS Cloud Control provider.

Solution:

required_providers {
  awscc = {
    source  = "hashicorp/awscc"
    version = "~> 1.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Use:

awscc_devopsagent_agent_space
awscc_devopsagent_association
Enter fullscreen mode Exit fullscreen mode

The official AWS documentation requires the awscc provider for these resources.

2) IAM trust policy validation failure

Example:

The operator role trust policy is invalid

Possible causes:

  • IAM propagation delay
  • Incorrect service principal
  • Incorrect source account
  • Incorrect Agent Space ARN
  • An Organizations SCP blocking the operation

Resolution:

  • Confirm the trust policy.
  • Confirm the current account ID.
  • Wait briefly for IAM propagation.
  • Run terraform apply again.
  • Check CloudTrail for denied API calls.
  • Review Organizations SCPs and permission boundaries.

3) Access denied while creating the Agent Space

Check the caller identity:

aws sts get-caller-identity
Enter fullscreen mode Exit fullscreen mode

Then verify the deployment principal can:

  • Create IAM roles
  • Attach IAM policies
  • Pass the required IAM roles
  • Create AWS DevOps Agent resources
  • Create account associations
  • Create service-linked roles when required

Also check whether an SCP blocks:

aidevops:*
iam:CreateServiceLinkedRole
iam:PassRole
Enter fullscreen mode Exit fullscreen mode

Do not grant unrestricted administrator access permanently merely to bypass a policy problem.

Cleanup

To remove the environment:

terraform plan -destroy -out=destroy.tfplan
terraform apply destroy.tfplan
Enter fullscreen mode Exit fullscreen mode

Or:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

Destroying an Agent Space can permanently remove its investigation history, recommendations, and associated data. Therefore, review retention requirements before deletion.

Top comments (0)