ec2-node
Creates EC2 instances with IMDSv2, encrypted root volumes, and optional key pairs.
Provisions one or more EC2 instances with IMDSv2 enforced, encrypted root and data EBS volumes, and optional detailed monitoring. Key pairs are created and associated when provided. ami_id is passed in explicitly per instance to keep builds deterministic — there is no AMI lookup or filtering in this module. Instance names are derived from name_prefix, the resolved AWS availability-zone ID, and each instance's name_suffix.
Primary and secondary private IPs can be set explicitly. Secondary IPs are attached to the instance's primary ENI and can be added or changed on existing instances without replacing them, subject to the max IP count for the chosen instance type.
Usage
Basic instance
module "ec2" {
source = "hcassc.jfrog.io/iac-tf-modules-virtual__compute/ec2-node/aws"
version = "0.6.0"
name_prefix = "prod"
instances = {
bastion = {
name_suffix = "bastion"
ami_id = "ami-0123456789abcdef0"
instance_type = "t3.micro"
subnet_id = module.vpc.public_subnet_ids["a"]
security_group_ids = [module.security_groups.ids["bastion"]]
iam_instance_profile = module.iam_role.instance_profile_name
associate_public_ip = true
root_volume = {
size = 20
}
}
}
}
Fixed primary and secondary private IPs
Useful when downstream systems (DNS, firewall rules, peer configs) need to reference stable addresses. Note the instance type's max private-IP-per-ENI limit caps how many secondary IPs you can request — a t3.micro, for example, allows only one secondary IP in addition to the primary.
module "ec2" {
source = "hcassc.jfrog.io/iac-tf-modules-virtual__compute/ec2-node/aws"
version = "0.6.0"
name_prefix = "prod"
instances = {
app-node = {
name_suffix = "app-node"
ami_id = "ami-0123456789abcdef0"
instance_type = "t3.medium"
subnet_id = module.vpc.private_subnet_ids["a"]
security_group_ids = [module.security_groups.ids["app"]]
primary_private_ip = "10.0.1.10"
secondary_private_ips = ["10.0.1.11", "10.0.1.12"]
root_volume = {
size = 20
}
}
}
}
Multiple instances with data volumes and key pair
module "ec2" {
source = "hcassc.jfrog.io/iac-tf-modules-virtual__compute/ec2-node/aws"
version = "0.6.0"
name_prefix = "prod"
key_pairs = {
ops = {
name = "ops-team"
public_key = file("${path.module}/keys/ops.pub")
}
}
instances = {
db-primary = {
name_suffix = "db-primary"
ami_id = "ami-0123456789abcdef0"
instance_type = "r6g.large"
subnet_id = module.vpc.private_subnet_ids["a"]
security_group_ids = [module.security_groups.ids["db"]]
key_name = "ops"
primary_private_ip = "10.0.2.10"
root_volume = {
size = 20
}
data_volumes = [
{
device_name = "/dev/xvdf"
volume_size = 200
volume_type = "gp3"
iops = 6000
throughput = 250
}
]
instance_tags = {
role = "database"
}
}
db-replica = {
name_suffix = "db-replica"
ami_id = "ami-0123456789abcdef0"
instance_type = "r6g.large"
subnet_id = module.vpc.private_subnet_ids["b"]
security_group_ids = [module.security_groups.ids["db"]]
key_name = "ops"
primary_private_ip = "10.0.3.10"
root_volume = {
size = 20
}
data_volumes = [
{
device_name = "/dev/xvdf"
volume_size = 200
}
]
instance_tags = {
role = "database-replica"
}
}
}
tags = {
environment = "prod"
team = "platform"
}
}
Requirements
Providers
| Name |
Version |
| aws |
>= 6.0, < 7.0 |
Resources
| Name |
Description |
Type |
Default |
Required |
| name_prefix |
Prefix prepended to resource names created by this module |
string |
n/a |
yes |
| instances |
Map of EC2 instance definitions.- ami_id is passed in explicitly to ensure deterministic builds.- name_suffix is appended to resources to ensure standardized names. |
map(object({ name_suffix = string ami_id = string instance_type = string subnet_id = string security_group_ids = list(string) iam_instance_profile = optional(string) key_name = optional(string) associate_public_ip = optional(bool, false) ebs_optimized = optional(bool, true) monitoring = optional(bool, false) placement_group = optional(string) tenancy = optional(string, "default") primary_private_ip = optional(string) secondary_private_ips = optional(list(string), []) # User data — mutually exclusive user_data = optional(string) user_data_base64 = optional(string) # IMDSv2 — tokens required by default, hop limit 1 unless overridden (e.g. ECS needs 2) metadata_http_tokens = optional(string, "required") metadata_hop_limit = optional(number, 1) # Root volume root_volume = object({ size = number type = optional(string, "gp3") kms_key_id = optional(string) delete_on_termination = optional(bool, true) tags = optional(map(string), {}) }) # Additional EBS data volumes data_volumes = optional(list(object({ device_name = string volume_size = number volume_type = optional(string, "gp3") kms_key_id = optional(string) delete_on_termination = optional(bool, true) iops = optional(number) throughput = optional(number) tags = optional(map(string), {}) })), []) # Per-instance tags — overrides module level tags instance_tags = optional(map(string), {}) })) |
{} |
no |
| key_pairs |
Map of key pairs to register in AWS EC2.Each entry requires a name and an OpenSSH-format public key stringwhich may be sourced from a secret store or a TLS provider. |
map(object({ name = string public_key = string })) |
{} |
no |
| tags |
Tags applied to all resources in this module. |
map(string) |
{} |
no |
Outputs