Skip to content

Commit 68edef8

Browse files
feat: Add example for connecting via Session Manager without Internet access (#336)
Co-authored-by: Bryant Biggs <bryantbiggs@gmail.com>
1 parent 376fba8 commit 68edef8

File tree

10 files changed

+293
-4
lines changed

10 files changed

+293
-4
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/antonbabenko/pre-commit-terraform
3-
rev: v1.81.0
3+
rev: v1.83.0
44
hooks:
55
- id: terraform_fmt
66
- id: terraform_wrapper_module_for_each

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Users of Terragrunt can achieve similar results by using modules provided in the
8484
## Examples
8585

8686
- [Complete EC2 instance](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete)
87+
- [EC2 instance w/ private network access via Session Manager](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/session-manager)
8788
- [EC2 instance with EBS volume attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment)
8889

8990
## Make an encrypted AMI for use

examples/complete/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ resource "aws_ec2_capacity_reservation" "targeted" {
359359
################################################################################
360360
# EC2 Module - CPU Options
361361
################################################################################
362+
362363
module "ec2_cpu_options" {
363364
source = "../../"
364365

examples/session-manager/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# EC2 instance w/ private network access via Session Manager
2+
3+
The configuration in this directory creates an EC2 instance not connected to the Internet that can be accessed using Session Manager through VPC Endpoints.
4+
5+
This example outputs instance id, ARN, state, and tags.
6+
7+
## Usage
8+
9+
To run this example you need to execute:
10+
11+
```bash
12+
$ terraform init
13+
$ terraform plan
14+
$ terraform apply
15+
```
16+
17+
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:
18+
19+
```bash
20+
aws ssm start-session --target <INSTANCE-ID> --region <REGION>
21+
```
22+
23+
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).
24+
25+
Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources.
26+
27+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
28+
## Requirements
29+
30+
| Name | Version |
31+
|------|---------|
32+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
33+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.66 |
34+
35+
## Providers
36+
37+
| Name | Version |
38+
|------|---------|
39+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.66 |
40+
41+
## Modules
42+
43+
| Name | Source | Version |
44+
|------|--------|---------|
45+
| <a name="module_ec2"></a> [ec2](#module\_ec2) | ../../ | n/a |
46+
| <a name="module_security_group_instance"></a> [security\_group\_instance](#module\_security\_group\_instance) | terraform-aws-modules/security-group/aws | ~> 5.0 |
47+
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
48+
| <a name="module_vpc_endpoints"></a> [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 |
49+
50+
## Resources
51+
52+
| Name | Type |
53+
|------|------|
54+
| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
55+
56+
## Inputs
57+
58+
No inputs.
59+
60+
## Outputs
61+
62+
| Name | Description |
63+
|------|-------------|
64+
| <a name="output_ec2_arn"></a> [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance |
65+
| <a name="output_ec2_capacity_reservation_specification"></a> [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance |
66+
| <a name="output_ec2_ebs_block_device"></a> [ec2\_ebs\_block\_device](#output\_ec2\_ebs\_block\_device) | EBS block device information |
67+
| <a name="output_ec2_ephemeral_block_device"></a> [ec2\_ephemeral\_block\_device](#output\_ec2\_ephemeral\_block\_device) | Ephemeral block device information |
68+
| <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 |
69+
| <a name="output_ec2_iam_instance_profile_id"></a> [ec2\_iam\_instance\_profile\_id](#output\_ec2\_iam\_instance\_profile\_id) | Instance profile's ID |
70+
| <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 |
71+
| <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 |
72+
| <a name="output_ec2_iam_role_name"></a> [ec2\_iam\_role\_name](#output\_ec2\_iam\_role\_name) | The name of the IAM role |
73+
| <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 |
74+
| <a name="output_ec2_id"></a> [ec2\_id](#output\_ec2\_id) | The ID of the instance |
75+
| <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` |
76+
| <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 |
77+
| <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 |
78+
| <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 |
79+
| <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 |
80+
| <a name="output_ec2_root_block_device"></a> [ec2\_root\_block\_device](#output\_ec2\_root\_block\_device) | Root block device information |
81+
| <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 |
82+
| <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 |
83+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

examples/session-manager/main.tf

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
provider "aws" {
2+
region = local.region
3+
}
4+
5+
data "aws_availability_zones" "available" {}
6+
7+
locals {
8+
name = "ex-${basename(path.cwd)}"
9+
region = "eu-west-1"
10+
11+
vpc_cidr = "10.0.0.0/16"
12+
azs = slice(data.aws_availability_zones.available.names, 0, 3)
13+
14+
tags = {
15+
Name = local.name
16+
Example = local.name
17+
Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance"
18+
}
19+
}
20+
21+
################################################################################
22+
# EC2 Module
23+
################################################################################
24+
25+
module "ec2" {
26+
source = "../../"
27+
28+
name = local.name
29+
30+
subnet_id = element(module.vpc.intra_subnets, 0)
31+
vpc_security_group_ids = [module.security_group_instance.security_group_id]
32+
33+
create_iam_instance_profile = true
34+
iam_role_description = "IAM role for EC2 instance"
35+
iam_role_policies = {
36+
AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
37+
}
38+
39+
tags = local.tags
40+
}
41+
42+
################################################################################
43+
# Supporting Resources
44+
################################################################################
45+
46+
module "vpc" {
47+
source = "terraform-aws-modules/vpc/aws"
48+
version = "~> 5.0"
49+
50+
name = local.name
51+
cidr = local.vpc_cidr
52+
53+
azs = local.azs
54+
intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)]
55+
56+
tags = local.tags
57+
}
58+
59+
module "security_group_instance" {
60+
source = "terraform-aws-modules/security-group/aws"
61+
version = "~> 5.0"
62+
63+
name = "${local.name}-ec2"
64+
description = "Security Group for EC2 Instance Egress"
65+
66+
vpc_id = module.vpc.vpc_id
67+
68+
egress_rules = ["https-443-tcp"]
69+
70+
tags = local.tags
71+
}
72+
73+
module "vpc_endpoints" {
74+
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
75+
version = "~> 5.0"
76+
77+
vpc_id = module.vpc.vpc_id
78+
79+
endpoints = { for service in toset(["ssm", "ssmmessages", "ec2messages"]) :
80+
replace(service, ".", "_") =>
81+
{
82+
service = service
83+
subnet_ids = module.vpc.intra_subnets
84+
private_dns_enabled = true
85+
tags = { Name = "${local.name}-${service}" }
86+
}
87+
}
88+
89+
create_security_group = true
90+
security_group_name_prefix = "${local.name}-vpc-endpoints-"
91+
security_group_description = "VPC endpoint security group"
92+
security_group_rules = {
93+
ingress_https = {
94+
description = "HTTPS from subnets"
95+
cidr_blocks = module.vpc.intra_subnets_cidr_blocks
96+
}
97+
}
98+
99+
tags = local.tags
100+
}

examples/session-manager/outputs.tf

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
output "ec2_id" {
2+
description = "The ID of the instance"
3+
value = module.ec2.id
4+
}
5+
6+
output "ec2_arn" {
7+
description = "The ARN of the instance"
8+
value = module.ec2.arn
9+
}
10+
11+
output "ec2_capacity_reservation_specification" {
12+
description = "Capacity reservation specification of the instance"
13+
value = module.ec2.capacity_reservation_specification
14+
}
15+
16+
output "ec2_instance_state" {
17+
description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`"
18+
value = module.ec2.instance_state
19+
}
20+
21+
output "ec2_primary_network_interface_id" {
22+
description = "The ID of the instance's primary network interface"
23+
value = module.ec2.primary_network_interface_id
24+
}
25+
26+
output "ec2_private_dns" {
27+
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"
28+
value = module.ec2.private_dns
29+
}
30+
31+
output "ec2_public_dns" {
32+
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"
33+
value = module.ec2.public_dns
34+
}
35+
36+
output "ec2_public_ip" {
37+
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"
38+
value = module.ec2.public_ip
39+
}
40+
41+
output "ec2_tags_all" {
42+
description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block"
43+
value = module.ec2.tags_all
44+
}
45+
46+
output "ec2_iam_role_name" {
47+
description = "The name of the IAM role"
48+
value = module.ec2.iam_role_name
49+
}
50+
51+
output "ec2_iam_role_arn" {
52+
description = "The Amazon Resource Name (ARN) specifying the IAM role"
53+
value = module.ec2.iam_role_arn
54+
}
55+
56+
output "ec2_iam_role_unique_id" {
57+
description = "Stable and unique string identifying the IAM role"
58+
value = module.ec2.iam_role_unique_id
59+
}
60+
61+
output "ec2_iam_instance_profile_arn" {
62+
description = "ARN assigned by AWS to the instance profile"
63+
value = module.ec2.iam_instance_profile_arn
64+
}
65+
66+
output "ec2_iam_instance_profile_id" {
67+
description = "Instance profile's ID"
68+
value = module.ec2.iam_instance_profile_id
69+
}
70+
71+
output "ec2_iam_instance_profile_unique" {
72+
description = "Stable and unique string identifying the IAM instance profile"
73+
value = module.ec2.iam_instance_profile_unique
74+
}
75+
76+
output "ec2_root_block_device" {
77+
description = "Root block device information"
78+
value = module.ec2.root_block_device
79+
}
80+
81+
output "ec2_ebs_block_device" {
82+
description = "EBS block device information"
83+
value = module.ec2.ebs_block_device
84+
}
85+
86+
output "ec2_ephemeral_block_device" {
87+
description = "Ephemeral block device information"
88+
value = module.ec2.ephemeral_block_device
89+
}
90+
91+
output "ssm_connect_command" {
92+
description = "The AWS CLI command to connect to the instance using Session Manager"
93+
value = "aws ssm start-session --target ${module.ec2.id} --region ${local.region}"
94+
}

examples/session-manager/variables.tf

Whitespace-only changes.

examples/session-manager/versions.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 4.66"
8+
}
9+
}
10+
}

examples/volume-attachment/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ Note that this example may create resources which can cost money. Run `terraform
2222
| Name | Version |
2323
|------|---------|
2424
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
25-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.20 |
25+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.66 |
2626

2727
## Providers
2828

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

3333
## Modules
3434

examples/volume-attachment/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ terraform {
44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
7-
version = ">= 4.20"
7+
version = ">= 4.66"
88
}
99
}
1010
}

0 commit comments

Comments
 (0)