feat: aws validator terraform example (#3170)
parent
72774b3b92
commit
0e8e169311
@ -0,0 +1,2 @@ |
||||
.terraform |
||||
.terraform.lock.* |
@ -0,0 +1,7 @@ |
||||
# Terraform Module for Hyperlane Validator |
||||
|
||||
This Terraform module is designed to set up the necessary infrastructure for a Hyperlane validator on AWS. It automates the creation of resources such as ECS clusters, VPCs, subnets, and security groups required for running a validator node. |
||||
|
||||
> **Note:** This module is intended to be an example of running a validator for a core supported network. You may have to modify the validator module to support more advanced configurations. It is recommended to test thoroughly before using in a production environment. |
||||
|
||||
For more information, read the [Deploy with Terraform](https://hyp-v3-docs-git-feat-aws-agent-guide-abacus-works.vercel.app/docs/operate/deploy-with-terraform) documentation. |
@ -0,0 +1,100 @@ |
||||
provider "aws" { |
||||
region = var.aws_region # Set the AWS region for the provider |
||||
} |
||||
|
||||
resource "aws_ecs_cluster" "validator_cluster" { |
||||
name = "hyperlane-validator-cluster" # Name of the ECS cluster for the validator |
||||
} |
||||
|
||||
resource "aws_vpc" "validator_vpc" { |
||||
cidr_block = "10.0.0.0/16" # Define the IP range for the VPC |
||||
enable_dns_support = true # Enable DNS support in the VPC |
||||
enable_dns_hostnames = true # Enable DNS hostnames in the VPC |
||||
} |
||||
|
||||
data "aws_availability_zones" "available" {} # Fetch the list of available AZs |
||||
|
||||
resource "aws_subnet" "public_subnet" { |
||||
vpc_id = aws_vpc.validator_vpc.id # Associate with the VPC |
||||
cidr_block = "10.0.2.0/24" # Define the IP range for the public subnet |
||||
availability_zone = data.aws_availability_zones.available.names[0] # Use the first available AZ |
||||
map_public_ip_on_launch = true # Automatically assign public IP on instance launch |
||||
} |
||||
|
||||
resource "aws_subnet" "validator_subnet" { |
||||
vpc_id = aws_vpc.validator_vpc.id # Associate with the VPC |
||||
cidr_block = "10.0.1.0/24" # Define the IP range for the validator subnet |
||||
availability_zone = data.aws_availability_zones.available.names[0] # Use the first available AZ |
||||
map_public_ip_on_launch = false # Do not assign public IP on instance launch |
||||
} |
||||
|
||||
resource "aws_internet_gateway" "vpc_igw" { |
||||
vpc_id = aws_vpc.validator_vpc.id # Attach the internet gateway to the VPC |
||||
} |
||||
|
||||
resource "aws_eip" "nat_gateway_eip" { |
||||
domain = "vpc" # Allocate an Elastic IP in the VPC domain |
||||
} |
||||
|
||||
resource "aws_nat_gateway" "validator_nat_gateway" { |
||||
allocation_id = aws_eip.nat_gateway_eip.id # Associate the EIP with the NAT gateway |
||||
subnet_id = aws_subnet.public_subnet.id # Place the NAT gateway in the public subnet |
||||
depends_on = [aws_internet_gateway.vpc_igw] # Ensure IGW is created before the NAT gateway |
||||
} |
||||
|
||||
resource "aws_route_table" "public_route_table" { |
||||
vpc_id = aws_vpc.validator_vpc.id # Associate the route table with the VPC |
||||
|
||||
route { |
||||
cidr_block = "0.0.0.0/0" # Route all traffic |
||||
gateway_id = aws_internet_gateway.vpc_igw.id # Through the internet gateway |
||||
} |
||||
} |
||||
|
||||
resource "aws_route_table" "private_route_table" { |
||||
vpc_id = aws_vpc.validator_vpc.id # Associate the route table with the VPC |
||||
|
||||
route { |
||||
cidr_block = "0.0.0.0/0" # Route all traffic |
||||
nat_gateway_id = aws_nat_gateway.validator_nat_gateway.id # Through the NAT gateway |
||||
} |
||||
} |
||||
|
||||
resource "aws_route_table_association" "public_subnet_association" { |
||||
subnet_id = aws_subnet.public_subnet.id # Associate the public subnet |
||||
route_table_id = aws_route_table.public_route_table.id # With the public route table |
||||
} |
||||
|
||||
resource "aws_route_table_association" "private_subnet_association" { |
||||
subnet_id = aws_subnet.validator_subnet.id # Associate the validator subnet |
||||
route_table_id = aws_route_table.private_route_table.id # With the private route table |
||||
} |
||||
|
||||
resource "aws_security_group" "validator_sg" { |
||||
name = "validator-sg" # Name of the security group for the validator |
||||
vpc_id = aws_vpc.validator_vpc.id # Associate with the VPC |
||||
|
||||
# prometheus |
||||
ingress { |
||||
from_port = 9090 # Prometheus metrics port |
||||
to_port = 9090 |
||||
protocol = "tcp" |
||||
cidr_blocks = ["0.0.0.0/0"] # Allow traffic from any IP |
||||
} |
||||
|
||||
# efs mounting |
||||
ingress { |
||||
from_port = 2049 # NFS port for EFS |
||||
to_port = 2049 |
||||
protocol = "tcp" |
||||
cidr_blocks = [aws_subnet.validator_subnet.cidr_block] # Allow traffic from the validator subnet |
||||
} |
||||
|
||||
# all egress |
||||
egress { |
||||
from_port = 0 # Allow all outbound traffic |
||||
to_port = 0 |
||||
protocol = "-1" |
||||
cidr_blocks = ["0.0.0.0/0"] # To any IP |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
# Configure a Hyperlane Validator |
||||
# Replaces https://docs.hyperlane.xyz/docs/operate/validators/run-validators |
||||
module "your_validator_name" { |
||||
source = "./modules/validator" |
||||
|
||||
validator_name = "your-validator-name" |
||||
origin_chain_name = "originChainName" |
||||
|
||||
aws_region = var.aws_region |
||||
validator_cluster_id = aws_ecs_cluster.validator_cluster.id |
||||
validator_subnet_id = aws_subnet.validator_subnet.id |
||||
validator_sg_id = aws_security_group.validator_sg.id |
||||
validator_nat_gateway_id = aws_nat_gateway.validator_nat_gateway.id |
||||
|
||||
# Disabling the validator task allows you to set up all the required infrastructure |
||||
# without running the actual validator yet. This is useful when setting up a validator for |
||||
# the first time, so that you can find out the validator address and fund it before it |
||||
# performs the announcement transaction. |
||||
# validator_task_disabled = true |
||||
} |
@ -0,0 +1,42 @@ |
||||
# This resource defines an EFS file system that acts as persistent storage for the validator. |
||||
# The `creation_token` is used to ensure idempotent creation of the file system. |
||||
resource "aws_efs_file_system" "validator_fs" { |
||||
creation_token = var.creation_token # Unique token to guarantee the idempotence of the resource |
||||
|
||||
# Tags are key-value pairs that help with the organization and identification of AWS resources. |
||||
tags = { |
||||
Name = var.creation_token # Name tag using the creation token for easy identification |
||||
} |
||||
} |
||||
|
||||
# The EFS access point serves as a custom entry point into the file system. |
||||
# It enforces the specified POSIX user and group, and the root directory settings. |
||||
resource "aws_efs_access_point" "validator_ap" { |
||||
file_system_id = aws_efs_file_system.validator_fs.id # Associates the access point with the file system |
||||
|
||||
# The POSIX user configuration sets the owner's user and group IDs for all file system requests. |
||||
posix_user { |
||||
gid = var.posix_user_gid # POSIX group ID |
||||
uid = var.posix_user_uid # POSIX user ID |
||||
} |
||||
|
||||
# The root directory configuration specifies the path and creation settings within the EFS. |
||||
root_directory { |
||||
path = var.root_directory_path # The path where the root directory is mounted |
||||
|
||||
# The creation info sets the ownership and permissions for the root directory upon creation. |
||||
creation_info { |
||||
owner_gid = var.posix_user_gid # Group ID of the directory owner |
||||
owner_uid = var.posix_user_uid # User ID of the directory owner |
||||
permissions = var.root_directory_permissions # Permissions for the root directory |
||||
} |
||||
} |
||||
} |
||||
|
||||
# This resource creates a mount target within a specific subnet, allowing EC2 instances to access the EFS file system. |
||||
# The mount target is secured by associating it with one or more security groups. |
||||
resource "aws_efs_mount_target" "validator_mt" { |
||||
file_system_id = aws_efs_file_system.validator_fs.id # Associates the mount target with the file system |
||||
subnet_id = var.subnet_id # The subnet ID where the mount target is placed |
||||
security_groups = var.security_group_ids # Security groups that define the access rules for the mount target |
||||
} |
@ -0,0 +1,19 @@ |
||||
output "file_system_id" { |
||||
description = "The ID of the EFS file system" |
||||
value = aws_efs_file_system.validator_fs.id |
||||
} |
||||
|
||||
output "access_point_id" { |
||||
description = "The ID of the EFS access point" |
||||
value = aws_efs_access_point.validator_ap.id |
||||
} |
||||
|
||||
output "mount_target_id" { |
||||
description = "The ID of the EFS mount target" |
||||
value = aws_efs_mount_target.validator_mt.id |
||||
} |
||||
|
||||
output "access_point_arn" { |
||||
description = "The ARN of the EFS access point" |
||||
value = aws_efs_access_point.validator_ap.arn |
||||
} |
@ -0,0 +1,38 @@ |
||||
variable "creation_token" { |
||||
description = "Unique string to ensure the idempotent creation of the file system" |
||||
type = string |
||||
} |
||||
|
||||
variable "subnet_id" { |
||||
description = "The ID of the subnet to create the mount target in" |
||||
type = string |
||||
} |
||||
|
||||
variable "security_group_ids" { |
||||
description = "A list of security group IDs to associate with the mount target" |
||||
type = list(string) |
||||
} |
||||
|
||||
variable "posix_user_gid" { |
||||
description = "The POSIX group ID for the EFS access point" |
||||
type = number |
||||
default = 1000 |
||||
} |
||||
|
||||
variable "posix_user_uid" { |
||||
description = "The POSIX user ID for the EFS access point" |
||||
type = number |
||||
default = 1000 |
||||
} |
||||
|
||||
variable "root_directory_path" { |
||||
description = "Path to the root directory on the EFS volume" |
||||
type = string |
||||
default = "/hyperlane_db" |
||||
} |
||||
|
||||
variable "root_directory_permissions" { |
||||
description = "Permissions to apply to the root directory on the EFS volume" |
||||
type = string |
||||
default = "700" |
||||
} |
@ -0,0 +1,179 @@ |
||||
# Creates an IAM user for the validator to interact with AWS services |
||||
resource "aws_iam_user" "ecs_user" { |
||||
name = "${var.validator_name}-exec-user" # The name of the IAM user is derived from the validator's name |
||||
} |
||||
|
||||
# Creates a KMS key for the validator to sign transactions securely |
||||
resource "aws_kms_key" "validator_signer_key" { |
||||
description = "KMS Key for Hyperlane Validator Signing" |
||||
key_usage = "SIGN_VERIFY" # Specifies that the key is used for signing and verification |
||||
customer_master_key_spec = "ECC_SECG_P256K1" # Specifies the type of key to be used |
||||
} |
||||
|
||||
# Creates an alias for the KMS key to make it easier to reference |
||||
resource "aws_kms_alias" "validator_signer_key_alias" { |
||||
name = "alias/${var.validator_name}" # The alias name includes the validator's name for easy identification |
||||
target_key_id = aws_kms_key.validator_signer_key.key_id # Associates the alias with the created KMS key |
||||
} |
||||
|
||||
# Defines an IAM policy that grants permissions to use the KMS key for signing operations |
||||
resource "aws_iam_policy" "validator_user_kms_policy" { |
||||
name = "${var.validator_name}-user-kms-policy" |
||||
description = "Allow ECS tasks to use the KMS key for signing" |
||||
|
||||
policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Effect = "Allow", |
||||
Action = [ |
||||
"kms:GetPublicKey", # Allows retrieval of the public key |
||||
"kms:Sign", # Allows signing operations |
||||
"kms:Verify" # Allows verification of signatures |
||||
], |
||||
Resource = aws_kms_key.validator_signer_key.arn # Specifies the KMS key resource |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Attaches the KMS policy to the IAM user, granting it the defined permissions |
||||
resource "aws_iam_user_policy_attachment" "validator_user_kms_policy_attachment" { |
||||
user = aws_iam_user.ecs_user.name # The IAM user to attach the policy to |
||||
policy_arn = aws_iam_policy.validator_user_kms_policy.arn # The ARN of the policy to attach |
||||
} |
||||
|
||||
# Generates an access key for the IAM user to authenticate with AWS services |
||||
resource "aws_iam_access_key" "ecs_user_key" { |
||||
user = aws_iam_user.ecs_user.name # The IAM user for which to create the access key |
||||
} |
||||
|
||||
# Stores the access key ID in SSM Parameter Store for secure retrieval |
||||
resource "aws_ssm_parameter" "key_id" { |
||||
name = "/ecs/${var.validator_name}/access-key-id" # The parameter name includes the validator's name |
||||
type = "String" # The type of the parameter is a simple string |
||||
value = aws_iam_access_key.ecs_user_key.id # The value is the access key ID |
||||
} |
||||
|
||||
# Stores the access key secret in SSM Parameter Store for secure retrieval |
||||
resource "aws_ssm_parameter" "key_secret" { |
||||
name = "/ecs/${var.validator_name}/secret-access-key" # The parameter name includes the validator's name |
||||
type = "String" # The type of the parameter is a simple string |
||||
value = aws_iam_access_key.ecs_user_key.secret # The value is the access key secret |
||||
} |
||||
|
||||
# Creates an IAM role for ECS tasks to assume during execution |
||||
resource "aws_iam_role" "ecs_execution_role" { |
||||
name = "${var.validator_name}-exec-role" # The name of the role includes the validator's name |
||||
|
||||
assume_role_policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Action = "sts:AssumeRole", |
||||
Effect = "Allow", |
||||
Principal = { |
||||
Service = "ecs-tasks.amazonaws.com" # Specifies that ECS tasks can assume this role |
||||
} |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Attaches the AmazonECSTaskExecutionRolePolicy to the ECS execution role |
||||
resource "aws_iam_role_policy_attachment" "ecs_execution_policy" { |
||||
role = aws_iam_role.ecs_execution_role.name # The ECS execution role to attach the policy to |
||||
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" # The ARN of the Amazon-managed policy |
||||
} |
||||
|
||||
# Defines an IAM policy to allow ECS tasks to write logs to CloudWatch |
||||
resource "aws_iam_policy" "cloudwatch_logs_policy" { |
||||
name = "${var.validator_name}-cloudwatch-logs-policy" |
||||
description = "IAM policy for ECS tasks to interact with CloudWatch Logs" |
||||
|
||||
policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Effect = "Allow", |
||||
Action = [ |
||||
"logs:CreateLogStream", # Allows creation of log streams |
||||
"logs:PutLogEvents" # Allows putting log events into log streams |
||||
], |
||||
Resource = "arn:aws:logs:${var.aws_region}:*:log-group:/aws/ecs/${var.aws_log_group}:log-stream:*" # Specifies the log group resource |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Attaches the CloudWatch logs policy to the ECS execution role |
||||
resource "aws_iam_role_policy_attachment" "cloudwatch_logs_policy_attachment" { |
||||
role = aws_iam_role.ecs_execution_role.name # The ECS execution role to attach the policy to |
||||
policy_arn = aws_iam_policy.cloudwatch_logs_policy.arn # The ARN of the CloudWatch logs policy |
||||
} |
||||
|
||||
# Defines an IAM policy to allow ECS tasks to read SSM parameters for access keys |
||||
resource "aws_iam_policy" "ssm_read_policy" { |
||||
name = "${var.validator_name}-ssm-read-policy" |
||||
description = "Allow ECS tasks to read parameters" |
||||
|
||||
policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Effect = "Allow", |
||||
Action = ["ssm:GetParameters"], # Allows retrieval of SSM parameters |
||||
Resource = [ |
||||
aws_ssm_parameter.key_id.arn, # The ARN of the access key ID parameter |
||||
aws_ssm_parameter.key_secret.arn # The ARN of the access key secret parameter |
||||
] |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Attaches the SSM read policy to the ECS execution role |
||||
resource "aws_iam_role_policy_attachment" "ssm_read_policy_execution_attachment" { |
||||
role = aws_iam_role.ecs_execution_role.name # The ECS execution role to attach the policy to |
||||
policy_arn = aws_iam_policy.ssm_read_policy.arn # The ARN of the SSM read policy |
||||
} |
||||
|
||||
# Creates an IAM role for ECS tasks to perform specific actions |
||||
resource "aws_iam_role" "ecs_task_role" { |
||||
name = "${var.validator_name}-task-role" # The name of the task role includes the validator's name |
||||
|
||||
assume_role_policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Action = "sts:AssumeRole", |
||||
Effect = "Allow", |
||||
Principal = { |
||||
Service = "ecs-tasks.amazonaws.com" # Specifies that ECS tasks can assume this role |
||||
} |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Defines an IAM policy to allow ECS tasks to perform actions on the EFS file system |
||||
resource "aws_iam_policy" "ecs_task_policy" { |
||||
name = "${var.validator_name}-task-policy" # The name of the policy includes the validator's name |
||||
|
||||
policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Effect = "Allow", |
||||
Action = "elasticfilesystem:*", # Allows all actions on the EFS file system |
||||
Resource = var.efs_access_point_arn # Specifies the EFS access point resource |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# Attaches the EFS policy to the ECS task role |
||||
resource "aws_iam_role_policy_attachment" "ecs_task_policy_attachment" { |
||||
role = aws_iam_role.ecs_task_role.name # The ECS task role to attach the policy to |
||||
policy_arn = aws_iam_policy.ecs_task_policy.arn # The ARN of the EFS policy |
||||
} |
@ -0,0 +1,35 @@ |
||||
output "ecs_user_arn" { |
||||
value = aws_iam_user.ecs_user.arn |
||||
} |
||||
|
||||
output "ecs_user_access_key_id_arn" { |
||||
value = aws_ssm_parameter.key_id.arn |
||||
} |
||||
|
||||
output "ecs_user_secret_access_key_arn" { |
||||
value = aws_ssm_parameter.key_secret.arn |
||||
} |
||||
|
||||
output "validator_signer_key_arn" { |
||||
value = aws_kms_key.validator_signer_key.arn |
||||
} |
||||
|
||||
output "validator_signer_key_alias" { |
||||
value = aws_kms_alias.validator_signer_key_alias.name |
||||
} |
||||
|
||||
output "validator_execution_role_arn" { |
||||
value = aws_iam_role.ecs_execution_role.arn |
||||
} |
||||
|
||||
output "validator_task_role_arn" { |
||||
value = aws_iam_role.ecs_task_role.arn |
||||
} |
||||
|
||||
output "aws_access_key_id" { |
||||
value = aws_iam_access_key.ecs_user_key.id |
||||
} |
||||
|
||||
output "aws_secret_access_key" { |
||||
value = aws_iam_access_key.ecs_user_key.secret |
||||
} |
@ -0,0 +1,19 @@ |
||||
variable "aws_region" { |
||||
description = "AWS region" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_name" { |
||||
description = "The name of the validator" |
||||
type = string |
||||
} |
||||
|
||||
variable "aws_log_group" { |
||||
description = "The name of the log group to write to" |
||||
type = string |
||||
} |
||||
|
||||
variable "efs_access_point_arn" { |
||||
description = "The ARN of the EFS access point" |
||||
type = string |
||||
} |
@ -0,0 +1,65 @@ |
||||
# This resource creates an S3 bucket used to store validator signatures. |
||||
# The `force_destroy` attribute is set to true to allow the bucket to be destroyed even if it contains objects. |
||||
resource "aws_s3_bucket" "validator_bucket" { |
||||
bucket = "${var.validator_name}-signatures" |
||||
force_destroy = true # Enables deletion of non-empty bucket during destroy operation |
||||
} |
||||
|
||||
# This resource applies a public access block configuration to the validator signatures bucket. |
||||
# It prevents public ACLs from being applied to the bucket and ignores any public ACLs already on the bucket. |
||||
resource "aws_s3_bucket_public_access_block" "validator_bucket_public_access_block" { |
||||
bucket = aws_s3_bucket.validator_bucket.id |
||||
|
||||
block_public_acls = true # Blocks public ACLs from being added to the bucket |
||||
ignore_public_acls = true # Ignores any public ACLs currently associated with the bucket |
||||
block_public_policy = false # Allows public bucket policies (not recommended for sensitive data) |
||||
restrict_public_buckets = false # Allows unrestricted public access to the bucket (not recommended for sensitive data) |
||||
} |
||||
|
||||
# This resource defines a bucket policy that allows public read access to the bucket and its objects. |
||||
# It also grants additional permissions to a specific IAM role to delete and put objects in the bucket. |
||||
resource "aws_s3_bucket_policy" "validator_bucket_policy" { |
||||
bucket = aws_s3_bucket.validator_bucket.id |
||||
policy = jsonencode({ |
||||
Version = "2012-10-17", |
||||
Statement = [ |
||||
{ |
||||
Effect = "Allow", |
||||
Principal = "*", |
||||
Action = [ |
||||
"s3:GetObject", # Allows retrieval of objects from the bucket |
||||
"s3:ListBucket" # Allows listing of the objects within the bucket |
||||
], |
||||
Resource = [ |
||||
"${aws_s3_bucket.validator_bucket.arn}", # Bucket ARN |
||||
"${aws_s3_bucket.validator_bucket.arn}/*" # All objects within the bucket |
||||
] |
||||
}, |
||||
{ |
||||
Effect = "Allow", |
||||
Principal = { |
||||
AWS = var.validator_iam_user_arn # IAM user ARN of validator |
||||
}, |
||||
Action = [ |
||||
"s3:PutObject", # Allows uploading of new objects to the bucket |
||||
"s3:GetObject", # Allows retrieval of objects from the bucket |
||||
"s3:ListBucket", # Allows listing of the objects within the bucket |
||||
"s3:DeleteObject", # Allows deletion of objects within the bucket |
||||
], |
||||
Resource = [ |
||||
"${aws_s3_bucket.validator_bucket.arn}", # Bucket ARN |
||||
"${aws_s3_bucket.validator_bucket.arn}/*" # All objects within the bucket |
||||
] |
||||
} |
||||
] |
||||
}) |
||||
} |
||||
|
||||
# This resource enables versioning for the S3 bucket to keep multiple versions of an object in the same bucket. |
||||
# Versioning is useful for data retention and recovery, as it allows you to recover from unintended user actions and application failures. |
||||
resource "aws_s3_bucket_versioning" "validator_bucket_versioning" { |
||||
bucket = aws_s3_bucket.validator_bucket.id |
||||
versioning_configuration { |
||||
status = "Enabled" # Enables versioning for the specified bucket |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
output "validator_bucket_id" { |
||||
value = aws_s3_bucket.validator_bucket.id |
||||
} |
||||
|
||||
output "validator_bucket_arn" { |
||||
value = aws_s3_bucket.validator_bucket.arn |
||||
} |
@ -0,0 +1,9 @@ |
||||
variable "validator_name" { |
||||
description = "The name of the validator" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_iam_user_arn" { |
||||
description = "The ARN of the IAM user that will write to the S3 bucket" |
||||
type = string |
||||
} |
@ -0,0 +1,138 @@ |
||||
# Sets up roles, permissions and KMS key |
||||
# Replaces https://docs.hyperlane.xyz/docs/operate/set-up-agent-keys |
||||
module "iam_kms" { |
||||
source = "../iam_kms" |
||||
|
||||
aws_region = var.aws_region |
||||
aws_log_group = var.aws_log_group |
||||
validator_name = var.validator_name |
||||
efs_access_point_arn = module.efs.access_point_arn |
||||
} |
||||
|
||||
# Creates bucket for posting validator signatures |
||||
# Replaces https://docs.hyperlane.xyz/docs/operate/validators/validator-aws |
||||
module "s3" { |
||||
source = "../s3" |
||||
|
||||
validator_name = var.validator_name |
||||
validator_iam_user_arn = module.iam_kms.ecs_user_arn |
||||
} |
||||
|
||||
# Creates file system and mounting point for the validator task |
||||
module "efs" { |
||||
source = "../efs" |
||||
|
||||
creation_token = "${var.validator_name}-db-fs" |
||||
subnet_id = var.validator_subnet_id |
||||
security_group_ids = [var.validator_sg_id] |
||||
} |
||||
|
||||
# A template for running the validator task |
||||
resource "aws_ecs_task_definition" "validator" { |
||||
family = var.validator_name |
||||
network_mode = "awsvpc" |
||||
requires_compatibilities = ["FARGATE"] |
||||
cpu = var.validator_cpu |
||||
memory = var.validator_memory |
||||
execution_role_arn = module.iam_kms.validator_execution_role_arn |
||||
task_role_arn = module.iam_kms.validator_task_role_arn |
||||
|
||||
container_definitions = jsonencode([ |
||||
{ |
||||
name = "validator", |
||||
image = "gcr.io/abacus-labs-dev/hyperlane-agent:${var.validator_image_version}", |
||||
user = "1000:1000", |
||||
secrets = [ |
||||
{ |
||||
name = "AWS_ACCESS_KEY_ID", |
||||
valueFrom = module.iam_kms.ecs_user_access_key_id_arn |
||||
}, |
||||
{ |
||||
name = "AWS_SECRET_ACCESS_KEY", |
||||
valueFrom = module.iam_kms.ecs_user_secret_access_key_arn |
||||
} |
||||
], |
||||
mountPoints = [ |
||||
{ |
||||
sourceVolume = "hyperlane_db", |
||||
containerPath = "/hyperlane_db" |
||||
}, |
||||
], |
||||
portMappings = [ |
||||
{ |
||||
containerPort = 9090, # Prometheus metrics port |
||||
hostPort = 9090 |
||||
} |
||||
], |
||||
command = [ |
||||
"./validator", |
||||
"--db", |
||||
"/hyperlane_db", |
||||
"--originChainName", |
||||
var.origin_chain_name, |
||||
"--validator.type", |
||||
"aws", |
||||
"--validator.id", |
||||
module.iam_kms.validator_signer_key_alias, |
||||
"--chains.${var.origin_chain_name}.type", |
||||
"aws", |
||||
"--chains.${var.origin_chain_name}.id", |
||||
module.iam_kms.validator_signer_key_alias, |
||||
"--checkpointSyncer.type", |
||||
"s3", |
||||
"--checkpointSyncer.bucket", |
||||
module.s3.validator_bucket_id, |
||||
"--checkpointSyncer.region", |
||||
var.aws_region, |
||||
"--validator.region", |
||||
var.aws_region |
||||
], |
||||
logConfiguration = { |
||||
logDriver = "awslogs", |
||||
options = { |
||||
"awslogs-group" = var.aws_log_group, |
||||
"awslogs-region" = var.aws_region, |
||||
"awslogs-stream-prefix" = "ecs" |
||||
} |
||||
} |
||||
} |
||||
]) |
||||
|
||||
volume { |
||||
name = "hyperlane_db" |
||||
|
||||
efs_volume_configuration { |
||||
file_system_id = module.efs.file_system_id |
||||
transit_encryption = "ENABLED" |
||||
|
||||
authorization_config { |
||||
access_point_id = module.efs.access_point_id |
||||
iam = "ENABLED" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
# An ECS service for running the validator ECS task |
||||
resource "aws_ecs_service" "validator_service" { |
||||
name = var.validator_name |
||||
cluster = var.validator_cluster_id |
||||
task_definition = aws_ecs_task_definition.validator.arn |
||||
launch_type = "FARGATE" |
||||
|
||||
# avoid rolling deployments to not lock agent db |
||||
deployment_maximum_percent = 100 |
||||
deployment_minimum_healthy_percent = 0 |
||||
|
||||
network_configuration { |
||||
subnets = [var.validator_subnet_id] |
||||
security_groups = [var.validator_sg_id] |
||||
} |
||||
|
||||
desired_count = var.validator_task_disabled ? 0 : 1 |
||||
|
||||
# implicit dependency on nat gateway existing |
||||
tags = { |
||||
NatGatewayID = var.validator_nat_gateway_id |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
output "validator_info" { |
||||
value = { |
||||
aws_access_key_id = module.iam_kms.aws_access_key_id, |
||||
aws_secret_access_key = module.iam_kms.aws_secret_access_key, |
||||
aws_kms_alias = module.iam_kms.validator_signer_key_alias, |
||||
aws_s3_bucket_id = module.s3.validator_bucket_id, |
||||
aws_region = var.aws_region, |
||||
} |
||||
} |
@ -0,0 +1,64 @@ |
||||
variable "aws_region" { |
||||
description = "AWS region" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_cluster_id" { |
||||
description = "ID of the validator cluster" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_subnet_id" { |
||||
description = "ID of the validator subnet" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_sg_id" { |
||||
description = "ID of the validator security group" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_nat_gateway_id" { |
||||
description = "ID of the validator NAT gateway" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_name" { |
||||
description = "The name of the validator" |
||||
type = string |
||||
} |
||||
|
||||
variable "origin_chain_name" { |
||||
description = "The origin chain of the validator" |
||||
type = string |
||||
} |
||||
|
||||
variable "validator_cpu" { |
||||
description = "CPU units used by the validator. Default 1 vCPU." |
||||
type = string |
||||
default = "1024" |
||||
} |
||||
|
||||
variable "validator_memory" { |
||||
description = "Memory units used by the validator. Default 6GB." |
||||
type = string |
||||
default = "6144" |
||||
} |
||||
|
||||
variable "aws_log_group" { |
||||
description = "The name of the log group to write to" |
||||
type = string |
||||
default = "DefaultLogGroup" |
||||
} |
||||
|
||||
variable "validator_image_version" { |
||||
description = "The name of the log group to write to" |
||||
type = string |
||||
default = "f44589e-20231130-114734" |
||||
} |
||||
|
||||
variable "validator_task_disabled" { |
||||
description = "Whether to run the validator in addition to auxiliary setup" |
||||
type = bool |
||||
default = false |
||||
} |
@ -0,0 +1,4 @@ |
||||
output "your_validator_name" { |
||||
value = module.your_validator_name.validator_info |
||||
sensitive = true |
||||
} |
@ -0,0 +1,5 @@ |
||||
variable "aws_region" { |
||||
description = "AWS region" |
||||
type = string |
||||
default = "us-east-1" |
||||
} |
Loading…
Reference in new issue