Skip to content

An SSH tunnel with ssm to configure resources behind a bastion host

License

Notifications You must be signed in to change notification settings

littlejo/terraform-ssm-tunnel

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This terraform module allows to communicate with a resource via an SSH tunnel.

I use it to create and configure databases on AWS RDS instances but it can be used to access any target/port. My RDS instances are connected to private subnets only and, so, cannot be accessed directly from the desktop I'm running terraform on. Running terraform on a host inside the VPC could be a solution but too complex to install and manage. An easier solution was to access my resources via an SSH tunnel on an SSH bastion host. Everything you need is a host which can connect to your private resources and that you can access from your client using SSH (this is generally named 'bastion host').

Please note that, when the 'create' input variable is false or the 'gateway_host' input variable is an empty string, no tunnel is created and the target host and port are returned, causing a direct connection to the target. So, input variables are used to decide whether a tunnel is wanted or not.

SSH command and options

By default, the module will use the 'ssh' string to launch the SSH client executable. This implies, among others that running 'ssh ' opens a connection to the bastion host (without asking any confirmation).

But you may need to modify this string if, for instance, you want to:

  • specify an absolute path and/or a different name when your SSH client is not in your path or has a different name (some use 'openssh')
  • Add options to pass to the SSH command like, '-o StrictHostKeyChecking=no' to avoid failures on non-registered bastions or '-i <key>' to specify an alternate private key.

Specifying an alternate SSH command is done by setting the 'ssh_cmd' variable to the command with options.

Please note that the SSH process inherits your environment, including a possible SSH agent configuration to retrieve your private key.

Target host name resolution

When supplying the target DNS name, note that the name will be resolved by the bastion host, not by the client you're running terraform on. So, you can use a private DNS name, like 'xxxx.csdfkzpf0iww.eu-west-1.rds.amazonaws.com' without having to convert it to an IP address first.

Combining multiple providers

As you can see in the example below, using a provider alias is encouraged as it is cleaner and makes it possible from a single provider to combine access to multiple targets, either tunneled or not.

Examples

SSM

module "ssh_tunnel" {
  source = "github.com/littlejo/terraform-ssm-tunnel"

  target_host  = split("https://", data.aws_eks_cluster.this.endpoint)[1]
  target_port  = "443"
  aws_profile  = "YOUR_PROFILE_TO_ACCESS_YOUR_BASTION"
  gateway_user = "ec2-user"

  ssm_instance_name = "bastion"
}

data "aws_eks_cluster" "this" {
  name = "eks_cluster"
}

SSH

# On AWS, if your bastions are in an autoscaling group,here's a way
# to get a public IP address to use as gateway :

data aws_instances bastions {
  instance_tags = {
    "aws:autoscaling:groupName" = "replace_with_bastion_autoscaling_group_name"
  }
}

#----

module db_tunnel {
  # You can also retrieve this module from the terraform registry
  source       = "flaupretre/tunnel/ssh"
  version      = "1.5.0"

  target_host  = aws_db_instance.mydb.address
  target_port  = aws_db_instance.mydb.port

  gateway_host = data.aws_instances.bastions.public_ips[0]
}

#----

provider mysql {
  alias    = "tunnel"

  endpoint = "${module.db_tunnel.host}:${module.db_tunnel.port}"

  # Target credentials
  username = aws_db_instance.mydb.username
  password = aws_db_instance.mydb.password
}

#---- DB resources

resource mysql_database this {
  provider = mysql.tunnel
  name = local.name
}

resource mysql_user user {
  provider = mysql.tunnel
  ....

You may also be interested by the terraform-ssh-tunnel-databases module, which uses SSH tunnels to manage MySql/PostgreSql databases, roles, and permissions.

Requirements

No requirements.

Providers

Name Version
external n/a

Modules

No modules.

Resources

Name Type
external_external.free_port data source
external_external.ssh_tunnel data source

Inputs

Name Description Type Default Required
aws_profile aws profile string "" no
create If false, do nothing and return target host bool true no
gateway_host Name or IP of SSH gateway - empty string if no gateway (direct connection) any "" no
gateway_port Gateway port number 22 no
gateway_user User to use on SSH gateway (default = empty string = current username) any "" no
local_host Local host name or IP. Set only if you cannot use the '127.0.0.1' default value string "127.0.0.1" no
python_cmd Command to run python string "python" no
shell_cmd Command to run a shell string "bash" no
ssh_cmd Shell command to use to start ssh client string "ssh -o StrictHostKeyChecking=no" no
ssh_tunnel_check_sleep extra time to wait for ssh tunnel to connect string "0s" no
ssm_instance_name ssm instance name (for aws) string "" no
target_host The target host. Name will be resolved by gateway string n/a yes
target_port Target port number number n/a yes
timeout Timeout value ensures tunnel won't remain open forever string "30m" no

Outputs

Name Description
host Host to connect to
kubernetes_host Host to connect to
port Port number to connect to

About

An SSH tunnel with ssm to configure resources behind a bastion host

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages

  • Shell 51.5%
  • HCL 47.6%
  • Makefile 0.9%