This Terraform module opens tunnels to your VPC resources using AWS Systems Manager Session Manager, right from your Terraform code. This enables you to provision VPC resources (e.g. databases in RDS, etc.) from wherever your Terraform code runs on the Internet without manually provisioning a bastion host, arranging VPN access or splitting your Terraform code into more modules.
Although designed for seamless use with our terraform-aws-ssm-bastion-fargate module, it can be used with any ECS service with ECS Exec enabled.
This module was inspired by flaupretre's terraform-ssh-tunnel.
- Opens a tunnel to any host/port, relayed through an existing ECS task running in your VPC through AWS SSM Session Manager
- Finds the bastion ECS task automatically using the provided ECS cluster and service names
- Supports all TCP port forwarding use cases
- Supports doing
plan
andapply
separately (terraform plan -out=...
andterraform apply ...
), including in different CI/CD stages, by opening the tunnel in both stages (optional, setseparate_plan_apply
to enable) - Uses default AWS CLI authentication mechanisms to automatically authenticate with AWS
- Supports using an AWS profile for authentication
- Supports additional AssumeRole/AssumeRoleWithWebIdentity (with a token supplied in a file or an environment variable). Both can be combined in role chaining scenarios
module "tunnel_rds" {
source = "github.com/nativelycloud/terraform-aws-ssm-tunnel?ref=v0.1.0"
ecs_bastion_cluster_name = "my-ecs-cluster"
ecs_bastion_service_name = "my-bastion-service"
target_host = aws_db_instance.this.address
target_port = 5432
local_port = 5432
}
provider "postgresql" {
# Use at least one of the module's outputs or depends_on it to ensure the tunnel is setup before connecting
host = module.tunnel_rds.local_host
port = module.tunnel_rds.local_port
database = "postgres"
username = aws_db_instance.this.username
password = aws_db_instance.this.password
}
See the examples directory for full usage examples.
terraform-aws-ssm-tunnel
versus other similar modules
- Do one thing and do it well — this module is focused on SSM Session Manager tunneling only and does not support other tunneling methods
- Simpler architecture — we start the tunnel with AWS CLI directly, without using an intermediate SSH session
- Support for separate plan/apply stages — this module supports running
plan
andapply
separately, including in completely different CI/CD stages
We try to keep requirements on the environment running Terraform at a minimum. The module requires sh
, the AWS CLI, the session-manager-plugin
for AWS CLI, printenv
, grep
, and cut
to be available in the environment.
The principal running the module must have at least the following IAM permissions:
ecs:ListTasks
on the target ECS clusterecs:DescribeTasks
on the target ECS clusterssm:StartSession
on the target task for the "AWS-StartPortForwardingSessionToRemoteHost" SSM document
This module does not incur any additional costs beyond the existing bastion ECS task cost and possible outbound data transfer costs for tunneled data.
- When doing separate
plan
andapply
, destroys usingplan -destroy
are not supported. A workaround is to remove resources from the Terraform code and run a regularplan
andapply
cycle, or to do aterraform destroy
without aplan
.
- EC2 bastion support
- Ability to specify the bastion ECS task ARN directly
- Smarter bastion ECS task selection (ignore tasks that are not running)
- Better logging
- Windows support (not planned yet)
Name | Version |
---|---|
terraform | >= 1.0 |
aws | >= 5.0 |
external | >= 1.0 |
Name | Version |
---|---|
aws | >= 5.0 |
external | >= 1.0 |
No modules.
Name | Type |
---|---|
aws_region.current | data source |
external_external.apply | data source |
external_external.plan | data source |
Name | Description | Type | Default | Required |
---|---|---|---|---|
assume_role_arn | If set, the module will assume this role before starting the tunnel. If both this variable and assume_role_with_web_identity_role_arn are set, the module will do role chaining, assuming the Web Identity role first and then this one |
string |
null |
no |
assume_role_session_name | The name of the session when assuming the role | string |
"terraform-aws-ssm-tunnel" |
no |
assume_role_with_web_identity_role_arn | If set, the module will assume this role with the Web Identity token | string |
null |
no |
assume_role_with_web_identity_role_session_name | The name of the session when assuming the role with the Web Identity token | string |
"terraform-aws-ssm-tunnel" |
no |
assume_role_with_web_identity_token_env_var_name | If set, the module will assume the role with the Web Identity token stored in the environment variable with this name. Mutually exclusive with assume_role_with_web_identity_token_file_path |
string |
null |
no |
assume_role_with_web_identity_token_file_path | If set, the module will assume the role with the Web Identity token stored in the specified file. Mutually exclusive with assume_role_with_web_identity_token_env_var_name |
string |
null |
no |
aws_profile | If set, the module will use this AWS profile to start the tunnel | string |
null |
no |
ecs_bastion_cluster_name | The name of the ECS cluster where the bastion service is running | string |
n/a | yes |
ecs_bastion_service_name | The name of the ECS service running the bastion | string |
n/a | yes |
local_port | The local port where the tunnel will listen | number |
n/a | yes |
separate_plan_apply | Set to true if you run plan and apply separately (terraform plan -out=... and terraform apply ... rather than a single terraform apply ). This will ensure the tunnel is available on both stages. |
bool |
false |
no |
ssm_document_name | The name of the SSM document to use to start the tunnel | string |
"AWS-StartPortForwardingSessionToRemoteHost" |
no |
target_host | The host to forward traffic to | string |
n/a | yes |
target_port | The port to forward traffic to | number |
n/a | yes |
Name | Description |
---|---|
local_host | The local host to connect to |
local_port | The local port to connect to |