# 🚀 Automating Scalable Infrastructure with Terraform & Ansible Dynamic Inventory

# 🚀 Automating Scalable Infrastructure with Terraform & Ansible Dynamic Inventory

## 🚀 Overview:

Modern infrastructure demands **automation, scalability, and repeatability**. Manual provisioning of cloud resources and configuration management quickly becomes error-prone and unmaintainable as environments grow.

This project demonstrates how to build a **fully automated, production-grade infrastructure pipeline** using **Terraform** for infrastructure provisioning and **Ansible with dynamic AWS inventory** for configuration management.

The solution provisions multiple EC2 instances across environments (dev, stage, prod), dynamically discovers them using AWS APIs, and configures them automatically — all without hardcoded IP addresses or manual intervention.

## 🔧 Problem Statement

Traditional infrastructure workflows often suffer from:

* Hardcoded server IPs in configuration files
    
* Manual SSH access and host inventory management
    
* Inconsistent environments across dev, stage, and prod
    
* Infrastructure drift due to manual changes
    
* Difficulty scaling across availability zones and environments
    

Additionally, many teams struggle with:

* Incorrect subnet placement
    
* SSH connectivity failures due to networking misconfigurations
    
* Poor separation between provisioning and configuration
    

This project solves these problems by combining **Infrastructure as Code (IaC)** with **dynamic configuration orchestration**.

## 💽 Techonology Stack

| Category | Tools |
| --- | --- |
| Infrastructure Provisioning | Terraform |
| Configuration Management | Ansible |
| Dynamic Inventory | Ansible AWS EC2 Plugin |
| Cloud Provider | AWS |
| Operating System | Ubuntu 22.04 LTS |
| Security | AWS Security Groups, IAM |
| Scripting | Bash |
| Version Control | Git & GitHub |

## 📌 Architecture Diagram

┌──────────────────┐

Local Machine (Deploy Scripts)

└─────────┬────────┘

▼

┌──────────────────────────┐

Terraform (IaC)

\- VPC & Subnets (existing)

\- EC2 Controller

\- EC2 Application Nodes

\- Security Groups

\- SSH Key Pair │

└─────────┬────────────────┘

▼

┌──────────────────────────┐

* * AWS EC2 Instances
        
    * \- Dev / Stage / Prod
        

\- Auto-assigned Public IP

└─────────┬────────────────┘

▼

┌──────────────────────────┐

Ansible Dynamic Inventory

\- AWS API Discovery

\- Tag-based Grouping

└─────────┬────────────────┘

▼

┌──────────────────────────┐

Ansible Playbooks

\- Configure environments

\- Apply roles

└──────────────────────────┘

### Key Architectural Decisions

* **Dynamic inventory** eliminates static host files
    
* **Tag-based grouping** separates dev/stage/prod automatically
    
* **Terraform-generated SSH keypair** ensures secure access
    
* **Public subnet detection via route tables** prevents silent networking failures
    
* **Preflight validation** ensures infrastructure readiness before configuration
    

## 🌟 Project Requirements

* AWS account with permissions for EC2, VPC, IAM
    
* Terraform ≥ 1.5
    
* Ansible ≥ 2.15
    
* AWS CLI configured (`aws configure`)
    
* Bash shell
    
* Git
    

## 📋 Table of Contents

I - **Terraform Configuration files**

[Step 1: Provider Configuration](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Provider-configuration)

[Step 2: Variables Configuration](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 3: Main Configuration](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-VPC-configuration)

[Step 4: Iam role Configuration](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-VPC-configuration)

[Step 5: Output Configuration](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Output-configuration)

[Step 6: User-data](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Output-configuration)

II - **Ansible files**

[Step 7: Inventory file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Provider-configuration)

