The Amazon EC2 is a cloud service within Amazon Web Services cloud platform that allows building and managing virtual machines to support various application workloads. With Amazon EC2, you can create, resize or decommission instances at any time depending on the business requirements. As a Cloud Automation Engineer, you’ll deal with many tasks around this topic. So, this Boto3 EC2 tutorial provides code snippets that will help you create, start, stop, list, filter, delete, tag, and modify Amazon EC2 Instances using the AWS Software Development Kit (SDK) for Python.

Table of contents

How to manage EC2 Instances using Boto3?

This article will cover the basic operations with EC2 instances using the Boto3 library.

Creating EC2 instance

To create one or more EC2 instances, you need to use the create_instances() method of the EC2 resource. The simplest EC2 instance configuration might include the following arguments:

  • MinCount – minimum number of EC2 instances to launch
  • MaxCount – maximum number of EC2 instances to launch
  • ImageId – the Amazon Machine Image, which is used to launch your EC2 instance
  • InstanceType – Instance Type specifies how much CPU and RAM resources your EC2 instance should have
  • KeyName – SSH key name, which you’re going to use to get remote access to the EC2 instance

Such configuration will launch an EC2 instance in the default VPC:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-1"
KEY_PAIR_NAME = 'Lenovo T410'
AMI_ID = 'ami-0c02fb55956c7d316' # Amazon Linux 2
SUBNET_ID = 'subnet-0984555689f5894d8'
SECURITY_GROUP_ID = 'sg-01304974040835e2f'
INSTANCE_PROFILE = 'EC2-Admin'
USER_DATA = '''#!/bin/bash
yum update
'''
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
instances = EC2_RESOURCE.create_instances(
    MinCount = 1,
    MaxCount = 1,
    ImageId=AMI_ID,
    InstanceType='t2.micro',
    KeyName=KEY_PAIR_NAME,
    SecurityGroupIds = [SECURITY_GROUP_ID],
    SubnetId=SUBNET_ID,
    UserData=USER_DATA,
    TagSpecifications=[
        {
            'ResourceType': 'instance',
            'Tags': [
                {
                    'Key': 'Name',
                    'Value': 'my-ec2-instance'
                },
            ]
        },
    ]
)

for instance in instances:
    print(f'EC2 instance "{instance.id}" has been launched')
    
    instance.wait_until_running()
    
    EC2_CLIENT.associate_iam_instance_profile(
        IamInstanceProfile = {'Name': INSTANCE_PROFILE},
        InstanceId = instance.id,
    )
    print(f'EC2 Instance Profile "{INSTANCE_PROFILE}" has been attached')
    print(f'EC2 instance "{instance.id}" has been started')

Thecreate_instances() method returns a list of launched instances.

The associate_iam_instance_profile() method allows you to assign an AWS IAM role to the EC2 instance and grant EC2 instance permissions to access AWS services and APIs.

In the script above, we used a user_data property to run a custom command during the EC2 instance launch.

Note: pay attention that the user_data is limited to 16 KB. If you need to do a complex EC2 instance configuration during its startup process, consider using Ansible, Chef, or Puppet.

Listing EC2 Instances

The best way to list all EC2 instances is to use the all() method from the instances collection of the EC2 resource.

Then you can use for-loop to iterate through the returned list of instances to get the information about Instance ID (id), Platform (platform), Instance Type (instance_type), Public IP (public_ip_address), Image (image.id) and many others by accessing instance object attributes.

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
instances = EC2_RESOURCE.instances.all()
for instance in instances:
    print(f'EC2 instance {instance.id}" information:')
    print(f'Instance state: {instance.state["Name"]}')
    print(f'Instance AMI: {instance.image.id}')
    print(f'Instance platform: {instance.platform}')
    print(f'Instance type: "{instance.instance_type}')
    print(f'Public IPv4 address: {instance.public_ip_address}')
    print('-'*60)

Filtering EC2 instances

