Skip to content

Commit

Permalink
Modify README
Browse files Browse the repository at this point in the history
  • Loading branch information
Francois Laupretre committed Dec 21, 2022
1 parent e06254a commit 7663ae6
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 40 deletions.
88 changes: 49 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,70 @@

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.
It is used, for instance, to create and configure databases on AWS RDS instances.
Creating RDS instances is easy, as it uses the AWS API, which is public but, creating
databases is harder because it requires connecting to the instance which is,
usually, connected to private subnets only.
Running terraform on a host inside the AWS VPC would be a solution but often too complex
to install and manage.

## SSH command and options
An alternate solution is to access remote resources via
an SSH tunnel through an SSH bastion host. There are two conditions :

By default, the module will use the 'ssh' string to launch the SSH client
executable. This implies, among others that running 'ssh <bastion host>'
opens a connection to the bastion host (without asking any confirmation).
- The bastion host can open a connection to the target host/port,
- and you can open an SSH connection to the bastion from your client.

But you may need to modify this string if, for instance, you want to:
## Tunnel conditional creation

- 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 '-i \<key>' to specify an
alternate private key to use.
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.

Specifying an alternate SSH command is done by setting the 'ssh_cmd' variable
to the command with options.
So, this module can be used in a scenario where you don't know in advance if
your connection will require a tunnel or not, passing configuration parameters you receive
from the outside, and using the host/port you receive from the module.

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

By default, the module uses the 'ssh -o StrictHostKeyChecking=no' string
in the command to launch the SSH client. If you use a different SSH client name/path or
if you want to add/remove options, you can modify this string by setting the
'ssh_cmd' input variable.
This may be used, for instance, to set the private key to use with a '-i' option.

## Target host name resolution

When supplying the target DNS name, note that the name will be resolved by the
When supplying the target DNS name, 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
## SSH agent

The SSH client process inherits your environment, including a
possible SSH agent configuration to retrieve your private key.

## Multiple SSH gateways

Please also note that the module cannot
be used to create a tunnel running through a set of several SSH gateways, each
one opening an SSH connection to the
next one. This is technically possible using the 'ProxyJump' feature introduced
in OpenSSH v7.3 and the feature may be added in a future version, depending on user's
demand (I personally don't need it yet).

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.
## Related resources

You may also be interested by the
[terraform-ssh-tunnel-databases](https://github.com/flaupretre/terraform-ssh-tunnel-databases)
module, which uses SSH tunnels to manage MySql/PostgreSql databases, roles, and
permissions.

## Example

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

data aws_instances bastions {
instance_tags = {
Expand All @@ -62,7 +77,7 @@ multiple targets, either tunneled or not.
module db_tunnel {
# You can also retrieve this module from the terraform registry
source = "flaupretre/tunnel/ssh"
version = "1.5.0"
version = "1.10.0"

target_host = aws_db_instance.mydb.address
target_port = aws_db_instance.mydb.port
Expand Down Expand Up @@ -93,12 +108,6 @@ multiple targets, either tunneled or not.
provider = mysql.tunnel
....

You may also be interested by the
[terraform-ssh-tunnel-databases](https://github.com/flaupretre/terraform-ssh-tunnel-databases)
module, which uses SSH tunnels to manage MySql/PostgreSql databases, roles, and
permissions.


<!-- BEGIN_TF_DOCS -->
## Requirements

Expand Down Expand Up @@ -130,9 +139,10 @@ No modules.
| <a name="input_gateway_port"></a> [gateway\_port](#input\_gateway\_port) | Gateway port | `number` | `22` | no |
| <a name="input_gateway_user"></a> [gateway\_user](#input\_gateway\_user) | User to use on SSH gateway (default = empty string = current username) | `any` | `""` | no |
| <a name="input_local_host"></a> [local\_host](#input\_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 |
| <a name="input_putin_khuylo"></a> [putin\_khuylo](#input\_putin\_khuylo) | Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo! | `bool` | `true` | no |
| <a name="input_python_cmd"></a> [python\_cmd](#input\_python\_cmd) | Command to run python | `string` | `"python"` | no |
| <a name="input_shell_cmd"></a> [shell\_cmd](#input\_shell\_cmd) | Command to run a shell | `string` | `"bash"` | no |
| <a name="input_ssh_cmd"></a> [ssh\_cmd](#input\_ssh\_cmd) | Shell command to use to start ssh client | `string` | `"ssh"` | no |
| <a name="input_ssh_cmd"></a> [ssh\_cmd](#input\_ssh\_cmd) | Shell command to use to start ssh client | `string` | `"ssh -o StrictHostKeyChecking=no"` | no |
| <a name="input_ssh_tunnel_check_sleep"></a> [ssh\_tunnel\_check\_sleep](#input\_ssh\_tunnel\_check\_sleep) | extra time to wait for ssh tunnel to connect | `string` | `"0s"` | no |
| <a name="input_target_host"></a> [target\_host](#input\_target\_host) | The target host. Name will be resolved by gateway | `string` | n/a | yes |
| <a name="input_target_port"></a> [target\_port](#input\_target\_port) | Target port number | `number` | n/a | yes |
Expand Down
2 changes: 1 addition & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ data external ssh_tunnel {
gateway_user = var.gateway_user,
shell_cmd = var.shell_cmd,
ssh_tunnel_check_sleep = var.ssh_tunnel_check_sleep
create = (var.create ? "y" : "")
create = ((var.create && var.putin_khuylo) ? "y" : "")
}
}
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ variable "ssh_tunnel_check_sleep" {
description = "extra time to wait for ssh tunnel to connect"
default = "0s"
}

variable "putin_khuylo" {
description = "Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!"
type = bool
default = true
}

0 comments on commit 7663ae6

Please sign in to comment.