diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e79e67b2..762423e1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.81.0 + rev: v1.83.0 hooks: - id: terraform_fmt - id: terraform_wrapper_module_for_each diff --git a/README.md b/README.md index c93c2634..54c21f6d 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Users of Terragrunt can achieve similar results by using modules provided in the ## Examples - [Complete EC2 instance](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) +- [EC2 instance w/ private network access via Session Manager](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/session-manager) - [EC2 instance with EBS volume attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment) ## Make an encrypted AMI for use diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 25baae5e..f14dfd9a 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -359,6 +359,7 @@ resource "aws_ec2_capacity_reservation" "targeted" { ################################################################################ # EC2 Module - CPU Options ################################################################################ + module "ec2_cpu_options" { source = "../../" diff --git a/examples/session-manager/README.md b/examples/session-manager/README.md new file mode 100644 index 00000000..3a08c1d9 --- /dev/null +++ b/examples/session-manager/README.md @@ -0,0 +1,83 @@ +# EC2 instance w/ private network access via Session Manager + +The configuration in this directory creates an EC2 instance not connected to the Internet that can be accessed using Session Manager through VPC Endpoints. + +This example outputs instance id, ARN, state, and tags. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +You can verify that SSM is setup correctly by connecting to the instance. The example output provides the AWS CLI command to connect to the instance under the output `ssm_connect_command` which will look like: + +```bash +aws ssm start-session --target --region +``` + +You will need to have the Session Manager plugin for the AWS CLI installed to execute the command. Instructions for installing can be found [here](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html). + +Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | >= 4.66 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 4.66 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [ec2](#module\_ec2) | ../../ | n/a | +| [security\_group\_instance](#module\_security\_group\_instance) | terraform-aws-modules/security-group/aws | ~> 5.0 | +| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | +| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 | + +## Resources + +| Name | Type | +|------|------| +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance | +| [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | +| [ec2\_ebs\_block\_device](#output\_ec2\_ebs\_block\_device) | EBS block device information | +| [ec2\_ephemeral\_block\_device](#output\_ec2\_ephemeral\_block\_device) | Ephemeral block device information | +| [ec2\_iam\_instance\_profile\_arn](#output\_ec2\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | +| [ec2\_iam\_instance\_profile\_id](#output\_ec2\_iam\_instance\_profile\_id) | Instance profile's ID | +| [ec2\_iam\_instance\_profile\_unique](#output\_ec2\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | +| [ec2\_iam\_role\_arn](#output\_ec2\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | +| [ec2\_iam\_role\_name](#output\_ec2\_iam\_role\_name) | The name of the IAM role | +| [ec2\_iam\_role\_unique\_id](#output\_ec2\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | +| [ec2\_id](#output\_ec2\_id) | The ID of the instance | +| [ec2\_instance\_state](#output\_ec2\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | +| [ec2\_primary\_network\_interface\_id](#output\_ec2\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | +| [ec2\_private\_dns](#output\_ec2\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | +| [ec2\_public\_dns](#output\_ec2\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | +| [ec2\_public\_ip](#output\_ec2\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | +| [ec2\_root\_block\_device](#output\_ec2\_root\_block\_device) | Root block device information | +| [ec2\_tags\_all](#output\_ec2\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | +| [ssm\_connect\_command](#output\_ssm\_connect\_command) | The AWS CLI command to connect to the instance using Session Manager | + diff --git a/examples/session-manager/main.tf b/examples/session-manager/main.tf new file mode 100644 index 00000000..b7896da3 --- /dev/null +++ b/examples/session-manager/main.tf @@ -0,0 +1,100 @@ +provider "aws" { + region = local.region +} + +data "aws_availability_zones" "available" {} + +locals { + name = "ex-${basename(path.cwd)}" + region = "eu-west-1" + + vpc_cidr = "10.0.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) + + tags = { + Name = local.name + Example = local.name + Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance" + } +} + +################################################################################ +# EC2 Module +################################################################################ + +module "ec2" { + source = "../../" + + name = local.name + + subnet_id = element(module.vpc.intra_subnets, 0) + vpc_security_group_ids = [module.security_group_instance.security_group_id] + + create_iam_instance_profile = true + iam_role_description = "IAM role for EC2 instance" + iam_role_policies = { + AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" + } + + tags = local.tags +} + +################################################################################ +# Supporting Resources +################################################################################ + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "~> 5.0" + + name = local.name + cidr = local.vpc_cidr + + azs = local.azs + intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] + + tags = local.tags +} + +module "security_group_instance" { + source = "terraform-aws-modules/security-group/aws" + version = "~> 5.0" + + name = "${local.name}-ec2" + description = "Security Group for EC2 Instance Egress" + + vpc_id = module.vpc.vpc_id + + egress_rules = ["https-443-tcp"] + + tags = local.tags +} + +module "vpc_endpoints" { + source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" + version = "~> 5.0" + + vpc_id = module.vpc.vpc_id + + endpoints = { for service in toset(["ssm", "ssmmessages", "ec2messages"]) : + replace(service, ".", "_") => + { + service = service + subnet_ids = module.vpc.intra_subnets + private_dns_enabled = true + tags = { Name = "${local.name}-${service}" } + } + } + + create_security_group = true + security_group_name_prefix = "${local.name}-vpc-endpoints-" + security_group_description = "VPC endpoint security group" + security_group_rules = { + ingress_https = { + description = "HTTPS from subnets" + cidr_blocks = module.vpc.intra_subnets_cidr_blocks + } + } + + tags = local.tags +} diff --git a/examples/session-manager/outputs.tf b/examples/session-manager/outputs.tf new file mode 100644 index 00000000..4324ddc5 --- /dev/null +++ b/examples/session-manager/outputs.tf @@ -0,0 +1,94 @@ +output "ec2_id" { + description = "The ID of the instance" + value = module.ec2.id +} + +output "ec2_arn" { + description = "The ARN of the instance" + value = module.ec2.arn +} + +output "ec2_capacity_reservation_specification" { + description = "Capacity reservation specification of the instance" + value = module.ec2.capacity_reservation_specification +} + +output "ec2_instance_state" { + description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" + value = module.ec2.instance_state +} + +output "ec2_primary_network_interface_id" { + description = "The ID of the instance's primary network interface" + value = module.ec2.primary_network_interface_id +} + +output "ec2_private_dns" { + description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" + value = module.ec2.private_dns +} + +output "ec2_public_dns" { + description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" + value = module.ec2.public_dns +} + +output "ec2_public_ip" { + description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" + value = module.ec2.public_ip +} + +output "ec2_tags_all" { + description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" + value = module.ec2.tags_all +} + +output "ec2_iam_role_name" { + description = "The name of the IAM role" + value = module.ec2.iam_role_name +} + +output "ec2_iam_role_arn" { + description = "The Amazon Resource Name (ARN) specifying the IAM role" + value = module.ec2.iam_role_arn +} + +output "ec2_iam_role_unique_id" { + description = "Stable and unique string identifying the IAM role" + value = module.ec2.iam_role_unique_id +} + +output "ec2_iam_instance_profile_arn" { + description = "ARN assigned by AWS to the instance profile" + value = module.ec2.iam_instance_profile_arn +} + +output "ec2_iam_instance_profile_id" { + description = "Instance profile's ID" + value = module.ec2.iam_instance_profile_id +} + +output "ec2_iam_instance_profile_unique" { + description = "Stable and unique string identifying the IAM instance profile" + value = module.ec2.iam_instance_profile_unique +} + +output "ec2_root_block_device" { + description = "Root block device information" + value = module.ec2.root_block_device +} + +output "ec2_ebs_block_device" { + description = "EBS block device information" + value = module.ec2.ebs_block_device +} + +output "ec2_ephemeral_block_device" { + description = "Ephemeral block device information" + value = module.ec2.ephemeral_block_device +} + +output "ssm_connect_command" { + description = "The AWS CLI command to connect to the instance using Session Manager" + value = "aws ssm start-session --target ${module.ec2.id} --region ${local.region}" +} diff --git a/examples/session-manager/variables.tf b/examples/session-manager/variables.tf new file mode 100644 index 00000000..e69de29b diff --git a/examples/session-manager/versions.tf b/examples/session-manager/versions.tf new file mode 100644 index 00000000..fd4d1167 --- /dev/null +++ b/examples/session-manager/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.66" + } + } +} diff --git a/examples/volume-attachment/README.md b/examples/volume-attachment/README.md index 3de72392..7c089f0b 100644 --- a/examples/volume-attachment/README.md +++ b/examples/volume-attachment/README.md @@ -22,13 +22,13 @@ Note that this example may create resources which can cost money. Run `terraform | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.20 | +| [aws](#requirement\_aws) | >= 4.66 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.20 | +| [aws](#provider\_aws) | >= 4.66 | ## Modules diff --git a/examples/volume-attachment/versions.tf b/examples/volume-attachment/versions.tf index eddf9d5b..fd4d1167 100644 --- a/examples/volume-attachment/versions.tf +++ b/examples/volume-attachment/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.20" + version = ">= 4.66" } } }