Work with boto3 for AWS automation
Learn to work with boto3 for AWS automation in this hands-on Python for DevOps tutorial. Master core concepts, complete practical exercises, and prepare for next steps.
Focus: work with boto3 for aws automation
Manually clicking through the AWS Console to create S3 buckets, snapshot EC2 instances, or rotate IAM keys is a productivity killer — and worse, it's a reliability risk when someone forgets a step or applies the wrong configuration. If you're a DevOps engineer automating cloud infrastructure, you need a programmatic, repeatable way to manage AWS resources. That's exactly what boto3, the official AWS SDK for Python, gives you. This lesson shows you how to work with boto3 for AWS automation — from the core mental model to practical, runnable scripts that you can adapt immediately.
The problem this lesson solves
Imagine you need to provision a new S3 bucket for every feature branch, snapshot a database before a risky migration, or clean up old EC2 instances. Doing this by hand doesn't scale and invites human error. The problem: cloud operations are tedious, error-prone, and impossible to audit when done manually. The solution: using Python with boto3 to define infrastructure and operations as code — so the same script runs the same way every time, and you can version it, review it, and reuse it.
Pro tip: boto3 is not just a wrapper around the AWS API. It handles retries, pagination, and session management for you — things that would take hours to implement yourself.
Core concept / mental model
Think of boto3 as your Python conversation layer with AWS. Instead of clicking buttons, you send request objects and receive response objects. The SDK translates your Python calls into HTTP requests to AWS's service endpoints, and then parses the JSON responses back into Python dictionaries and lists.
Here's the mental model:
1. Client vs. Resource — boto3.client() gives you a low-level, service-specific client (e.g., s3, ec2) with get_, create_, delete_ methods. boto3.resource() gives a higher-level, object-oriented interface where you work with Bucket, Instance, etc.
2. Session & Credentials — boto3 uses a credential chain: environment variables, shared credential file, IAM roles, or AWS config. The default chain works out-of-the-box for most setups.
3. Pagination — AWS APIs often return limited results per call. boto3 can automatically loop through pages using the PaginationConfig parameter or the paginator objects.
4. Regions — Every client is bound to a region (e.g., us-east-1). Some resources are global (like IAM), but most are regional.
import boto3
# Low-level client
s3_client = boto3.client('s3', region_name='us-east-1')
print(type(s3_client)) # <class 'botocore.client.S3'>
# High-level resource
s3_resource = boto3.resource('s3', region_name='us-east-1')
print(type(s3_resource)) # <class 'boto3.resources.factory.s3.ServiceResource'>
Output:
<class 'botocore.client.S3'>
<class 'boto3.resources.factory.s3.ServiceResource'>
How it works step by step
Working with boto3 follows a predictable sequence — once you learn it, you can apply the same pattern to any AWS service.
- Install and import boto3 —
pip install boto3. Thenimport boto3in your script. - Configure credentials — Either set environment variables like
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY, or use the shared credentials file at~/.aws/credentials. For security, prefer IAM roles when running in EC2 or Lambda. - Create a client or resource — Choose based on whether you need granular control (client) or convenience (resource).
- Call the method — For example,
s3.create_bucket(Bucket='name', CreateBucketConfiguration={'LocationConstraint': 'us-west-2'}). - Handle the response — The response is a
dictwith a'ResponseMetadata'key, plus service-specific data. Always check theHTTPStatusCode. - Iterate with paginators when needed — For lists (e.g., all S3 buckets or EC2 instances), use
paginator.paginate()to loop through all results.
Hands-on walkthrough
Let's build a real automation script: list and clean up old EC2 snapshots. This is a common DevOps task to save cost.
Example 1: List EC2 instances and their states
import boto3
def list_instances(region='us-east-1'):
ec2 = boto3.client('ec2', region_name=region)
response = ec2.describe_instances()
instances = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instances.append({
'Id': instance['InstanceId'],
'State': instance['State']['Name'],
'Type': instance['InstanceType']
})
return instances
print(list_instances())
Expected output (example):
[{'Id': 'i-0abc1234567890def', 'State': 'running', 'Type': 't3.micro'},
{'Id': 'i-0fedcba9876543210', 'State': 'stopped', 'Type': 'm5.large'}]
Example 2: Snapshot all EBS volumes attached to running instances
import boto3
def snapshot_running_volumes(region='us-east-1'):
ec2 = boto3.client('ec2', region_name=region)
instances = ec2.describe_instances(Filters=[{'Name': 'instance-state-name', 'Values': ['running']}])
snapshots = []
for reservation in instances['Reservations']:
for instance in reservation['Instances']:
for block in instance['BlockDeviceMappings']:
vol_id = block['Ebs']['VolumeId']
resp = ec2.create_snapshot(
VolumeId=vol_id,
Description=f"Snapshot for {instance['InstanceId']} on {datetime.utcnow()}"
)
snapshots.append(resp['SnapshotId'])
return snapshots
from datetime import datetime
print(snapshot_running_volumes())
Note: This script requires ec2:CreateSnapshot and ec2:DescribeInstances permissions.
Example 3: Use a paginator to list all S3 buckets
import boto3
s3 = boto3.client('s3')
paginator = s3.get_paginator('list_objects_v2')
for page in paginator.paginate(Bucket='my-bucket', PaginationConfig={'PageSize': 5}):
for obj in page.get('Contents', []):
print(obj['Key'], obj['Size'])
Compare options / when to choose what
| Approach | Best for | Pros | Cons |
|---|---|---|---|
| boto3 client | Granular control, complex API calls | Full access to every API parameter | Verbose, lower-level |
| boto3 resource | Simple CRUD operations, readability | Less boilerplate, object-like syntax | Not available for all services (e.g., IAM) |
| AWS CLI + subprocess | Quick one-off tasks from shell | No Python overhead, easy to script | Mixing languages, harder to handle complex logic |
| Terraform / CloudFormation | Infrastructure-as-code (IaC) | Declarative, state management | Not Python, requires learning HCL/YAML |
When to choose what: Use boto3 client when you need detailed control or when the resource interface doesn't exist. Use resource for frequent, simple operations (like S3). For infrastructure provisioning that's long-lived, consider Terraform — but for day-to-day operations, boto3 is your Swiss Army knife.
Troubleshooting & edge cases
1. No credentials found
botocore.exceptions.NoCredentialsError: Unable to locate credentials
Fix: Set environment variables or configure ~/.aws/credentials correctly. Verify with aws sts get-caller-identity.
2. Permission denied
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the ListBuckets operation
Fix: Ensure your IAM policy includes the required actions (e.g., s3:ListAllMyBuckets).
3. Wrong region for S3 bucket creation
Creating an S3 bucket in us-east-1 doesn't require LocationConstraint, but other regions do. If you specify one for us-east-1, you'll get IllegalLocationConstraintException. Use conditional logic.
import boto3
s3 = boto3.client('s3', region_name='us-east-1')
try:
s3.create_bucket(Bucket='my-bucket')
except ClientError as e:
# Handle 409 BucketAlreadyOwnedByYou
pass
4. Pagination missed items
If you only fetch one page, you might miss resources. Always use paginators or loop until IsTruncated is false.
5. Rate limiting
AWS throttles API calls. boto3 retries automatically, but you should still add exponential backoff for robustness.
What you learned & what's next
You now understand how to work with boto3 for AWS automation — the core client/resource model, how to authenticate, and how to automate common tasks like listing instances, snapshotting volumes, and paginating results. You've completed a practical exercise that can be extended to manage your own infrastructure.
Next step: Now that you can automate AWS with Python, the next lesson in this track will show you how to build reusable boto3 helper modules — wrapping common operations (like instance start/stop or S3 upload/download) into clean, testable functions you can use across your DevOps tooling. You'll also learn how to integrate these helpers into CI/CD pipelines. Until then, try extending today's script to automatically delete snapshots older than 7 days — a classic cost-saving automation.
Practice recap
Extend the snapshot script to add a retention policy: before creating a new snapshot, list existing snapshots with the same description prefix and delete any older than 7 days. Run it against a test instance to verify it works, then schedule it with cron or CloudWatch Events to run nightly.
Common mistakes
- Hardcoding AWS credentials directly in Python scripts — use environment variables, IAM roles, or the shared credential file instead.
- Forgetting to handle
ClientError— AWS returns this for permission issues, invalid parameters, and resource conflicts; wrap calls in try/except to give meaningful errors. - Using
boto3.client()for S3 when you only need simple bucket operations — the resource interface saves lines and is easier to read. - Ignoring pagination — calling
list_objects_v2()once only returns up to 1000 objects; always use paginators or loop untilIsTruncatedis false. - Not specifying a region for regional services like EC2 — every client needs a region, otherwise boto3 uses the default config which may differ from where your resources are.
Variations
- Use boto3 resource interfaces for high-level CRUD (e.g.,
s3.Bucket('name').upload_file()) when you prefer object-oriented syntax. - Use AWS CLI via
subprocessfrom Python if you need quick one-off commands and don't want to write full boto3 code. - Consider Terraform or CloudFormation for declarative infrastructure-as-code when provisioning long-lived resources, but use boto3 for operational tasks (snapshots, cleanup, monitoring).
Real-world use cases
- Automated nightly EBS snapshots for EC2 instances with retention policy cleanup using boto3.
- CI/CD pipeline step that creates an S3 bucket for each deployment artifact, uploads files, and sets lifecycle rules.
- Cost-reduction bot that scans and terminates idle EC2 instances after hours using boto3 and AWS Lambda.
Key takeaways
- boto3 is the official AWS SDK for Python, providing both low-level clients and high-level resources.
- Always configure credentials securely — prefer environment variables or IAM roles over hardcoded keys.
- Use paginators for any API that returns lists to ensure you capture all resources.
- Handle
ClientErrorexceptions to gracefully manage permission and resource conflicts. - Automate common DevOps tasks (backups, cleanup, provisioning) with reusable Python scripts.
- Boto3 is ideal for operational tasks, while Terraform/CloudFormation excel at declarative provisioning.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.