- Published on
Running SSH Commands on AWS EC2 Instances with Python
- Authors
- Name
- Ruan Bekker
- @ruanbekker
In this quick post I will demonstrate how to discover a EC2 Instance's Private IP Address using the AWS API by using Tags then use Paramiko in Python to SSH to the EC2 instance and run SSH commands on the target instance.
Install the required dependencies:
$ virtualenv -p python3 .venv
$ source .venve/bin/activate
$ pip install boto3 paramiko
I have my development profile for aws configured under dev
as can seen below:
$ aws --profile dev configure list
Name Value Type Location
---- ----- ---- --------
profile dev manual --profile
access_key ****************xxxx assume-role
secret_key ****************xxxx assume-role
region eu-west-1 config-file ~/.aws/config
First we need to discover the private ip address from the api by referencing tags, and in this example we will use the Name
tag:
import boto3
ec2 = boto3.Session(profile_name='dev', region_name='eu-west-1').client('ec2')
target_instances = ec2.describe_instances(
Filters=[{'Name':'tag:Name','Values':['my-demo-ec2-instance']}]
)
ec2_instances = []
for each_instance in target_instances['Reservations']:
for found_instance in each_instance['Instances']:
ec2_instances.append(found_instance['PrivateIpAddress'])
# ec2_instances
# ['172.31.2.89']
So we are instantiating a ec2 instance with our configured dev profile, then we describe all our instances using the tag key Name
and value my-demo-ec2-instance
and then access the private ip address and append it to our ec2_instances
list.
Next we want to define the commands that we want to run on the target ec2 instance:
commands = [
"echo hi",
"whoami",
"hostname"
]
In my case I only have 1 ec2 instance with the name my-demo-ec2-instance
, but if you have more you can just loop through the list and perform the actions.
Next we want to establish the SSH connection:
k = paramiko.RSAKey.from_private_key_file("/Users/ruan/.ssh/id_rsa")
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=ec2_instances[0], username="ruan", pkey=k, allow_agent=False, look_for_keys=False)
Once our SSH connection has established, we can loop through our commands and execute them:
for command in commands:
print("running command: {}".format(command))
stdin , stdout, stderr = c.exec_command(command)
print(stdout.read())
print(stderr.read())
Which will output the folling:
running command: echo hi
b'hi\n'
b''
running command: whoami
b'ruan\n'
b''
running command: hostname
b'ip-172-31-2-89\n'
b''
And then close the SSH connection:
c.close()
And the full script will look like this:
import boto3
ssh_username = "ruan"
ssh_key_file = "/Users/ruan/.ssh/id_rsa"
ec2 = boto3.Session(profile_name='dev', region_name='eu-west-1').client('ec2')
target_instances = ec2.describe_instances(
Filters=[{'Name':'tag:Name','Values':['my-demo-ec2-instance']}]
)
ec2_instances = []
for each_instance in target_instances['Reservations']:
for found_instance in each_instance['Instances']:
ec2_instances.append(found_instance['PrivateIpAddress'])
commands = [
"echo hi",
"whoami",
"hostname"
]
k = paramiko.RSAKey.from_private_key_file(ssh_key_file)
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=ec2_instances[0], username=ssh_username, pkey=k, allow_agent=False, look_for_keys=False)
for command in commands:
print("running command: {}".format(command))
stdin , stdout, stderr = c.exec_command(command)
print(stdout.read())
print(stderr.read())
c.close()
Thank You
Thanks for reading, feel free to check out my website, and subscribe to my newsletter or follow me at @ruanbekker on Twitter.
- Linktree: https://go.ruan.dev/links
- Patreon: https://go.ruan.dev/patreon