Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add example for connecting via Session Manager without Internet access #336

Merged
merged 8 commits into from
Aug 30, 2023
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ resource "aws_ec2_capacity_reservation" "targeted" {
################################################################################
# EC2 Module - CPU Options
################################################################################

module "ec2_cpu_options" {
source = "../../"

Expand Down
83 changes: 83 additions & 0 deletions examples/session-manager/README.md
Original file line number Diff line number Diff line change
@@ -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 <INSTANCE-ID> --region <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.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.66 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.66 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ec2"></a> [ec2](#module\_ec2) | ../../ | n/a |
| <a name="module_security_group_instance"></a> [security\_group\_instance](#module\_security\_group\_instance) | terraform-aws-modules/security-group/aws | ~> 5.0 |
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
| <a name="module_vpc_endpoints"></a> [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 |
|------|-------------|
| <a name="output_ec2_arn"></a> [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance |
| <a name="output_ec2_capacity_reservation_specification"></a> [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance |
| <a name="output_ec2_ebs_block_device"></a> [ec2\_ebs\_block\_device](#output\_ec2\_ebs\_block\_device) | EBS block device information |
| <a name="output_ec2_ephemeral_block_device"></a> [ec2\_ephemeral\_block\_device](#output\_ec2\_ephemeral\_block\_device) | Ephemeral block device information |
| <a name="output_ec2_iam_instance_profile_arn"></a> [ec2\_iam\_instance\_profile\_arn](#output\_ec2\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile |
| <a name="output_ec2_iam_instance_profile_id"></a> [ec2\_iam\_instance\_profile\_id](#output\_ec2\_iam\_instance\_profile\_id) | Instance profile's ID |
| <a name="output_ec2_iam_instance_profile_unique"></a> [ec2\_iam\_instance\_profile\_unique](#output\_ec2\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile |
| <a name="output_ec2_iam_role_arn"></a> [ec2\_iam\_role\_arn](#output\_ec2\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role |
| <a name="output_ec2_iam_role_name"></a> [ec2\_iam\_role\_name](#output\_ec2\_iam\_role\_name) | The name of the IAM role |
| <a name="output_ec2_iam_role_unique_id"></a> [ec2\_iam\_role\_unique\_id](#output\_ec2\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role |
| <a name="output_ec2_id"></a> [ec2\_id](#output\_ec2\_id) | The ID of the instance |
| <a name="output_ec2_instance_state"></a> [ec2\_instance\_state](#output\_ec2\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` |
| <a name="output_ec2_primary_network_interface_id"></a> [ec2\_primary\_network\_interface\_id](#output\_ec2\_primary\_network\_interface\_id) | The ID of the instance's primary network interface |
| <a name="output_ec2_private_dns"></a> [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 |
| <a name="output_ec2_public_dns"></a> [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 |
| <a name="output_ec2_public_ip"></a> [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 |
| <a name="output_ec2_root_block_device"></a> [ec2\_root\_block\_device](#output\_ec2\_root\_block\_device) | Root block device information |
| <a name="output_ec2_tags_all"></a> [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 |
| <a name="output_ssm_connect_command"></a> [ssm\_connect\_command](#output\_ssm\_connect\_command) | The AWS CLI command to connect to the instance using Session Manager |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
100 changes: 100 additions & 0 deletions examples/session-manager/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
94 changes: 94 additions & 0 deletions examples/session-manager/outputs.tf
Original file line number Diff line number Diff line change
@@ -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}"
}
Empty file.
10 changes: 10 additions & 0 deletions examples/session-manager/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.66"
}
}
}
4 changes: 2 additions & 2 deletions examples/volume-attachment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ Note that this example may create resources which can cost money. Run `terraform
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.20 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.66 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.20 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.66 |

## Modules

Expand Down
2 changes: 1 addition & 1 deletion examples/volume-attachment/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.20"
version = ">= 4.66"
}
}
}