Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ terraform.rc

go.mod
go.sum


.amazonq/
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Please refer to the [examples](./examples/basic) on how to get started.

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ecs_cluster"></a> [ecs\_cluster](#module\_ecs\_cluster) | git::https://github.com/terraform-aws-modules/terraform-aws-ecs | 6b52c965734d95767d8e20d965afcd0db29dae5e |
| <a name="module_ecs_cluster"></a> [ecs\_cluster](#module\_ecs\_cluster) | git::https://github.com/terraform-aws-modules/terraform-aws-ecs | be968fc4af733fae2ac41dfb3c34dce7712e028f |

## Resources

Expand Down Expand Up @@ -86,6 +86,7 @@ Please refer to the [examples](./examples/basic) on how to get started.
| <a name="input_assign_public_ip"></a> [assign\_public\_ip](#input\_assign\_public\_ip) | Whether to assign a public IP address to the ECS tasks. Set to true when using public subnets. | `bool` | `false` | no |
| <a name="input_cloudwatch_log_group_name"></a> [cloudwatch\_log\_group\_name](#input\_cloudwatch\_log\_group\_name) | The name of the CloudWatch log group where agent logs will be sent. | `string` | `"/hcp/hcp-terraform-agent"` | no |
| <a name="input_cloudwatch_log_group_retention"></a> [cloudwatch\_log\_group\_retention](#input\_cloudwatch\_log\_group\_retention) | The number of days to retain logs in the CloudWatch log group. | `number` | `365` | no |
| <a name="input_cpu_architecture"></a> [cpu\_architecture](#input\_cpu\_architecture) | The CPU architecture for the ECS task. Valid values are X86\_64 and ARM64. | `string` | `"X86_64"` | no |
| <a name="input_create_cloudwatch_log_group"></a> [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Whether the CloudWatch log group should be created. | `bool` | `true` | no |
| <a name="input_create_ecs_cluster"></a> [create\_ecs\_cluster](#input\_create\_ecs\_cluster) | Whether to create a new ECS cluster for the agent. | `bool` | `true` | no |
| <a name="input_create_tfe_agent_pool"></a> [create\_tfe\_agent\_pool](#input\_create\_tfe\_agent\_pool) | Whether to omit agent pool/token creation | `bool` | `true` | no |
Expand Down
21 changes: 21 additions & 0 deletions examples/arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ARM64 Example

This example demonstrates how to deploy HCP Terraform agents on ARM64 architecture using AWS Fargate.

## Key Features

- Uses ARM64 CPU architecture for potentially better cost efficiency
- Deploys on Fargate Spot instances for additional cost savings
- Creates a new VPC with private subnets for secure agent deployment

## Usage

```bash
terraform init
terraform plan
terraform apply
```

## Configuration

The example sets `cpu_architecture = "ARM64"` to deploy agents on ARM64-based Fargate instances instead of the default x86_64 architecture.
59 changes: 59 additions & 0 deletions examples/arm64/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#####################################################################################
# Terraform module examples are meant to show an _example_ on how to use a module
# per use-case. The code below should not be copied directly but referenced in order
# to build your own root module that invokes this module
#####################################################################################

data "aws_availability_zones" "available" {}

locals {
region = "us-west-2"
azs = slice(data.aws_availability_zones.available.names, 0, 3)
name = "ecs-${basename(path.cwd)}"
vpc_cidr = "10.0.0.0/16"
tags = {
Terraform = "true"
Environment = "dev"
ManagedBy = "aws-ia/terraform-aws-tf-cloud-agents"
}
}

#####################################################################################
# MODULE INVOCATION
#####################################################################################

module "agent_pool" {
source = "../../"
name = local.name
hcp_terraform_org_name = var.hcp_terraform_org_name
agent_image = "hashicorp/tfc-agent:latest"
cpu_architecture = "ARM64"
use_spot_instances = true
agent_cpu = 512
agent_memory = 2048
num_agents = 1
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
task_policy_arns = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
tags = local.tags
}

#####################################################################################
# VPC
#####################################################################################

module "vpc" {
source = "git::https://github.com/terraform-aws-modules/terraform-aws-vpc?ref=25322b6b6be69db6cca7f167d7b0e5327156a595" # v5.8.1

name = local.name
cidr = local.vpc_cidr

azs = local.azs
private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]

enable_nat_gateway = true
single_nat_gateway = true

tags = local.tags
}
49 changes: 49 additions & 0 deletions examples/arm64/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
output "agent_pool_name" {
description = "Name of the HCP Terraform or HCP Terraform Enterprise agent pool."
value = module.agent_pool.agent_pool_name
}

output "agent_pool_id" {
description = "ID of the HCP Terraform or HCP Terraform Enterprise agent pool."
value = module.agent_pool.agent_pool_id
}

output "ecs_service_arn" {
description = "ARN of the ECS service."
value = module.agent_pool.ecs_service_arn
}

output "ecs_task_arn" {
description = "ARN of the ECS task definition."
value = module.agent_pool.ecs_task_arn
}

output "ecs_task_revision" {
description = "Revision number of the ECS task definition."
value = module.agent_pool.ecs_task_revision
}

output "log_stream_prefix" {
description = "Prefix for the CloudWatch log stream."
value = module.agent_pool.log_stream_prefix
}

output "security_group_name" {
description = "Name of the VPC security group attached to the service."
value = module.agent_pool.security_group_name
}

output "security_group_id" {
description = "ID of the VPC security group attached to the service."
value = module.agent_pool.security_group_id
}

output "task_role_name" {
description = "Name of the IAM role attached to the task containers."
value = module.agent_pool.task_role_name
}

output "task_role_arn" {
description = "ARN of the IAM role attached to the task containers."
value = module.agent_pool.task_role_arn
}
19 changes: 19 additions & 0 deletions examples/arm64/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
terraform {
required_version = ">= 1.5.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.47.0"
}
}
}


provider "aws" {
region = local.region
}

provider "tfe" {
token = var.tfe_token
}
9 changes: 9 additions & 0 deletions examples/arm64/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
variable "hcp_terraform_org_name" {
type = string
description = "The name of the HCP Terraform organization."
}

variable "tfe_token" {
type = string
description = "Terraform token to be used to create the agent pool."
}
21 changes: 9 additions & 12 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ data "aws_iam_policy_document" "kms_key_policy" {
"kms:*",
]
resources = [
"arn:aws:kms:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:key/*"
"arn:aws:kms:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:key/*"
]
}
statement {
Expand All @@ -53,7 +53,7 @@ data "aws_iam_policy_document" "kms_key_policy" {
principals {
type = "Service"
identifiers = [
"logs.${data.aws_region.current.name}.amazonaws.com",
"logs.${data.aws_region.current.id}.amazonaws.com",
"ssm.amazonaws.com"
]
}
Expand All @@ -65,7 +65,7 @@ data "aws_iam_policy_document" "kms_key_policy" {
"kms:Describe*"
]
resources = [
"arn:aws:kms:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:key/*"
"arn:aws:kms:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:key/*"
]
}
}
Expand Down Expand Up @@ -94,6 +94,7 @@ resource "aws_ecs_task_definition" "hcp_terraform_agent" {

runtime_platform {
operating_system_family = "LINUX"
cpu_architecture = var.cpu_architecture
}

container_definitions = jsonencode(
Expand All @@ -107,7 +108,7 @@ resource "aws_ecs_task_definition" "hcp_terraform_agent" {
options : {
awslogs-create-group : "true",
awslogs-group : var.create_cloudwatch_log_group ? aws_cloudwatch_log_group.cloudwatch[0].name : var.cloudwatch_log_group_name
awslogs-region : data.aws_region.current.name
awslogs-region : data.aws_region.current.id
awslogs-stream-prefix : "hcp-tf-${var.hcp_terraform_org_name}-${var.name}"
}
}
Expand Down Expand Up @@ -209,20 +210,16 @@ resource "aws_security_group_rule" "allow_egress" {

module "ecs_cluster" {
count = var.create_ecs_cluster ? 1 : 0
source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs?ref=6b52c965734d95767d8e20d965afcd0db29dae5e" # v5.11.2
source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecs?ref=be968fc4af733fae2ac41dfb3c34dce7712e028f" # v6.6.1

cluster_name = var.name

fargate_capacity_providers = {
default_capacity_provider_strategy = {
FARGATE = {
default_capacity_provider_strategy = {
weight = 50
}
weight = var.use_spot_instances ? 0 : 100
}
FARGATE_SPOT = {
default_capacity_provider_strategy = {
weight = 50
}
weight = var.use_spot_instances ? 100 : 0
}
}

Expand Down
10 changes: 10 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ variable "agent_image" {
default = "hashicorp/tfc-agent:latest"
}

variable "cpu_architecture" {
type = string
description = "The CPU architecture for the ECS task. Valid values are X86_64 and ARM64."
default = "X86_64"
validation {
condition = contains(["X86_64", "ARM64"], var.cpu_architecture)
error_message = "Valid values: X86_64, ARM64"
}
}

variable "agent_single_execution" {
type = bool
description = "Whether to use single-execution mode."
Expand Down