# 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

```hcl
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.

```hcl
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

```hcl
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"
  }
}
```

<!-- BEGIN_TF_DOCS — DO NOT EDIT BELOW THIS LINE -->

## Requirements

| Name                                                                     | Version            |
| ------------------------------------------------------------------------ | ------------------ |
| <a name="requirement_terraform"></a> [terraform](#requirement_terraform) | >= 1.15.0, < 2.0.0 |
| <a name="requirement_aws"></a> [aws](#requirement_aws)                   | >= 6.0, < 7.0      |

## Providers

| Name                                             | Version       |
| ------------------------------------------------ | ------------- |
| <a name="provider_aws"></a> [aws](#provider_aws) | >= 6.0, < 7.0 |

## Resources

| Name                                                                                                                        | Type     |
| --------------------------------------------------------------------------------------------------------------------------- | -------- |
| [aws_ebs_volume.data](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume)               | resource |
| [aws_instance.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance)                   | resource |
| [aws_key_pair.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair)                   | resource |
| [aws_volume_attachment.data](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/volume_attachment) | resource |

## Inputs

| Name                                                               | Description                                                                                                                                                                         | Type                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Default | Required |
| ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | :------: |
| <a name="input_name_prefix"></a> [name_prefix](#input_name_prefix) | Prefix prepended to resource names created by this module                                                                                                                           | `string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | n/a     |   yes    |
| <a name="input_instances"></a> [instances](#input_instances)       | Map of EC2 instance definitions.<br/><br/>- ami_id is passed in explicitly to ensure deterministic builds.<br/>- name_suffix is appended to resources to ensure standardized names. | <pre>map(object({<br/> name_suffix = string<br/> ami_id = string<br/> instance_type = string<br/> subnet_id = string<br/> security_group_ids = list(string)<br/> iam_instance_profile = optional(string)<br/> key_name = optional(string)<br/> associate_public_ip = optional(bool, false)<br/> ebs_optimized = optional(bool, true)<br/> monitoring = optional(bool, false)<br/> placement_group = optional(string)<br/> tenancy = optional(string, "default")<br/> primary_private_ip = optional(string)<br/> secondary_private_ips = optional(list(string), [])<br/><br/> # User data — mutually exclusive<br/> user_data = optional(string)<br/> user_data_base64 = optional(string)<br/><br/> # IMDSv2 — tokens required by default, hop limit 1 unless overridden (e.g. ECS needs 2)<br/> metadata_http_tokens = optional(string, "required")<br/> metadata_hop_limit = optional(number, 1)<br/><br/> # Root volume<br/> root_volume = object({<br/> size = number<br/> type = optional(string, "gp3")<br/> kms_key_id = optional(string)<br/> delete_on_termination = optional(bool, true)<br/> tags = optional(map(string), {})<br/> })<br/><br/> # Additional EBS data volumes<br/> data_volumes = optional(list(object({<br/> device_name = string<br/> volume_size = number<br/> volume_type = optional(string, "gp3")<br/> kms_key_id = optional(string)<br/> delete_on_termination = optional(bool, true)<br/> iops = optional(number)<br/> throughput = optional(number)<br/> tags = optional(map(string), {})<br/> })), [])<br/><br/> # Per-instance tags — overrides module level tags<br/> instance_tags = optional(map(string), {})<br/> }))</pre> | `{}`    |    no    |
| <a name="input_key_pairs"></a> [key_pairs](#input_key_pairs)       | Map of key pairs to register in AWS EC2.<br/>Each entry requires a name and an OpenSSH-format public key string<br/>which may be sourced from a secret store or a TLS provider.     | <pre>map(object({<br/> name = string<br/> public_key = string<br/> }))</pre>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | `{}`    |    no    |
| <a name="input_tags"></a> [tags](#input_tags)                      | Tags applied to all resources in this module.                                                                                                                                       | `map(string)`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `{}`    |    no    |

## Outputs

| Name                                                                                                     | Description                                                                      |
| -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| <a name="output_ami_ids"></a> [ami_ids](#output_ami_ids)                                                 | Map of instance keys to the AMI ID in use.                                       |
| <a name="output_data_volume_attachments"></a> [data_volume_attachments](#output_data_volume_attachments) | Map of data volume keys to attached volume IDs.                                  |
| <a name="output_data_volume_ids"></a> [data_volume_ids](#output_data_volume_ids)                         | Map of data volume keys to EBS volume IDs.                                       |
| <a name="output_instance_arns"></a> [instance_arns](#output_instance_arns)                               | Map of instance keys to instance ARNs.                                           |
| <a name="output_instance_ids"></a> [instance_ids](#output_instance_ids)                                  | Map of instance keys to instance IDs.                                            |
| <a name="output_key_pair_fingerprints"></a> [key_pair_fingerprints](#output_key_pair_fingerprints)       | Map of key pair keys to fingerprints.                                            |
| <a name="output_key_pair_ids"></a> [key_pair_ids](#output_key_pair_ids)                                  | Map of key pair keys to AWS key pair IDs.                                        |
| <a name="output_network_interface_ids"></a> [network_interface_ids](#output_network_interface_ids)       | Map of instance keys to primary network interface IDs (for manual ENI IP tests). |
| <a name="output_primary_private_ips"></a> [primary_private_ips](#output_primary_private_ips)             | Map of instance keys to primary private IP addresses.                            |
| <a name="output_private_dns"></a> [private_dns](#output_private_dns)                                     | Map of instance keys to private DNS names.                                       |
| <a name="output_public_ips"></a> [public_ips](#output_public_ips)                                        | Map of instance keys to public IP addresses. Null if no public IP assigned.      |
| <a name="output_secondary_private_ips"></a> [secondary_private_ips](#output_secondary_private_ips)       | Map of instance keys to their secondary private IP addresses.                    |

<!-- END_TF_DOCS — DO NOT EDIT ABOVE THIS LINE -->
