diff --git a/aliases b/aliases index 87800d6f..f08a9854 100644 --- a/aliases +++ b/aliases @@ -77,6 +77,7 @@ alias instance-dns='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-dns' alias instance-health-set-unhealthy='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-health-set-unhealthy' alias instance-iam-profile='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-iam-profile' alias instance-ip='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-ip' +alias instance-portforward='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-portforward' alias instance-ssh='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-ssh' alias instance-ssh-details='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-ssh-details' alias instance-ssm='${BMA_HOME:-$HOME/.bash-my-aws}/bin/bma instance-ssm' diff --git a/bash_completion.sh b/bash_completion.sh index 204f7df1..9a52715e 100644 --- a/bash_completion.sh +++ b/bash_completion.sh @@ -173,6 +173,7 @@ complete -F _bma_instances_completion instance-dns complete -F _bma_instances_completion instance-health-set-unhealthy complete -F _bma_instances_completion instance-iam-profile complete -F _bma_instances_completion instance-ip +complete -F _bma_instances_completion instance-portforward complete -F _bma_instances_completion instance-ssh complete -F _bma_instances_completion instance-ssh-details complete -F _bma_instances_completion instance-ssm diff --git a/docs/command-reference.md b/docs/command-reference.md index e127f3e9..6748b326 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -585,6 +585,64 @@ List ip address of EC2 Instance(s) i-89cefa9403373d7a5 10.155.35.61 54.214.206.114 i-806d8f1592e2a2efd 10.178.243.63 54.214.244.90 +### instance-portforward + +Setup a SSM portforward between a port on a remote EC2 Instance and a local port. + +Remote port may be given as a number, or as a keyword from the following list: + +- aurora (i.e. port 3306) +- dns (i.e. port 53) +- elasticgfx (i.e. port 2007) +- http (i.e. port 80) +- https (i.e. port 443) +- imap (i.e. port 143) +- imaps (i.e. port 993) +- ldap (i.e. port 398) +- mssql (i.e. port 1433) +- mysql (i.e. port 3306) +- oracle (i.e. port 1521) +- pop3 (i.e. port 110) +- pop3s (i.e. port 995) +- postgres (i.e. port 5432) +- redshift (i.e. port 5439) +- rdp (i.e. port 3389) +- smb (i.e. port 445) +- smtp (i.e. port 25) +- smtps (i.e. port 465) +- ssh (i.e. port 22) +- winrm (i.e. port 5985) +- winrms (i.e. port 5986) + +Local port is optional and must be a number. If unspecified, the same port number as the remote port will be attempted. + + USAGE: instance-portforward [remote port] [local port (optional)] [instance-id] + + # Example: Remote RDP portforwarded to localhost port 9000 + # ec2-instance:3389 <-- portforward --> localhost:9000 + $ instances example-windows-host | instance-portforward rdp 9000 + + Portforwarding between EC2 instance i-008db2027225a0a40 port 3389 and localhost port 9000 + + Starting session with SessionId: jo.bloggs@contoso.com-0e84c8293af47aad6. + Port 9000 opened for sessionId jo.bloggs@contoso.com-0e84c8293af47aad6. + Waiting for connections... + + # At this point, we open an RDP client and connect to localhost:9000 + Connection accepted for session [jo.bloggs@contoso.com-0e84c8293af47aad6] + + # When you're finished, enter Ctrl+C to close the portforward and exit + ^CTerminate signal received, exiting. + + Exiting session with sessionId: jo.bloggs@contoso.com-0e84c8293af47aad6. + +Further examples without example output: + + # ec2-instance:1433 <-- portforward --> localhost:5600 + $ instances mssql01 | instance-portforward 1433 5600 + + # ec2-instance:443 <-- portforward --> localhost:8080 + $ instance-portforward https 8080 i-806d8f1592e2a2efd ### instance-ssh diff --git a/functions b/functions index 52bc4cf0..6c19fac4 100644 --- a/functions +++ b/functions @@ -77,6 +77,7 @@ instance-dns instance-health-set-unhealthy instance-iam-profile instance-ip +instance-portforward instance-ssh instance-ssh-details instance-ssm diff --git a/lib/instance-functions b/lib/instance-functions index 50116833..48f85c6e 100644 --- a/lib/instance-functions +++ b/lib/instance-functions @@ -226,6 +226,83 @@ instance-ip() { column -s$'\t' -t } +instance-portforward() { + + # Establish SSM-based portforwards from EC2 Instance(s) + # + # USAGE: instance-portforward [remote port] [local port (optional)] [instance-id] + # + # Remote port may be given as a number, or as a keyword from the list below + # e.g. 'instance-portforwarding rdp' is equivalent to 'instance-portforwarding 3389' + # + # Local port is optional and must be a number + # If unspecified, the same port number as the remote port will be attempted. + local instance_id remote_port local_port + + # We want this to word split + # shellcheck disable=SC2046,SC2068 + set -- $(skim-stdin ${@}) + + # Map our remote port + case "${1}" in + (aurora) remote_port=3306 ;; + (dns) remote_port=53 ;; + (elasticgfx) remote_port=2007 ;; + (http) remote_port=80 ;; + (https) remote_port=443 ;; + (imap) remote_port=143 ;; + (imaps) remote_port=993 ;; + (ldap) remote_port=398 ;; + (mssql) remote_port=1433 ;; + (mysql) remote_port=3306 ;; + (oracle) remote_port=1521 ;; + (pop3) remote_port=110 ;; + (pop3s) remote_port=995 ;; + (postgres) remote_port=5432 ;; + (redshift) remote_port=5439 ;; + (rdp) remote_port=3389 ;; + (smb) remote_port=445 ;; + (smtp) remote_port=25 ;; + (smtps) remote_port=465 ;; + (ssh) remote_port=22 ;; + (winrm) remote_port=5985 ;; + (winrms) remote_port=5986 ;; + (*) remote_port="${1}" ;; + esac + + # Validate that the remote port is a number. + printf -- '%d\n' "${remote_port}" >/dev/null 2>&1 || { + __bma_error "Remote Port must be a number or a recognised keyword" + return 1 + } + + # Map the rest of our vars based on how many params are given + case "${#}" in + (2) local_port="${remote_port}"; instance_id="${2}" ;; + (3) local_port="${2}"; instance_id="${3}" ;; + (*) + __bma_usage "[remote port] [local port (optional)] [instance-id]" + return 1 + ;; + esac + + # Validate that the local port is a number + printf -- '%d\n' "${local_port}" >/dev/null 2>&1 || { + __bma_error "Local Port must be a number" + return 1 + } + + printf -- '\nPortforwarding between EC2 instance %s port %d and localhost port %d\n' \ + "${instance_id}" "${remote_port}" "${local_port}" + + # Ignore shellcheck alert on parameters directive + # shellcheck disable=SC2140 + aws ssm start-session \ + --target "${instance_id}" \ + --document-name AWS-StartPortForwardingSession \ + --parameters "portNumber"=["${remote_port}"],"localPortNumber"=["${local_port}"] + +} instance-ssh() {