Filtering EC2 allows you to get a list of EC2 instances based on specified conditions. For example, you can get specific instance information by instance type, a list of instances based on Tags, instance state, and many other conditions.

Filtering EC2 instances by state

To filter by state, you can use the filter() method in the instances collection of the EC2 resource.

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_STATE = 'running'
instances = EC2_RESOURCE.instances.filter(
    Filters=[
        {
            'Name': 'instance-state-name',
            'Values': [
                INSTANCE_STATE
            ]
        }
    ]
)
print(f'Instances in state "{INSTANCE_STATE}":')
for instance in instances:
    print(f'  - Instance ID: {instance.id}')

Filtering EC2 instances by type

To filter EC2 instances by type, you can usethe filter() method in the instances collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_TYPE = 't2.micro'
instances = EC2_RESOURCE.instances.filter(
    Filters=[
        {
            'Name': 'instance-type',
            'Values': [
                INSTANCE_TYPE
            ]
        }
    ]
)
print(f'Instances of type "{INSTANCE_TYPE}":')
for instance in instances:
    print(f'  - Instance ID: {instance.id}')

Filtering EC2 instances by Tag

To filter EC2 instances by type, you can usethe filter() method in the instances collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_NAME_TAG_VALUE = 'my-ec2-instance'
instances = EC2_RESOURCE.instances.filter(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': [
                INSTANCE_NAME_TAG_VALUE
            ]
        }
    ]
)
print(f'Instances with Tag "Name={INSTANCE_NAME_TAG_VALUE}":')
for instance in instances:
    print(f'  - Instance ID: {instance.id}')

Filtering EC2 instances by instance ID

