Ansible AWS: Complete Guide to Cloud Automation (2026)
By Luca Berton · Published 2026-04-03 · Category: installation
Complete guide to automating AWS with Ansible. Manage EC2, S3, IAM, VPC, RDS, and Lambda with amazon.aws collection and practical examples.
Ansible's amazon.aws and community.aws collections let you automate your entire AWS infrastructure — from EC2 instances to S3 buckets to RDS databases.
Setup
# Install collections
ansible-galaxy collection install amazon.aws
ansible-galaxy collection install community.aws
# Python requirements
pip install boto3 botocore
Authentication
# Method 1: Environment variables
# export AWS_ACCESS_KEY_ID='your-key'
# export AWS_SECRET_ACCESS_KEY='your-secret'
# export AWS_REGION='us-east-1'
# Method 2: In playbook (use vault!)
- hosts: localhost
vars:
aws_access_key: "{{ vault_aws_key }}"
aws_secret_key: "{{ vault_aws_secret }}"
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
AWS_REGION: us-east-1
# Method 3: AWS CLI profile
# ~/.aws/credentials configured, use profile parameter
See also: Ansible for AWS: Complete Guide to Cloud Automation with EC2, S3, RDS, and More
EC2 Instances
Launch an EC2 instance
- name: Launch EC2 instance
amazon.aws.ec2_instance:
name: web-server-01
instance_type: t3.medium
image_id: ami-0abcdef1234567890
key_name: my-keypair
security_groups:
- web-sg
vpc_subnet_id: subnet-12345678
network:
assign_public_ip: true
volumes:
- device_name: /dev/sda1
ebs:
volume_size: 50
volume_type: gp3
tags:
Environment: production
Role: webserver
state: running
register: ec2
- name: Show instance IP
debug:
msg: "Instance IP: {{ ec2.instances[0].public_ip_address }}"
Stop/Terminate instances
- name: Stop instances by tag
amazon.aws.ec2_instance:
filters:
"tag:Environment": staging
state: stopped
- name: Terminate instance
amazon.aws.ec2_instance:
instance_ids:
- i-1234567890abcdef0
state: terminated
Security Groups
- name: Create security group
amazon.aws.ec2_security_group:
name: web-sg
description: Web server security group
vpc_id: vpc-12345678
rules:
- proto: tcp
ports: [80, 443]
cidr_ip: 0.0.0.0/0
rule_desc: HTTP/HTTPS
- proto: tcp
ports: [22]
cidr_ip: 10.0.0.0/8
rule_desc: SSH from internal
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0
tags:
Name: web-sg
See also: Ansible Troubleshooting: Resolving community.aws.ec2_instance Issues
S3 Buckets
- name: Create S3 bucket
amazon.aws.s3_bucket:
name: my-app-assets-{{ aws_account_id }}
versioning: true
encryption: AES256
public_access:
block_public_acls: true
block_public_policy: true
tags:
Environment: production
- name: Upload file to S3
amazon.aws.s3_object:
bucket: my-app-assets
object: configs/app.yml
src: /opt/app/config.yml
mode: put
- name: Download from S3
amazon.aws.s3_object:
bucket: my-app-assets
object: configs/app.yml
dest: /opt/app/config.yml
mode: get
- name: Sync directory to S3
community.aws.s3_sync:
bucket: my-website
file_root: /opt/website/public
permission: public-read
VPC Networking
- name: Create VPC
amazon.aws.ec2_vpc_net:
name: app-vpc
cidr_block: 10.0.0.0/16
region: us-east-1
tags:
Environment: production
register: vpc
- name: Create public subnet
amazon.aws.ec2_vpc_subnet:
vpc_id: "{{ vpc.vpc.id }}"
cidr: 10.0.1.0/24
az: us-east-1a
tags:
Name: public-subnet-1a
register: public_subnet
- name: Create Internet Gateway
amazon.aws.ec2_vpc_igw:
vpc_id: "{{ vpc.vpc.id }}"
tags:
Name: app-igw
register: igw
See also: Ansible S3 Module: Upload, Download, Manage AWS S3 Objects (Complete Guide)
RDS Databases
- name: Create RDS PostgreSQL instance
community.aws.rds_instance:
db_instance_identifier: myapp-db
engine: postgres
engine_version: "16.1"
db_instance_class: db.t3.medium
allocated_storage: 100
master_username: admin
master_user_password: "{{ vault_rds_password }}"
vpc_security_group_ids:
- sg-12345678
db_subnet_group_name: my-db-subnet-group
backup_retention_period: 7
multi_az: true
tags:
Environment: production
Dynamic Inventory
# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
filters:
tag:managed_by: ansible
keyed_groups:
- key: tags.Role
prefix: role
- key: tags.Environment
prefix: env
compose:
ansible_host: public_ip_address
ansible-inventory -i inventory/aws_ec2.yml --graph
Complete Example: Web Application Stack
- name: Deploy AWS web stack
hosts: localhost
connection: local
tasks:
- name: Create VPC and networking
include_tasks: tasks/networking.yml
- name: Create RDS database
include_tasks: tasks/database.yml
- name: Launch web servers
amazon.aws.ec2_instance:
name: "web-{{ item }}"
instance_type: t3.medium
image_id: "{{ ami_id }}"
key_name: deploy-key
security_groups: ["{{ web_sg.group_id }}"]
vpc_subnet_id: "{{ public_subnet.subnet.id }}"
user_data: "{{ lookup('file', 'userdata.sh') }}"
count: 1
tags:
Role: webserver
Environment: production
loop: "{{ range(1, 4) | list }}"
FAQ
Should I use Ansible or Terraform for AWS?
Use both: Terraform for infrastructure provisioning (VPCs, subnets, RDS), Ansible for configuration management (installing software, deploying apps). They complement each other.
How do I handle AWS credentials securely?
Use IAM roles for EC2 instances (no credentials needed), AWS SSO profiles, or Ansible Vault for encrypted credentials. Never put keys in plaintext.
Can Ansible replace CloudFormation?
For many use cases, yes. Ansible's AWS modules cover most services. CloudFormation has better drift detection and rollback. Choose based on your team's workflow.
Setup
# Install AWS collection
ansible-galaxy collection install amazon.aws
# Install Python dependencies
pip install boto3 botocore
# Configure credentials
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=us-east-1
Launch EC2 Instance
- name: Launch EC2
amazon.aws.ec2_instance:
name: web-server
instance_type: t3.micro
image_id: ami-0c55b159cbfafe1f0
key_name: deploy-key
security_groups: [web-sg]
subnet_id: subnet-abc123
state: running
tags:
Environment: production
Team: web
wait: true
register: ec2
S3 Bucket
- amazon.aws.s3_bucket:
name: my-app-backups
versioning: true
tags:
Environment: production
- amazon.aws.s3_object:
bucket: my-app-backups
object: backups/db-backup.sql
src: /tmp/db-backup.sql
mode: put
VPC and Networking
- amazon.aws.ec2_vpc_net:
name: my-vpc
cidr_block: 10.0.0.0/16
tags: { Name: my-vpc }
register: vpc
- amazon.aws.ec2_vpc_subnet:
vpc_id: "{{ vpc.vpc.id }}"
cidr: 10.0.1.0/24
az: us-east-1a
tags: { Name: public-subnet }
register: subnet
- amazon.aws.ec2_security_group:
name: web-sg
description: Web server SG
vpc_id: "{{ vpc.vpc.id }}"
rules:
- proto: tcp
ports: [80, 443]
cidr_ip: 0.0.0.0/0
- proto: tcp
ports: [22]
cidr_ip: 10.0.0.0/8
RDS Database
- amazon.aws.rds_instance:
db_instance_identifier: myapp-db
engine: postgres
engine_version: "16.2"
db_instance_class: db.t3.micro
allocated_storage: 20
master_username: admin
master_user_password: "{{ vault_db_password }}"
vpc_security_group_ids: ["{{ sg.group_id }}"]
tags: { Environment: production }
Dynamic Inventory
# aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
keyed_groups:
- key: tags.Environment
prefix: env
- key: instance_type
prefix: type
filters:
instance-state-name: running
ansible-inventory -i aws_ec2.yml --list
ansible -i aws_ec2.yml env_production -m ping
Key Modules
| Module | Purpose |
|--------|---------|
| ec2_instance | Manage EC2 instances |
| s3_bucket | S3 buckets |
| s3_object | S3 files |
| ec2_vpc_net | VPCs |
| ec2_vpc_subnet | Subnets |
| ec2_security_group | Security groups |
| rds_instance | RDS databases |
| iam_role | IAM roles |
| route53 | DNS records |
| elb_application_lb | ALB |
FAQ
Ansible vs Terraform for AWS?
Terraform is purpose-built for AWS infrastructure with state management. Ansible can provision AWS resources but excels at post-provisioning configuration. Many teams use both.
How do I authenticate?
Environment variables (AWS_ACCESS_KEY_ID), IAM instance profiles, ~/.aws/credentials, or aws_access_key/aws_secret_key in tasks.
Can I manage multiple AWS accounts?
Yes — use profile parameter or set credentials per task/play.
Install Collection
ansible-galaxy collection install amazon.aws
pip install boto3 botocore
Configure Credentials
# Option 1: Environment variables
# export AWS_ACCESS_KEY_ID=AKIA...
# export AWS_SECRET_ACCESS_KEY=...
# Option 2: In playbook
- hosts: localhost
vars:
aws_access_key: "{{ vault_aws_key }}"
aws_secret_key: "{{ vault_aws_secret }}"
region: us-east-1
Launch EC2 Instance
- amazon.aws.ec2_instance:
name: web-server-1
instance_type: t3.medium
image_id: ami-0c55b159cbfafe1f0
key_name: my-keypair
security_group: web-sg
subnet_id: subnet-abc123
network:
assign_public_ip: true
tags:
Environment: production
Role: webserver
state: running
register: ec2
Manage S3
# Create bucket
- amazon.aws.s3_bucket:
name: my-app-backups
state: present
versioning: true
encryption: AES256
# Upload file
- amazon.aws.s3_object:
bucket: my-app-backups
object: backups/db-2026-04-07.sql.gz
src: /tmp/db-backup.sql.gz
mode: put
Create VPC
- amazon.aws.ec2_vpc_net:
name: my-vpc
cidr_block: 10.0.0.0/16
region: us-east-1
tags: { Environment: production }
register: vpc
- amazon.aws.ec2_vpc_subnet:
vpc_id: "{{ vpc.vpc.id }}"
cidr: 10.0.1.0/24
az: us-east-1a
tags: { Name: public-subnet }
register: subnet
Security Groups
- amazon.aws.ec2_security_group:
name: web-sg
description: Web server security group
vpc_id: "{{ vpc.vpc.id }}"
rules:
- proto: tcp
ports: [80, 443]
cidr_ip: 0.0.0.0/0
- proto: tcp
ports: [22]
cidr_ip: 10.0.0.0/8
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0
Dynamic Inventory
# aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
filters:
tag:Environment: production
keyed_groups:
- key: tags.Role
prefix: role
compose:
ansible_host: public_ip_address
ansible-inventory -i aws_ec2.yml --graph
RDS Database
- amazon.aws.rds_instance:
db_instance_identifier: my-postgres
engine: postgres
engine_version: "16.2"
db_instance_class: db.t3.medium
allocated_storage: 50
master_username: admin
master_user_password: "{{ vault_rds_password }}"
vpc_security_group_ids: ["{{ db_sg.group_id }}"]
state: present
no_log: true
IAM
- amazon.aws.iam_user:
name: deploy-bot
state: present
- amazon.aws.iam_policy:
iam_type: user
iam_name: deploy-bot
policy_name: s3-access
policy_json: |
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-app-*"
}]
}
FAQ
Do I need boto3?
Yes — all amazon.aws modules require boto3 and botocore Python packages on the controller.
How to use IAM roles instead of keys?
On EC2 instances with an IAM role, boto3 auto-discovers credentials. No access keys needed.
Can I manage multiple regions?
Yes — set region per task or use dynamic inventory with multiple regions.
Install Collection
ansible-galaxy collection install amazon.aws
pip install boto3 botocore
Authentication
# Environment variables (recommended)
# export AWS_ACCESS_KEY_ID=AKIA...
# export AWS_SECRET_ACCESS_KEY=...
# export AWS_DEFAULT_REGION=us-east-1
# Or in playbook
- hosts: localhost
vars:
aws_access_key: "{{ vault_aws_key }}"
aws_secret_key: "{{ vault_aws_secret }}"
region: us-east-1
EC2 Instance
- amazon.aws.ec2_instance:
name: web-server
instance_type: t3.micro
image_id: ami-0abcdef1234567890
key_name: my-keypair
security_group: web-sg
subnet_id: subnet-12345
state: running
tags:
Environment: production
App: mywebapp
register: ec2
S3 Bucket
- amazon.aws.s3_bucket:
name: my-app-assets
state: present
versioning: true
tags:
Environment: production
- amazon.aws.s3_object:
bucket: my-app-assets
object: config/app.conf
src: files/app.conf
mode: put
Security Group
- amazon.aws.ec2_security_group:
name: web-sg
description: Web server security group
rules:
- proto: tcp
ports: [80, 443]
cidr_ip: 0.0.0.0/0
- proto: tcp
ports: [22]
cidr_ip: 10.0.0.0/8
VPC
- amazon.aws.ec2_vpc_net:
name: my-vpc
cidr_block: 10.0.0.0/16
tags:
Environment: production
register: vpc
- amazon.aws.ec2_vpc_subnet:
vpc_id: "{{ vpc.vpc.id }}"
cidr: 10.0.1.0/24
az: us-east-1a
tags:
Name: public-subnet
IAM User
- amazon.aws.iam_user:
name: deploy-user
state: present
managed_policies:
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Dynamic Inventory
# aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
keyed_groups:
- key: tags.Environment
prefix: env
- key: instance_type
prefix: type
filters:
instance-state-name: running
compose:
ansible_host: public_ip_address
FAQ
How to use AWS profiles?
Set AWS_PROFILE environment variable or profile parameter in modules.
Costs from Ansible runs?
Ansible API calls to AWS are free. Costs come from resources you create (EC2, S3, etc.).
amazon.aws vs community.aws?
amazon.aws is maintained by Red Hat (certified). community.aws has additional community-contributed modules.
Related Articles
• Ansible Galaxy authentication • reading environment variables in Ansible playbooks • Ansible Vault Guide • static and dynamic Ansible inventory • Ansible loop patterns and tipsRelated: Ansible Database Automation
Category: installation