Unlocking the Power of Terraform: How the GitHub AT-AT is Evolving to Simplify Multi-Environment Automation
The evolution of the GitHub AT-AT model has been an exciting journey — one that began with the goal of automating infrastructure provisioning across multiple platforms and has now expanded to accommodate more complex, flexible scenarios. Originally, the GitHub AT-AT was designed as a simple, one-shot deployment to get users up and running with Terraform and Azure quickly. However, as I continued to use and improve the model, it became clear that there were opportunities to introduce more flexibility while maintaining the simplicity and ease of use that made the AT-AT so effective in the first place. In this article, I’ll walk you through the latest enhancements to the GitHub AT-AT, explaining how I updated the codebase, restructured the modules, and added new configurations to make the model more adaptable to a range of use cases.
Updated Codebase: Moving Beyond Random Strings
One of the first changes I made was to the codebase-terraform-azure-application module, which provisions a starter Azure Terraform codebase that creates a simple resource group. The original design used a random string to ensure the uniqueness of the resource group name, but this approach sometimes felt like overkill. Now, instead of using a random string, I rely on the application_name and environment_name input variables to guarantee the uniqueness of the resource group name. This update streamlines the process, making it simpler and more predictable.
Additionally, I added tags to the resource group, including the application name and environment name, to help users identify the resource easily. To further improve flexibility, I introduced an optional additional_tags variable, which allows users to add custom tags. This map of tags is intentionally defaulted to an empty map, giving users the option to opt in as needed.
Terraform Backend Module Enhancements
Another significant update involved the terraform-backend module. This module provisions a resource group, a storage account, and a container for both Terraform state and transient Terraform plan files. The GitHub Actions workflows in this module are designed with the assumption that Terraform state will be stored in this storage account, and that compiled Terraform plans will be saved in the container as well.
Previously, the GitHub AT-AT worked under the assumption that the state storage was a single, monolithic backend. I wanted to break away from this and make the architecture more flexible by allowing users to manage different environments separately. So, I modified the backend module to support non-production (non-PROD) Terraform state, enabling more granular control over backend configurations. This change helps improve organization and ensures that each environment can have its own backend if needed.
Refactoring the AT-AT Modules: Modularization and Flexibility
In the updated version of the GitHub AT-AT, I shifted away from the monolithic root module and restructured the project into a modules directory. Here, I’ve introduced two key modules:
- azure-dual-backend-core: This module provisions two separate backend modules for non-PROD Terraform state. These backends are designed to support multiple environments, such as development (dev), testing (test), and production (prod). I moved away from the traditional DEV-PROD split that was previously implied in the original version. This change was made to make it clearer that backend environments can and should be shared across various environments, not just split between dev and prod.
- azure-dual-backend-app: This module is the key to leveraging the dual backend setup. It takes backend configurations as input parameters for both non-PROD and PROD environments. This setup provides users with the flexibility to use the dual backend structure or create their own custom configuration. It is especially useful when implementing microservices or deploying multiple applications across different environments. This module is ideal for those working with services like Azure Functions or Kubernetes, and I plan to expand it to support Kubernetes as well.
Using Random Strings for One-Shot Deployments
For the azure-dual-backend-stand-alone module, I opted to keep the traditional “one-shot” approach, akin to the original GitHub AT-AT model. This module provisions the dual backends and sets up multiple environments using the flexible new configuration. It also adds a third non-prod environment called test and adjusts the GitFlow to support this new environment. This module is especially useful when you want to quickly deploy a complete solution and then destroy it when you’re finished testing.
module "backend" {
source = "../../modules/azure-dual-backend-core"
providers = {
azurerm.nonprod = azurerm.nonprod
azurerm.prod = azurerm.prod
}
name = "tf${random_string.backend_suffix.result}"
location = var.location
}
In this module, I use a random string to generate the Terraform state names, which allows for easy destruction once testing is complete. This is different from the shared backend version, where I use a more static name like “terraform-state” for the backend, as it’s meant to be a persistent environment.
Expanding GitFlow: Multiple Environments and Branches
The updated GitHub AT-AT now supports a more robust GitFlow structure with three environments: dev, test, and prod. This setup helps align the Terraform deployment with GitHub repository branches. The key here is that dev and test both use the same non-PROD backend, but each is stored on a different branch. This distinction is important because the GitHub Actions workflows are configured to trigger on specific branches. For example, a push or merge to the developbranch will trigger the deployment for the dev environment, while the release branch will trigger the test environment. Here’s an example of how the code is set up to define the environments:
module "app" {
source = "../../modules/azure-dual-backend-app"
application_name = var.application_name
github_organization = var.github_organization
repository_name = var.github_repository_name
repository_description = var.github_repository_description
repository_visibility = var.github_repository_visibility
terraform_version = var.terraform_version
commit_user = {
name = var.github_username
email = var.github_email
}
environments = {
dev = {
subscription_id = var.azure_nonprod_subscription
branch_name = "develop"
backend = module.backend.nonprod
}
test = {
subscription_id = var.azure_nonprod_subscription
branch_name = "release"
backend = module.backend.nonprod
}
prod = {
subscription_id = var.azure_prod_subscription
branch_name = "main"
backend = module.backend.prod
}
}
}
In this setup, dev and test share the same non-PROD backend, but their environments are differentiated by their respective branches (develop, release, and main). This change aligns the infrastructure provisioning process with the branching strategy in GitFlow, allowing for more streamlined deployments across different stages of development.
Maintaining Flexibility with Opinionated Modules
One of the challenges I faced was finding the balance between flexibility and the highly opinionated nature of the original GitHub AT-AT. The AT-AT model was designed with a very specific set of assumptions about the resources it should provision and the workflows it should use. While this made it great for getting started quickly, it also made it somewhat rigid. In the new version, I aimed to maintain the original simplicity while providing enough flexibility for users to customize the deployment to their needs. The modularization of the AT-AT allows users to swap in different components or configurations if needed, but the core modules are still highly opinionated. This means that the solution will work “out of the box” for most common use cases, but users can extend it to support more complex scenarios by integrating custom components or adjusting the configurations.
Conclusion
The new version of the GitHub AT-AT is a major step forward in making infrastructure automation more flexible and adaptable. By modularizing the codebase and adding support for multiple environments and GitFlow configurations, I’ve created a solution that is both powerful and customizable. The goal of reducing toil and speeding up project onboarding remains at the forefront, but with these new enhancements, users can now scale their automation efforts across more complex environments and use cases. Whether you’re working with microservices, deploying multiple applications, or experimenting with different cloud architectures, the GitHub AT-AT can help accelerate your journey to automation success.