To filter EC2 instances by Instance ID, you can usethe filter() method in the instances collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instances = EC2_RESOURCE.instances.filter(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
for instance in instances:
    print(f'Instance {instance.id} state is {instance.state["Name"]}')

Describing EC2 instance properties

To access theEC2 instance properties, you can use thedescribe_instances() method of the EC2 client (gets all properties in the Python dictionary format), or you can use the EC2.Instance class’ attributes (provides access to a specific attribute) of the EC2 resource.

Describing all EC2 instance properties

The describe_instances() method accepts the Filters and InstanceIds attributes that allow you to find specific instances.

#!/usr/bin/env python3
import json
from datetime import date, datetime
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'

# Helper method to serialize datetime fields
def json_datetime_serializer(obj):
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

response = EC2_CLIENT.describe_instances(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
print(f'Instance {INSTANCE_ID} attributes:')
for reservation in response['Reservations']:
    print(json.dumps(
            reservation,
            indent=4,
            default=json_datetime_serializer
        )
    )

Listing EC2 instance EBS volumes

To get EC2 instance EBS volumes, you can use the block_device_mappings list of the EC2.Instance resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = 'us-east-2'
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
device_mappings = instance.block_device_mappings
print(f'Volumes attached to the EC2 instance "{INSTANCE_ID}":')
for device in device_mappings:
    print(f"  - Volume {device['Ebs']['VolumeId']} attached as {device['DeviceName']}")

For additional information on working with EBS volumes, check out the Working with EBS volumes in Python using the Boto3 article.

Getting EC2 instance state

To get the EC2 instance state, you can use the state attribute of the EC2.Instance resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = 'us-east-2'
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
print(f'EC2 instance "{INSTANCE_ID}" state: {instance.state["Name"]}')

If you’d like to get a state of multiple EC2 instances, here’s an example of using the filter() method.

Managing EC2 instance Tags

Tags allow you to group your resources according to your organization and project structure, and they usually help organize resources in groups for management or billing reporting purposes.

Adding Tags to EC2 instance

To add Tags to EC2 instances, you can use thecreate_tags() method of the EC2.Instance resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
TAGS = [
    {
        'Key': 'Environment',
        'Value': 'dev'
    }
]
instances = EC2_RESOURCE.instances.filter(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
for instance in instances:
    instance.create_tags(Tags=TAGS)
    print(f'Tags successfully added to the instance {instance.id}')

Listing EC2 instance Tags

To list all tags that are associated with the EC2 instances, you can use a for loop to iterate through the list of instance.tags (EC2 resource):

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instances = EC2_RESOURCE.instances.filter(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
for instance in instances:
    print(f'EC2 instance {instance.id} tags:')
    if len(instance.tags) > 0:
        for tag in instance.tags:
            print(f'  - Tag: {tag["Key"]}={tag["Value"]}')
    else:
        print(f'  - No Tags')
    print('-'*60)

Updating EC2 instance Tags

To update Tags of EC2 instances, you can use thecreate_tags() method of the EC2.Instance resource that not only creates but also overrides Tags.

Deleting EC2 instance Tags

To delete Tags from EC2 instances, you can use thedelete_tags() method of the EC2.Instance resource.

Note: you can delete the EC2 instance Tag based on its Key (required) and optional Value. If you specify a Tag Key without a Tag Value, the delete_tags() method will delete any Tag with the specified Key regardless of its value. If you specify a Tag Key with the Value that equals an empty string,the delete_tags() method will delete the Tag only if its value is an empty string.

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
TAGS = [
    {
        'Key': 'Environment',
        'Value': 'dev'
    }
]
instances = EC2_RESOURCE.instances.filter(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
for instance in instances:
    instance.delete_tags(Tags=TAGS)
    print(f'Tags successfully deleted from the instance {instance.id}')

EC2 instance advanced monitoring

To enable advanced monitoring for the EC2 Instance, use the monitor() method to turn the monitoring on and the unmonitor() method to turn the monitoring off (EC2 resource):

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instances = EC2_RESOURCE.instances.filter(
    InstanceIds=[
        INSTANCE_ID,
    ],
)
for instance in instances:
    monitoring_state = instance.monitoring['State']
    if monitoring_state == 'enabled':
        instance.unmonitor()
    else:
        instance.monitor()
    print(f'Instance monitoring: {monitoring_state}')

Managing EC2 instance state

In this section of the article, we’ll cover the basic method allowing to manage EC2 instance state: start(), stop(), reboot(), and terminate().

Starting EC2 instance

To start up instances, you can use the start() method of the EC2.Instance object:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.start()
print(f'Starting EC2 instance: {instance.id}')
    
instance.wait_until_running()
print(f'EC2 instance "{instance.id}" has been started')

Thewait_until_running() waiter method allows you to wait till the EC2 instance is up and running.

Stopping EC2 instance

To stop instances, you can use the stop() method of the EC2.Instance object:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.stop()
print(f'Stopping EC2 instance: {instance.id}')
    
instance.wait_until_stopped()
print(f'EC2 instance "{instance.id}" has been stopped')

Thewait_until_stopped() waiter method allows you to wait till the EC2 instance is completely stopped.

Rebooting EC2 instance

To stop instances, you can use the reboot() method of the EC2.Instance object:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.reboot()
print(f'EC2 instance "{instance.id}" has been rebooted')

Terminating EC2 instance

To terminate the EC2 instance, you can use the terminate() method of the EC2.Instance object:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-020b3f1914105320d'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.terminate()
print(f'Terminating EC2 instance: {instance.id}')
    
instance.wait_until_terminated()
print(f'EC2 instance "{instance.id}" has been terminated')

Thewait_until_terminated() waiter method allows you to wait till the EC2 instance is completely terminated.

Modifying EC2 instance attributes using Boto3

To change EC2 instance attributes, you can use the modify_attribute() method of the EC2 resource.

Note: You can specify only one attribute at a time. In addition, some attribute changes require the instance to be in a stopped state at the time of the change.

Changing EC2 instance type

To modify the EC2 instance type, you can use the modify_attribute() method of the EC2 client:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-04091b10d2cdc86aa'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.stop()
instance.wait_until_stopped()
instance.modify_attribute(
    InstanceType={
        'Value': 't2.small'
    }
)
instance.start()
instance.wait_until_running()
print(f'Instance type has been successfully changed')

How to manage SSH keys using Boto3?

Before creating an EC2 instance using Boto3, you have to set up an SSH key in your account. You must have an SSH key during the EC2 instance launch if you’re not using AWS Systems Manager and are willing to have remote access to your EC2 instance. In addition to that, you’ll need an SSH key to get the Windows EC2 instance password.

You can create an SSH key manually using AWS Web Console or automatically by using the Boto3 library. This section of the article will describe how to use the Boto3 library to manage SSH keys.

Creating SSH key

To create an SSH key pair, you have to use the create_key_pair() method of the EC2 resource. This method will generate a new SSH key pair and let you save the private SSH key.

Note: pay attention that if you don’t save your private SSH key returned by the create_key_pair() method, you’ll have to generate a new SSH key because AWS does not store your private SSH key.

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
key_pair = EC2_RESOURCE.create_key_pair(
    KeyName='my-ssh-key-pair',
    TagSpecifications=[
        {
            'ResourceType': 'key-pair',
            'Tags': [
                {
                    'Key': 'Name',
                    'Value': 'my-ssh-key-pair'
                },
            ]
        },
    ]
)
print(f'SSH key fingerprint: {key_pair.key_fingerprint}')
print(f'Private SSH key: {key_pair.key_material}')

Listing SSH keys

To list all SSH keys using Boto3, you need to use the all() method of the key_pairs collection of the EC2 resource. The most useful properties of the returned KeyPairInfo object are:

  • key_name
  • key_fingerprint
  • tags
#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
key_pairs = EC2_RESOURCE.key_pairs.all()
for key in key_pairs:
    print(f'SSH key "{key.key_name}" fingerprint: {key.key_fingerprint}')

Searching for SSH keys

The key_pairs collection of the EC2 resource allows you to use the filter() method to search for specific SSH keys by key id, name, or tag.

Searching for SSH key by name

Here’s an example of filtering SSH key by its name:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
key_pairs = EC2_RESOURCE.key_pairs.filter(
    KeyNames=[
        'my-ssh-key-pair',
    ],
)
for key in key_pairs:
    print(f'SSH key "{key.key_name}" fingerprint: {key.key_fingerprint}')

Searching for SSH key by tag

Here’s an example of filtering SSH key by the tag (you may specify as many tags as you’d like):

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
key_pairs = EC2_RESOURCE.key_pairs.filter(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': [
                'my-ssh-key-pair',
            ]
        },
    ],
)
for key in key_pairs:
    print(f'SSH key "{key.key_name}" fingerprint: {key.key_fingerprint}')

Deleting SSH key

To delete an SSH key pair, you have to use the delete() method of the KeyPair class of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
KEY_PAIR_NAME = 'my-ssh-key-pair'
key_pair = EC2_RESOURCE.KeyPair(KEY_PAIR_NAME)
key_pair.delete()
print(f'SSH key "{KEY_PAIR_NAME}" successfully deleted')

Managing Security Groups using Boto3

Security groups control inbound and outbound traffic of the EC2 instance network interface. Each Security Group consists of one or many Security Group Rules. This section of the article will cover how to manage Security Groups and use them with EC2 instances.

Note: every EC2 instance must have at least one Security Group associated with it. If no Security Group has been specified during the EC2 instance launch, the default Security Group of the default VPC is associated with the instance.

Creating a Security Group

To define a Security Group, you can use the create_security_group() of the EC2 resource. To control inbound and outbound traffic, the authorize_ingress() and the authorize_egress() methods are used:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
VPC_ID = 'vpc-4b43de20'
security_group = EC2_RESOURCE.create_security_group(
    Description='Allow inbound SSH traffic',
    GroupName='allow-inbound-ssh',
    VpcId=VPC_ID,
    TagSpecifications=[
        {
            'ResourceType': 'security-group',
            'Tags': [
                {
                    'Key': 'Name',
                    'Value': 'allow-inbound-ssh'
                },
            ]
        },
    ],
)
security_group.authorize_ingress(
    CidrIp='0.0.0.0/0',
    FromPort=22,
    ToPort=22,
    IpProtocol='tcp',
)
print(f'Security Group {security_group.id} has been created')

Listing all Security Groups

To list all Security Groups, you can use the all() method of the security_groups collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
security_groups = EC2_RESOURCE.security_groups.all()
print('Security Groups:')
for security_group in security_groups:
    print(f'  - Security Group {security_group.id}')

Searching Security Groups

To find Security Groups by specified conditions, you can use the filter() method of the security_groups collection of the EC2 resource.

Searching Security Groups by ID

To find Security Groups by the Security Group ID, you can use the filter() method of the security_groups collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
SECURITY_GROUP_ID = 'sg-0e0fe09d642656bf3'
security_groups = EC2_RESOURCE.security_groups.filter(
    GroupIds=[
        SECURITY_GROUP_ID
    ]
)
for security_group in security_groups:
    print(f'Security Group {security_group.id} description: {security_group.description}')

Searching Security Groups by Tag

To find Security Groups by the Tag, you can use the filter() method of the security_groups collection of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
SECURITY_GROUP_ID = 'sg-0e0fe09d642656bf3'
security_groups = EC2_RESOURCE.security_groups.filter(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': [
                'allow-inbound-ssh',
            ]
        },
    ],
)
for security_group in security_groups:
    print(f'Security Group {security_group.id} description: {security_group.description}')