[Step 8: Ansible configuration file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 9: Playbook file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 10: Requirements file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 11: Handlers](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 12: Tasks](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

[Step 13: Template files](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

III - **Scripting files**

[Step 14: Deploy file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Provider-configuration)

[Step 15: Destroy file](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-variables-configuration)

IV - **Instructions of Deployment**

[Step 16: Clone Repository](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Clone-Repository)

[Step 17: Run Deployment](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Format-Files)

[Step 18: Destroy Infrastructure](http://127.0.0.1:8000/vpc-foundation-terraform-on-aws/#-Format-Files)

## ✨Terraform Configuration files

You need to write different files generating resources

##### Step 1: ***Provider Configuration***

Here we declare our cloud provider and we specify the region where we will be launching resources

* [provider Configuration](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/providers.tf)
    

##### Step 2: ***Variables Configuration***

This is where we declare all variables and their value. It includes the list of element that can vary or change. They can be reuse values throughout our code without repeating ourselves and help make the code dynamic

* [variables Configuration](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/variables.tf)
    

##### Step 3: ***Main Configuration***

This is where you create the basement, foundation and networking where all the resources will be launch. It includes keypair, Security groups and EC2 instances,

* [Main Configuration](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/main.tf)
    

##### Step 4: ***IAM Role Configuration***

We define the temporary access to the instances via the role. it is a simple way of allow the controller to SSH via the others instances.

* [IAM Role Configuration](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/iam-role.tf)
    

##### Step 5: ***Output Configuration***

Know as Output Value : it is a convenient way to get useful information about your infrastructure printed on the CLI. It is showing all public IP of the instances.(Controller and nodes)

* [Output Configuration](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/outputs.tf)
    

##### Step 6: ***User-data***

user data is **<mark>a script or custom data that you provide to an EC2 instance to be executed automatically on its first launch</mark>**. It's used to automate the initial setup of an instance, such as installing software, configuring settings, or running commands needed to make the instance ready for use. In our case we will have two user data one for the controller where ansible and all dependencies will be install. The the one for the nodes where Python3 will be install.

* [Userdata-controller](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/userdata-controller.sh)
    
* [Userdata-node](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/terra-config/userdata-node.sh)
    

## ✨Ansible files

You need to write different files generating resources

##### Step 7 : ***Inventory file***

The Ansible AWS EC2 inventory plugin dynamically discovers EC2 instances directly from AWS using API calls instead of static host files. Instances are grouped automatically based on tags, regions, or environments, ensuring inventories stay accurate as infrastructure scales or changes.

* [Inventory : AWS plugin](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/inventory/aws_ec2.yml)
    

##### Step 8: ***Ansible Configuration***

The `ansible.cfg` file defines global Ansible behavior such as inventory location, SSH settings, privilege escalation, and retry behavior. It standardizes execution across environments and prevents inconsistencies caused by user-specific defaults.

* [ansible.cfg](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/ansible.cfg)
    

##### Step 9: ***Playbook file***

An Ansible playbook is a declarative YAML file that defines which tasks run on which hosts and in what order. It orchestrates configuration, package installation, and service management in a repeatable and idempotent manner.

* [playbook.yml](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/playbook.yml)
    

##### Step 10: ***Requirements file***

The `requirements.yml` file defines external Ansible roles or collections required by the project. This ensures consistent dependencies across environments and allows easy setup using a single installation command.

* [requirements.yml](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/requirements.yml)
    

##### Step 11: ***Handlers file***

Handlers are special Ansible tasks that run only when triggered by a change in another task. They are commonly used for operations like restarting services, ensuring actions occur only when necessary and avoiding unnecessary disruptions.

* [main.yml](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/roles/webserver/handlers/main.yml)
    

##### Step 12: ***Tasks file***

This is where you create the basement, foundation and networking where all the resources will be launch. It includes keypair, Security groups and EC2 instances,

* [main.yml](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/roles/webserver/tasks/main.yml)
    

##### Step 13: ***Template files***

The `index.html` template is a Jinja2-based HTML file dynamically rendered by Ansible during deployment. It allows environment-specific values (such as hostnames or environment names) to be injected into web content automatically. Deploys environment-specific `index.html` pages:

* [prod.html](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/roles/webserver/templates/prod.html). → Portfolio UI with achievements, skills, certifications, socials, and image.
    
* [dev.html](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/roles/webserver/templates/dev.html). → Minimal UI with a developer theme.
    
* [stage.html](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/ansible/roles/webserver/templates/stage.html). → Modern preview UI.
    

## ✨ Scripting files

You need to write different bash script files generating and destroying resources. The file will contains all step by step meaning all terraform command and ansible management for the execution of the process.

##### Step 14: ***Deploy file***

Here we declare the initialization of the folder, the validation of the configuration, the plan of resources to be create and apply of the execution where we will be launching resources, then we will SSH in the controller and pursuit the deployment of the index webpage in all 6 instances in three environment..

* [Deploy file](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/deploy.sh)
    

##### Step 15: ***Destroy file***

This is where we declare the script that will allow terraform command to destroy all the resources created and all other dependencies and ansible to be destroy.

* [Destroy file](https://github.com/Joebaho/Terra-Ansible-Dynamic/blob/main/destroy.sh)
    

## 💼 Instructions of Deployment

Follow these steps to deploy the architecture:

##### Step 16: ***Clone Repository:***

Clone the repository in your local machine using the command "git clone" then enter the folder

> git clone [https://github.com/Joebaho/Terra-Ansible-Dynamic.git](https://github.com/Joebaho/Terra-Ansible-Dynamic.git)
> 
> cd Terra-Ansible-Dynamic

##### Step 17: ***Run Deployment***

For a one time deployment of the infrastructures and configuration of the application you must type both commands bellow. These would launch the process and get everything ready. Terraform and Ansible would apply the configuration and management of the webpages in each environments.

> chmod +x deploy.sh
> 
> ./deploy.sh

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770413205134/b8c199e4-d2e4-4415-a619-bd8347cfcc6b.png align="center")

The process will execute all terraform command and display the following steps. You must see this image

Terraform init: Initialize the folder. Terraform fmt & validate: Check for any syntax error and valid the status of the configuration files

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770414884872/1bca9879-a01a-4c4e-b851-39322dec51f9.png align="center")

Terraform apply: confirm all resources created and Terraform output: show all the output information to be use by user.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770414964835/9afab2fe-8e80-4c33-a468-77f48e3a4f26.png align="center")

After all infrastructure deploy, Ansible now take over and starting process by first via the aws ec2 plugin will collect the public Ip of all the instances.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415178899/e2ad670e-6e8c-4195-8787-92414e2ce7e0.png align="center")

Then ansible will run the playbook

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415224726/55081b70-b7a8-4575-975c-a237ce1b3c41.png align="center")

