Skip to content

Instantly share code, notes, and snippets.

@lukeplausin
Last active December 18, 2024 10:26
Show Gist options
  • Save lukeplausin/4b412d83fb1246b0bed6507b5083b3a7 to your computer and use it in GitHub Desktop.
Save lukeplausin/4b412d83fb1246b0bed6507b5083b3a7 to your computer and use it in GitHub Desktop.
Transfer a file to EC2 SSM instance without using S3 (SSM only)
# This script will explain how to transfer a file to EC2 using SSM ONLY!
# You will need to have permission to run SSM commands on the target machine and have sudo access as well
# Infos
INSTANCE_ID=i-1234567890
FILE_NAME=the_file.tar.gz
# Step 1: Run command on machine to install netcat and dump from port to filename
# < Start session
aws ssm start-session --target $INSTANCE_ID --document-name
# < (On target machine) :
cd && sudo yum install nc -y && sudo nc -l -p 1234 > the_file.tar.gz
# Step 2: On another shell, open a port-forwarding session from your machine to the target machine
aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["1234"],"localPortNumber":["1234"]}'
# Step 3: On yet another shell, cat the source file into the transfer port on localhost over the tunnel
nc -w 3 127.0.0.1 1234 < the_file.tar.gz
# Step 4: Once the command in step 3 finishes, close all of the other shell sessions. Your file should be on the target now.
@ritwik-g
Copy link

This was really useful. Thanks for publishing

@johnp789
Copy link

That's handy! I had to remove the --document-name on the first start-session call.

@pWoLiAn
Copy link

pWoLiAn commented Apr 2, 2024

similarly, have you tried copying a file from ec2 to your local machine without using s3

@toliadobe
Copy link

Extremely helpful! Thank you for sharing.

@bdalli
Copy link

bdalli commented Apr 29, 2024

Very helpful, thank you Luke ..

@s4wet
Copy link

s4wet commented Jun 18, 2024

Thank helpful

@baerrach
Copy link

baerrach commented Jun 25, 2024

Thanks for your script.
I wanted to download a file from the EC2 instance, so the commands are reversed somewhat.

Step 1: On EC2 instance dump from filename to port

nc -l 1234 < the_file.tar.gz

Step 2: On your machine open a shell, open a port-forwarding session from your machine to the target machine

aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["1234"],"localPortNumber":["1234"]}'

Step 3: On your machine open another shell, use nc to read the data over the tunnel and write to destination file

nc -w 3 localhost 1234 > the_file.tar.gz

Step 4: Once the command in step 3 finishes, close all of the other shell sessions. Your file should be on the destination now.

@dmitrygusev
Copy link

Same approach but in one script, save the below script into a file and call it like this:

./upload-file 1234 "/local/path/to/the_file" i-xxxxx "/remote/path/to/the_file"

Note, the script is also creating a folder on the remote if it doesn't exist

upload-file

#!/usr/bin/expect

# Set the script to not time out
set timeout -1

# Capture the script arguments
# Port for netcat
set port [lindex $argv 0]
# File to send via netcat
set file_to_send [lindex $argv 1]
# AWS SSM instance ID
set remote_instance_id [lindex $argv 2]
# Remove file name
set remote_file_name [lindex $argv 3]

# Start AWS SSM session on host A and run netcat to listen on a port
spawn aws ssm start-session --target $remote_instance_id
expect {
    -re "sh-.*" {
        send_user "\nAWS SSM session started.\n"
        send "mkdir -p \"\$(dirname \"$remote_file_name\")\" && nc -l -p $port > \"$remote_file_name\"\r"
        send_user "\nNetcat listener started on port $port > $remote_file_name.\n"
    }
}

# Start a background AWS SSM session for port forwarding
spawn bash -c "aws ssm start-session --target $remote_instance_id --document-name AWS-StartPortForwardingSession --parameters '{\"portNumber\":\[\"$port\"\],\"localPortNumber\":\[\"$port\"\]}'"
expect {
    -re "Waiting for connections" {
        send_user "\nPort forwarding session established.\n"
    }
}

# Use netcat to send the file to the port
spawn bash -c "nc localhost $port < \"$file_to_send\""
expect {
    eof {
        send_user "\nFile sent.\n"
    }
}

# Terminate the netcat listener on the remote host
spawn aws ssm start-session --target $remote_instance_id
expect {
    -re "sh-.*" {
        send_user "\nTerminating netcat listener on remote host.\n"
        send "pkill -f 'nc -l -p $port'\r"
    }
}

# Terminate all AWS SSM sessions
send_user "\nClosing all sessions...\n"
exec pkill -f "aws ssm"
send_user "\nAll sessions terminated.\n"

exit

@Kostukk
Copy link

Kostukk commented Oct 3, 2024

@lukeplausin thanks for the script. But how about security issues? NC sends raw data over the tunnel, any data that passes through could potentially be intercepted if the port forwarding or the session is compromised. EC2 instance has a nc listener running on port 1234 while you're using AWS SSM to forward traffic, having an open port increases the risk of unauthorized access, especially if the security group or other controls are misconfigured. NC does not authenticate the sender, meaning anyone with access to the port could send data if they know the port number and the instance is exposed.

@mimmus
Copy link

mimmus commented Dec 6, 2024

it's quick-and-dirty but very useful!

SSM is encrypted by default and 'nc' traffic is always over SSM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment