A practical EC2 module — SSM-only by design. No SSH keys are created, stored, or attached; you reach the instance through AWS Session Manager.
Requirements:
- Terraform >= 1.15.0
- Trivy >= 0.68.2
Trivy can be installed via Homebrew on macOS with the command:
brew install aquasecurity/trivy/trivy- No SSH key pair — access is via SSM Session Manager. No private key is generated, written to disk, or stored in Terraform state.
- IMDSv2 required; root EBS volume encrypted
- Instance role limited to
AmazonSSMManagedInstanceCoreplus an optional bucket-scoped S3 policy - You open only the ingress ports you serve — examples open 80/443, never 22
- Scanned with Trivy and gitleaks; integration-tested with Terratest
- Gives to ability for create a EC2 Instance
- EC2 is already setup for SSM Agent to be installed
- Dynamically Create Ingress Security Rules
- Optionally create all network infrastructure needed for public access
- Optionally create public DNS record for the Red Instance
- Optionally pass user data into instance creation
- Optionally enabled S3 Bucket IAM Role Access
Self-contained (creates a minimal public VPC) — see
examples/complete:
provider "aws" {
region = "us-east-1"
}
module "instance" {
source = "RussellGilmore/red-instance/aws"
project_name = "my-project"
instance_name = "web"
ingress_rules = [{
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}]
}Connect with: aws ssm start-session --target <instance_id>.
To place the instance in an existing network (e.g. red-network), set
create_vpc = false and pass vpc_id/subnet_id — see
examples/with-network.
| Name | Version |
|---|---|
| terraform | >= 1.15.0 |
| aws | >= 6.47.0 |
| Name | Version |
|---|---|
| aws | >= 6.47.0 |
No modules.
| Name | Type |
|---|---|
| aws_eip.red_instance_eip | resource |
| aws_iam_instance_profile.red_instance_profile | resource |
| aws_iam_role.red_role | resource |
| aws_iam_role_policy.s3_bucket_policy | resource |
| aws_iam_role_policy_attachment.red_ssm_policy_attachment | resource |
| aws_instance.red-instance | resource |
| aws_internet_gateway.igw | resource |
| aws_route53_record.red_instance_dns | resource |
| aws_route_table.public | resource |
| aws_route_table_association.public | resource |
| aws_security_group.red_sg | resource |
| aws_subnet.public | resource |
| aws_vpc.main | resource |
| aws_ami.red_ami | data source |
| aws_route53_zone.zone | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| additional_tags | Additional tags to apply to all resources created by this module. | map(string) |
{} |
no |
| allocate_eip | Controls whether an Elastic IP should be allocated. | bool |
true |
no |
| ami_name | The name (or name pattern) of the AMI to use for the instance. | string |
"ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-arm64-server-20250610" |
no |
| ami_owner | The owner account ID of the AMI. | string |
"099720109477" |
no |
| apex_domain | Apex domain whose hosted zone holds the DNS record. | string |
"" |
no |
| availability_zone | Availability zone for the created subnet. Leave empty for default placement. | string |
"" |
no |
| create_vpc | Create a minimal public VPC (single subnet + IGW) for the instance. Set false to place the instance in an existing VPC via vpc_id/subnet_id. | bool |
true |
no |
| disable_api_stop | Controls whether API stop is disabled. | bool |
false |
no |
| disable_api_termination | Controls whether API termination is disabled. | bool |
false |
no |
| dns_name | FQDN for the public DNS record. | string |
"" |
no |
| enable_public_dns | Create a public Route53 A record pointing at the instance's EIP. | bool |
false |
no |
| enable_s3_bucket_policy | Attach an S3 access policy (scoped to s3_bucket_name) to the instance role. | bool |
false |
no |
| ingress_rules | List of ingress rules for the instance security group. Access is via SSM Session Manager by default; only open inbound ports you actually serve (e.g. 80/443). | list(object({ |
n/a | yes |
| instance_name | The name of the instance. | string |
n/a | yes |
| instance_tags | Tags to apply only to the EC2 instance resource. | map(string) |
{} |
no |
| instance_type | The instance type to use for the instance. | string |
"t4g.small" |
no |
| project_name | Project name used for naming and the Project tag. | string |
n/a | yes |
| s3_bucket_name | Name of the S3 bucket the instance role may access. | string |
"" |
no |
| subnet_id | ID of an existing subnet to use when create_vpc is false. | string |
"" |
no |
| user_data_script_path | Path to a user data script to run on first boot. | string |
"" |
no |
| volume_size | The size of the root volume in GB. | number |
30 |
no |
| vpc_id | ID of an existing VPC to use when create_vpc is false. | string |
"" |
no |
| Name | Description |
|---|---|
| instance_id | The ID of the EC2 instance. |
| public_dns | The public DNS name of the instance. |
| public_ip | The public IP address of the instance (EIP when allocated). |
| security_group_id | The ID of the instance security group. |
| subnet_id | The ID of the created subnet, or a note when an existing subnet was supplied. |
| vpc_id | The ID of the created VPC, or a note when an existing VPC was supplied. |