Describing Security Groups

To list all Security Group’s properties, you can use the describe_security_groups() method that supports the same search attributes as the filter() method of the EC2 resource:

#!/usr/bin/env python3
import json
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
SECURITY_GROUP_ID = 'sg-0e0fe09d642656bf3'
response = EC2_CLIENT.describe_security_groups(
    GroupIds=[
        SECURITY_GROUP_ID,
    ],
)
print(f'Security Group {SECURITY_GROUP_ID} attributes:')
for security_group in response['SecurityGroups']:
    print(json.dumps(
            security_group,
            indent=4
        )
    )

Deleting Security Groups

To delete a Security Group, you can use the delete() method of the SecurityGroup class of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
SECURITY_GROUP_ID = 'sg-0e0fe09d642656bf3'
security_group = EC2_RESOURCE.SecurityGroup(SECURITY_GROUP_ID)
security_group.delete()
print(f'Security Group {SECURITY_GROUP_ID} has been deleted')

Attaching Security Groups to the EC2 Instance

To attach Security Groups to the EC2 instance, you need to use the modify_attribute() method of the EC2.Instance class of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
SECURITY_GROUP_ID = 'sg-084dfa143cc85a5cf'
INSTANCE_ID = 'i-04091b10d2cdc86aa'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance.modify_attribute(
    Groups=[
        SECURITY_GROUP_ID
    ]
)
print(f'Security Group {SECURITY_GROUP_ID} has been attached to EC2 instance {INSTANCE_ID}')

