Python SSH with AWS Assumed User: A Quick Guide
When managing cloud infrastructure, developers often need to establish secure shell (SSH) connections to their servers. This becomes particularly relevant when working with Amazon Web Services (AWS), where instances may require AWS Identity and Access Management (IAM) roles for access. In this guide, we will delve into how to connect to an AWS EC2 instance using Python while assuming a specific IAM role, thereby ensuring both secure and efficient operations.
Understanding SSH and AWS IAM Roles
What is SSH?
SSH (Secure Shell) is a protocol that enables secure access to remote servers over an unsecured network. SSH is widely used for managing servers securely, allowing for command execution, file transfers, and tunneling.
What are AWS IAM Roles?
AWS IAM (Identity and Access Management) roles are crucial for granting permissions to perform actions on AWS resources. An IAM role does not have any credentials associated with it; instead, it is assumed by trusted entities such as AWS services, applications, or users.
Why Use an Assumed Role?
Assuming a role for SSH access can be especially useful in a shared environment where multiple users need to access EC2 instances without hardcoding credentials. It allows better management of permissions and improves security, as temporary credentials can be generated dynamically.
Prerequisites
Before you start, ensure you have the following:
- An AWS account
- IAM role with appropriate permissions (e.g., EC2:DescribeInstances, EC2:StartInstances, etc.)
- An EC2 instance running with SSH enabled
- Python installed on your local machine
- Necessary Python libraries:
boto3
,paramiko
, andrequests
Installing Required Libraries
Use pip to install the required libraries:
pip install boto3 paramiko requests
Step-by-Step Guide to Connect via SSH
Step 1: Set Up IAM Role
-
Create an IAM Role: In the AWS Management Console, navigate to IAM, then Roles, and create a new role. Select EC2 as the trusted entity and attach policies allowing necessary permissions.
-
Attach the Role to the EC2 Instance: When launching an EC2 instance, you can associate the IAM role. Alternatively, you can attach the role to an existing instance through the EC2 console.
Step 2: Configure Your Local Environment
You need to set up your AWS CLI with your credentials:
aws configure
This will prompt you to input your AWS Access Key ID, Secret Access Key, region, and output format.
Step 3: Obtain Temporary Credentials
Using the boto3
library in Python, you can assume a role and retrieve temporary credentials. Here's how you do it:
import boto3
def assume_role(role_arn):
client = boto3.client('sts')
response = client.assume_role(
RoleArn=role_arn,
RoleSessionName='session_name'
)
return response['Credentials']
Step 4: Establish SSH Connection
Using paramiko
, you can create an SSH client to connect to the EC2 instance. Ensure you have the private key file (.pem) to connect.
import paramiko
def ssh_connect(hostname, port, username, private_key_file):
key = paramiko.RSAKey.from_private_key_file(private_key_file)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=hostname, port=port, username=username, pkey=key)
return client
Step 5: Execute Commands Over SSH
Once connected, you can execute commands:
def execute_command(client, command):
stdin, stdout, stderr = client.exec_command(command)
print(stdout.read().decode())
print(stderr.read().decode())
# Usage
client = ssh_connect('ec2-instance-ip', 22, 'ec2-user', 'path/to/private-key.pem')
execute_command(client, 'ls -la')
client.close()
Putting It All Together
Here’s the complete script that encompasses all the steps mentioned above:
import boto3
import paramiko
def assume_role(role_arn):
client = boto3.client('sts')
response = client.assume_role(
RoleArn=role_arn,
RoleSessionName='session_name'
)
return response['Credentials']
def ssh_connect(hostname, port, username, private_key_file):
key = paramiko.RSAKey.from_private_key_file(private_key_file)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=hostname, port=port, username=username, pkey=key)
return client
def execute_command(client, command):
stdin, stdout, stderr = client.exec_command(command)
print(stdout.read().decode())
print(stderr.read().decode())
if __name__ == '__main__':
role_arn = 'arn:aws:iam::account-id:role/role-name'
credentials = assume_role(role_arn)
# Use the temporary credentials to create a boto3 session
session = boto3.Session(
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
)
ec2_client = session.client('ec2')
# Replace with your instance ID and desired commands
instance_id = 'your-instance-id'
instance_info = ec2_client.describe_instances(InstanceIds=[instance_id])
public_ip = instance_info['Reservations'][0]['Instances'][0]['PublicIpAddress']
client = ssh_connect(public_ip, 22, 'ec2-user', 'path/to/private-key.pem')
execute_command(client, 'ls -la')
client.close()
Important Notes
Always ensure to use the appropriate IAM policies with the least privilege principle to enhance security. The temporary credentials obtained from assuming a role are valid for a limited duration and should not be hardcoded.
Troubleshooting Common Issues
- Connection Timed Out: Ensure your EC2 instance has proper security group rules allowing inbound traffic on port 22.
- Permission Denied: Check if the correct private key is being used and that the username matches the AMI used (e.g.,
ec2-user
for Amazon Linux). - Invalid Host Key: If you encounter host key issues, consider setting the missing host key policy to
AutoAddPolicy
.
Conclusion
Connecting to AWS EC2 instances via SSH using Python and assumed roles offers a flexible and secure way to manage your cloud resources. By leveraging AWS IAM roles and temporary credentials, you can maintain robust security practices while streamlining your operations. Whether you're executing commands or transferring files, this method can significantly enhance your cloud management capabilities. Happy coding! 🚀