Continue the play following each stage or environment

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415305805/18e3fb35-a642-4274-afa2-2976536c14fe.png align="center")

Playbook completed you will have the confirmation

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415357702/dfd50937-f24f-46dc-b52c-cce1e41c2191.png align="center")

Going back in the console we can see all instances created

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415434414/4ddcb137-1bf4-4966-9b49-fdcb892e4585.png align="center")

By picking any public IP and paste that in a new window on the browser and the web page will display. As we had three environments we will have three webpage

Prod webpage

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415616716/b5f1be28-b636-414b-9fa1-3960427e1d30.png align="center")

Dev Webpage

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415649322/7c3ee5d4-f867-49ed-8855-43ce412daae9.png align="center")

stage webpage

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770415665928/cd2edc32-dad8-4c29-a488-676578e13254.png align="center")

##### Step 18: ***Destroy infrastructure***

After you are done with the infrastructure and you are ready to destroy you can run the command. First you make the file executable then you apply execution.

> chmod +x destroy.sh
> 
> ./destroy.sh

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770413434851/477aafce-2aed-401f-82eb-13479a4569bf.png align="center")

After typing or pasting the command, the process will destroy all infrastructures and configuration files. You will get bellow image as confirmation

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770414745046/e600a881-fb93-47d6-9d28-30c77b9cff3b.png align="center")

## **📌 Learning Outcomes**

* Through this project, you will learn how to:
    
    * Build **production-ready Terraform modules**
        
    * Avoid common AWS networking pitfalls (public vs private subnets)
        
    * Use **Ansible dynamic inventory with AWS**
        
    * Eliminate static inventory files
        
    * Secure SSH access using Terraform-managed keys
        
    * Debug real-world infrastructure issues (timeouts, subnet routing)
        
    * Structure deploy/destroy workflows professionally
        
    * Create **reusable DevOps portfolio projects**
        

---

## **🔗 Resources**

* * Terraform AWS Provider Documentation  
        [https://registry.terraform.io/providers/hashicorp/aws/latest/docs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)
        
    * [Ansible Dynamic Inventory (AWS EC2)  
        ](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)[https://docs.ansible.com/ansible/latest/plugins/inventory/aws\_ec2.html](https://docs.ansible.com/ansible/latest/plugins/inventory/aws_ec2.html)
        
    * [AWS VPC Routing Concepts  
        ](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)[https://docs.aws.amazon.com/vpc/latest/userguide/VPC\_Route\_Tables.html](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html)
        
    * [In](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html)f[rastructure as Code Best Practices  
        ](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)[https://www.hashicorp.com/resources/infrastructure-as-code](https://www.hashicorp.com/resources/infrastructure-as-code)
        

## [🤝 Contributing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)

[Your perspective is valuable! Whether you see po](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)tential for imp[rovem](https://developer.hashicorp.com/terraform/cli)ent or ap[pre](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)ciate what'[s](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html) already here, your contributions are welcomed and appreciated. Thank [you for](https://developer.hashicorp.com/terraform/cli) [considering joini](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)[ng](https://developer.hashicorp.com/terraform/cli) [us in making this project even better. Feel free to follow me for upda](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html)tes on this project and others, and to explore opportunities for collaboration. Together, we can create something amazing!

Contributions are welcome 🚀

If you’d like to improve this project:

1. Fork the repository
    
2. Create a feature branch
    
3. Submit a pull request
    

Ideas for contributions:

* Add private subnet + NAT architecture
    
* Introduce Ansible roles
    
* Add CI/CD validation
    
* Extend to multi-region deployments
    

## 📄 License

This project is licensed under the JoebahoCloud License
