AWS Boto3 is the Python SDK for AWS. Boto3 can be used to directly interact with AWS resources from Python scripts. In this tutorial, we will look at how we can use the Boto3 library to perform various operations on AWS EC2.

Table of contents

Prerequisites

  • Python3
  • Boto3: Boto3 can be installed using pip: pip install boto3
  • AWS Credentials: If you haven’t setup AWS credentials before, this resource from AWS is helpful.

How to create an EC2 key pair?

A key pair consists of a private key and a public key. These are required to be able to securely access an EC2 instance. Amazon stores the public key and we store the private key.


def create_key_pair():
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    key_pair = ec2_client.create_key_pair(KeyName="ec2-key-pair")

    private_key = key_pair["KeyMaterial"]

    # write private key to file with 400 permissions
    with os.fdopen(os.open("/tmp/aws_ec2_key.pem", os.O_WRONLY | os.O_CREAT, 0o400), "w+") as handle:
        handle.write(private_key)

The function above creates an EC2 key pair with the name ec2-key-pair and then stores in a file located at /tmp/aws_ec2_key.pem with the 400 permissions that will be needed when we use the private key to access the EC2 instance.


How to create a new EC2 instance using Boto3?

Requirements for creating an EC2 instance

  • ImageId: An Amazon Machine Image (AMI) is required to launch an EC2 instance. You can either use one of the freely available AMIs provided by Amazon or create your own. For this tutorial, we will use the Amazon Linux 2 AMI in us-west-2. /assets/img/boto3-ec2/ami.png
  • MinCount: Minimum number of EC2 instances to create
  • MaxCount: Maximum number of EC2 instances to create
  • InstanceType: The instance type for the EC2 instance. Information about all the instance types is available here.
  • KeyName: The name of the key pair that will be used to access the EC2 instance. If no KeyName is specified, we won’t be able to SSH into the EC2 instance.
  • SecurityGroupIds: Security groups allow you to control access into and out of your EC2 instance.
  • IamInstanceProfile: The name of the IAM profile that will be attached to the EC2 instance.

Information on all available paramters is listed on the boto3 specs.

Code

def create_instance():
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    instances = ec2_client.run_instances(
        ImageId="ami-0b0154d3d8011b0cd",
        MinCount=1,
        MaxCount=1,
        InstanceType="t4g.nano",
        KeyName="ec2-key-pair"
    )

    print(instances["Instances"][0]["InstanceId"])

In this example, we create 1 EC2 instance for the t4g.nano instance type and the key pair we created above. Once the instance is created successfully, you will be able to see the InstanceId for the newly created instance.

i-0d0ce9186a9627c1b

EC2 instances can take a few minutes before they are accessible. In the next section, we will see how to retrieve the Public IP for the instance and then access the instance.


How to get the public IP for a running EC2 instance?

We can use the describe_instances method to retrieve the public IP of the EC2 instance:


def get_public_ip(instance_id):
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    reservations = ec2_client.describe_instances(InstanceIds=[instance_id]).get("Reservations")

    for reservation in reservations:
        for instance in reservation['Instances']:
            print(instance.get("PublicIpAddress"))

After running this script for the instance id we had created above, I was able to retrieve the public ip of the instance. We can use this public IP and the key pair we created earlier to SSH into the instance.

ssh -i /tmp/aws_ec2_key.pem [email protected]

How to list all running EC2 instances?

We will use the describe_instances method to get a list of all running instances. We will use the Filters arguments to only return instances which are in the Running state.

def get_running_instances():
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    reservations = ec2_client.describe_instances(Filters=[
        {
            "Name": "instance-state-name",
            "Values": ["running"],
        }
    ]).get("Reservations")

    for reservation in reservations:
        for instance in reservation["Instances"]:
            instance_id = instance["InstanceId"]
            instance_type = instance["InstanceType"]
            public_ip = instance["PublicIpAddress"]
            private_ip = instance["PrivateIpAddress"]
            print(f"{instance_id}, {instance_type}, {public_ip}, {private_ip}")

Output:

i-0d0ce9186a9627c1b, t4g.nano, 35.166.125.100, 172.31.22.48

How to stop an EC2 instance?

An EC2 instance can be shut down using the stop_instances command. A stopped EC2 instance is not charged for usage (except for any EBS volumes).


def stop_instance(instance_id):
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    response = ec2_client.stop_instances(InstanceIds=[instance_id])
    print(response)

{'StoppingInstances': [{'CurrentState': {'Code': 64, 'Name': 'stopping'}, 'InstanceId': 'i-0d0ce9186a9627c1b', 'PreviousState': {'Code': 16, 'Name': 'running'}}], 'ResponseMetadata': {'RequestId': '653eb6eb-10f5-4405-8765-2eda89bcbf02', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '653eb6eb-10f5-4405-8765-2eda89bcbf02', 'content-type': 'text/xml;charset=UTF-8', 'content-length': '579', 'date': 'Thu, 17 Dec 2020 06:35:39 GMT', 'server': 'AmazonEC2'}, 'RetryAttempts': 0}}

How to terminate an EC2 instance?

We will use the terminate_instances method to terminate and remove our EC2 instance.


def terminate_instance(instance_id):
    ec2_client = boto3.client("ec2", region_name="us-west-2")
    response = ec2_client.terminate_instances(InstanceIds=[instance_id])
    print(response)

{'TerminatingInstances': [{'CurrentState': {'Code': 48, 'Name': 'terminated'}, 'InstanceId': 'i-0d0ce9186a9627c1b', 'PreviousState': {'Code': 80, 'Name': 'stopped'}}], 'ResponseMetadata': {'RequestId': '68ec3f9e-c162-4a7a-9b17-d19c366bf88f', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '68ec3f9e-c162-4a7a-9b17-d19c366bf88f', 'content-type': 'text/xml;charset=UTF-8', 'transfer-encoding': 'chunked', 'vary': 'accept-encoding', 'date': 'Thu, 17 Dec 2020 06:38:31 GMT', 'server': 'AmazonEC2'}, 'RetryAttempts': 0}}