Listing EC2 instance Security Groups

To list EC2 instance Security Groups, you can use the security_groups attribute of the EC2.Instance class of the EC2 resource:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-04091b10d2cdc86aa'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
print(f'Instance {INSTANCE_ID} Security Groups:')
for security_group in instance.security_groups:
    print(f'  - Security Group {security_group["GroupId"]}')

Detaching Security Group from the EC2 Instance

There’s no specific API call to detach the Security Group from the EC2 instance. To detach aSecurity Group from the EC2 Instance, you need to get all instance Security Groups as a list, remove the required Security Group from the list, and overrise the Groups EC2 instance attribute.

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-04091b10d2cdc86aa'
SECURITY_GROUP_ID = 'sg-6dbc5f1b'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
instance_sgs = [
    sg['GroupId'] for sg in instance.security_groups
]
if SECURITY_GROUP_ID in instance_sgs:
    instance_sgs.remove(SECURITY_GROUP_ID)
instance.modify_attribute(
    Groups=instance_sgs
)
print(f'Security Group {SECURITY_GROUP_ID} has been detached from the instance {INSTANCE_ID}')

How to manage Elastic IP addresses using Boto3?

The Elastic IP is a public IP address provided by AWS that doesn’t change when you start or stop the EC2 instance. In addition to that,the Elastic IP address can be attached or detached from the EC2 instance at any moment. By default, each AWS Account can allocate a maximum of five Elastic IP addresses.

