# How to Use Ansible for Automating EC2 Instances and RDS Databases: A Complete Guide

> Automate AWS EC2 instances and RDS databases with Ansible. Use agentless architecture and cloud modules to provision and manage your infrastructure via YAML playbooks. Learn how now.

- Repository: [Arie Bregman/devops-exercises](https://github.com/bregman-arie/devops-exercises)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Ansible automates EC2 instances and RDS databases using agentless architecture and cloud-specific modules like `amazon.aws.ec2` and `community.aws.rds`, enabling you to provision, configure, and manage AWS infrastructure through declarative YAML playbooks.**

Ansible serves as a powerful automation engine for managing diverse cloud infrastructure components without requiring agents on target systems. In the `bregman-arie/devops-exercises` repository, comprehensive exercises demonstrate how to leverage Ansible's cloud modules and dynamic inventory to automate EC2 instances and RDS databases, making infrastructure provisioning repeatable and version-controlled.

## Understanding Ansible Cloud Automation Architecture

Ansible manages cloud resources through four distinct layers that work together to provide declarative infrastructure management.

### Inventory Layer

The inventory lists target hosts or cloud services Ansible communicates with. Static files work for on-premises hosts, while **dynamic inventory** pulls live data from AWS APIs. According to [`topics/ansible/README.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/ansible/README.md), dynamic inventory is essential when hosts are created or terminated automatically, ensuring playbooks always reference current cloud state.

### Playbook Layer

Playbooks are YAML files that orchestrate tasks, groups, roles, and variables. As shown in [`topics/ansible/my_first_playbook.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/ansible/my_first_playbook.md), playbooks define *what* should exist (EC2 instances, security groups, RDS clusters) rather than *how* to create them.

### Module Layer

Modules perform single actions such as creating an EC2 instance or modifying an RDS parameter group. Ansible ships with official AWS modules under `amazon.aws.*` and `community.aws.*` collections. The `ansible-doc -l` command lists available modules as referenced in the repository's self-assessment section.

### Dynamic Inventory Implementation

Dynamic inventory scripts or plugins query AWS APIs to generate runtime inventories. The [`aws_ec2.yaml`](https://github.com/bregman-arie/devops-exercises/blob/main/aws_ec2.yaml) configuration file defines how Ansible discovers EC2 instances:

```yaml
plugin: amazon.aws.ec2
regions:
  - us-east-1
filters:
  tag:Environment: production
keyed_groups:
  - key: tags.Role
    prefix: role

```

Save this file as [`inventory/aws_ec2.yaml`](https://github.com/bregman-arie/devops-exercises/blob/main/inventory/aws_ec2.yaml) and execute:

```bash
ANSIBLE_INVENTORY=inventory/aws_ec2.yaml ansible-playbook provision.yml

```

## Automating EC2 Instances with Ansible

Managing EC2 instances requires combining dynamic inventory discovery with the `amazon.aws.ec2` module for idempotent provisioning.

### Configuring Dynamic Inventory for AWS

Before provisioning, configure the dynamic inventory plugin to discover existing instances. As noted in [`topics/aws/exercises/launch_ec2_instance/exercise.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/aws/exercises/launch_ec2_instance/exercise.md), understanding EC2 parameters (AMI ID, instance type, security groups) is prerequisite to automating them.

### Provisioning EC2 Instances Using the amazon.aws.ec2 Module

The following playbook demonstrates complete EC2 automation:

```yaml
---
- name: Provision EC2 instances for production
  hosts: localhost          # control host talks directly to AWS

  gather_facts: false
  collections:
    - amazon.aws

  vars:
    instance_type: t3.medium
    ami_id: "{{ lookup('env','AWS_AMI') | default('ami-0c55b159cbfafe1f0') }}"
    key_name: my-ssh-key
    security_group: sg-0123456789abcdef0
    subnet_id: subnet-0a1b2c3d4e5f6g7h8

  tasks:
    - name: Ensure EC2 instance exists
      amazon.aws.ec2:
        key_name: "{{ key_name }}"
        instance_type: "{{ instance_type }}"
        image_id: "{{ ami_id }}"
        region: us-east-1
        vpc_subnet_id: "{{ subnet_id }}"
        group_id: "{{ security_group }}"
        count: 2
        wait: true
        state: present
      register: ec2

    - name: Show created instance IDs
      debug:
        var: ec2.instances

```

This playbook uses the `amazon.aws.ec2` module documented in the AWS collection. It is fully **idempotent**—re-running it will only create missing instances, preventing duplicates.

## Managing RDS Databases with Ansible

RDS automation follows similar patterns but requires the `community.aws` collection for database-specific modules.

### Deploying RDS Instances with community.aws.rds

As referenced in [`topics/aws/exercises/mysql_db/exercise.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/aws/exercises/mysql_db/exercise.md), RDS configuration involves subnet groups, parameter groups, and engine specifications. The following role tasks automate RDS deployment:

```yaml
---
- name: Ensure DB subnet group exists
  community.aws.rds_subnet_group:
    name: prod-db-subnet
    description: Subnet group for production RDS
    subnet_ids:
      - subnet-0a1b2c3d4e5f6g7h8
      - subnet-1b2c3d4e5f6g7h8i9
    state: present

- name: Deploy PostgreSQL RDS instance
  community.aws.rds:
    command: create
    instance_name: prod-db
    engine: postgres
    engine_version: "13.4"
    db_instance_class: db.t3.medium
    allocated_storage: 20
    master_username: "{{ rds_username }}"
    master_user_password: "{{ rds_password }}"
    multi_az: true
    publicly_accessible: false
    db_subnet_group_name: prod-db-subnet
    tags:
      Environment: production
    state: present

```

Include this role in a top-level playbook that runs against `localhost` (no remote host needed—Ansible communicates directly with AWS APIs):

```yaml
- name: Deploy RDS
  hosts: localhost
  gather_facts: false
  collections:
    - community.aws
  vars:
    rds_username: admin
    rds_password: "{{ lookup('env','RDS_PASSWORD') | default('ChangeMe123!') }}"
  roles:
    - rds_provision

```

### Configuring DB Subnet Groups and Security

The `community.aws.rds_subnet_group` module ensures network isolation prerequisites exist before database deployment. This declarative approach prevents deployment failures due to missing infrastructure dependencies.

## Orchestrating Complete Infrastructure Stacks

A single orchestrating playbook can provision a VPC, launch EC2 workers, spin up an RDS instance, and wire security groups together:

```yaml
---
- import_playbook: provision_ec2.yml
- import_playbook: rds_deploy.yml

```

Running `ansible-playbook site.yml` provisions both compute and database layers in a single, reproducible run. Because Ansible is **push-based**, you can trigger this from CI pipelines (GitHub Actions) or local developer machines. The same playbooks serve both **development** and **production** environments through different inventory files or variable overrides.

## Summary

- **Ansible uses agentless architecture** to manage EC2 and RDS through cloud-specific modules without installing software on target instances.
- **Dynamic inventory** (`amazon.aws.ec2` plugin) automatically discovers cloud resources, ensuring playbooks always reference current infrastructure state.
- **Idempotent modules** like `amazon.aws.ec2` and `community.aws.rds` ensure repeated runs create no duplicate resources.
- **Role-based organization** separates EC2 provisioning from RDS management, enabling reusable infrastructure code.
- **Push-based execution** allows integration with CI/CD pipelines for automated infrastructure deployment.

## Frequently Asked Questions

### What is the difference between static and dynamic inventory for AWS automation?

Static inventory requires manually listing hostnames or IP addresses in files, which becomes unmanageable with auto-scaling EC2 instances. Dynamic inventory uses plugins like `amazon.aws.ec2` to query AWS APIs at runtime, automatically grouping instances by tags or regions. According to [`topics/ansible/README.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/ansible/README.md), dynamic inventory is essential when hosts are created or terminated automatically.

### How does Ansible ensure idempotency when managing EC2 instances?

Ansible modules like `amazon.aws.ec2` check the current state of AWS resources before taking action. When you specify `state: present` and provide instance parameters, the module queries existing instances and only creates new ones if the desired count or configuration is not met. Re-running the same playbook from [`provision_ec2.yml`](https://github.com/bregman-arie/devops-exercises/blob/main/provision_ec2.yml) will not create duplicate instances if the desired state already exists.

### Can Ansible manage RDS databases without installing agents on database servers?

Yes, Ansible manages RDS through AWS API calls rather than direct host connections. The `community.aws.rds` module communicates with the AWS RDS service to create, modify, or delete database instances. As shown in the `rds_provision` role tasks, playbooks run against `localhost` with `gather_facts: false`, using API credentials to manage the database lifecycle without ever connecting to the RDS instance directly.

### Which Ansible collections are required for AWS cloud automation?

For comprehensive AWS automation, you need the `amazon.aws` collection for core EC2, VPC, and IAM resources, and the `community.aws` collection for additional services like RDS. The `amazon.aws.ec2` module handles instance provisioning, while `community.aws.rds` and `community.aws.rds_subnet_group` manage database resources. Install these via `ansible-galaxy collection install amazon.aws community.aws` before executing cloud playbooks.