Allocating Elastic IP address

To allocate an Elastic IP address for your AWS account, you can use the allocate_address() method of the EC2 client:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
allocation = EC2_CLIENT.allocate_address(
    Domain='vpc',
    TagSpecifications=[
        {
            'ResourceType': 'elastic-ip',
            'Tags': [
                {
                    'Key': 'Name',
                    'Value': 'my-elastic-ip'
                },
            ]
        },
    ]
)
print(f'Allocation ID {allocation["AllocationId"]}')
print(f'  - Elastic IP {allocation["PublicIp"]} has been allocated')

Listing and describing Elastic IP addresses

To list and describe Elastic IP addresses, you can use the descibe_addresses() method of the EC2 client:

#!/usr/bin/env python3
import json
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
response = EC2_CLIENT.describe_addresses(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': ['my-elastic-ip']
        }
    ]
)
print('EIP attributes:')
for address in response['Addresses']:
    print(json.dumps(address, indent=4))

Attaching an Elastic IP to an EC2 Instance

To associate an Elastic IP address with an EC2 Instance, you can use the associate_address() method of the EC2 client:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-04091b10d2cdc86aa'
response = EC2_CLIENT.describe_addresses(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': ['my-elastic-ip']
        }
    ]
)
public_ip = response['Addresses'][0]['PublicIp']
allocation_id = response['Addresses'][0]['AllocationId']
response = EC2_CLIENT.associate_address(
    InstanceId=INSTANCE_ID,
    AllocationId=allocation_id
)
print(f'EIP {public_ip} associated with the instance {INSTANCE_ID}')

Detaching an Elastic IP address from an EC2 instance

To disassociate (detach) an Elastic IP address from the EC2 instance, you need to use the disassociate_address() method of the EC2 client. The disassociate_address() method requires theAssociationId argument, which you can find by processing the list of the EC2 instance network interfaces:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
EC2_RESOURCE = boto3.resource('ec2', region_name=AWS_REGION)
INSTANCE_ID = 'i-04091b10d2cdc86aa'
instance = EC2_RESOURCE.Instance(INSTANCE_ID)
response = EC2_CLIENT.describe_addresses(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': ['my-elastic-ip']
        }
    ]
)
public_ip = response['Addresses'][0]['PublicIp']
for interface in instance.network_interfaces:
    if interface.association:
        if public_ip == interface.association.public_ip:
            EC2_CLIENT.disassociate_address(
                AssociationId=interface.association.id
            )
print(f'EIP {public_ip} diassociated from the instance {INSTANCE_ID}')

Releasing the Elastic IP address

To release an Elastic IP address, you can use the release_address() method of the EC2 client:

#!/usr/bin/env python3
import boto3
AWS_REGION = "us-east-2"
EC2_CLIENT = boto3.client('ec2', region_name=AWS_REGION)
response = EC2_CLIENT.describe_addresses(
    Filters=[
        {
            'Name': 'tag:Name',
            'Values': ['my-elastic-ip']
        }
    ]
)
public_ip = response['Addresses'][0]['PublicIp']
allocation_id = response['Addresses'][0]['AllocationId']
EC2_CLIENT.release_address(
    AllocationId=allocation_id
)
print(f'EIP {public_ip} has been released')

EBS Volumes, Snapshots, and AMIs

Manage EBS volumes using Boto3
Working with EC2 Snapshots and AMIs using Boto3

Summary

This article provides many Python code snippets for creating, starting, stopping, rebooting, filtering, deleting, and tagging EC2 Instances using the Boto3. In addition to that, we’ve covered the management of SSH keys, Security Groups, and Elastic IP addresses.