12 Cloud Commandments: Applying 12 Factor App Principles to Master Terraform — Part 2

Manish Warang
Engineered @ Publicis Sapient
8 min readMay 28, 2024

In Part 1, we introduced the integration of the 12 Factor App principles with Terraform to optimize Cloud infrastructure management. We began with an overview of these principles, highlighting their relevance in building scalable and maintainable applications.

The Codebase principle emphasized maintaining a single codebase with multiple deploys, ensuring a clean and organized environment. We also discussed the Dependencies principle, focusing on the need to explicitly declare and isolate dependencies to prevent hidden or unmanaged issues.

These foundational concepts set the stage for effective Infrastructure as Code practices using Terraform.

Config — Store configuration in the environment

Configurations are the seasoning of your infrastructure — they add flavor and personality, but too much can leave a bad taste in your mouth. Keep it simple, sprinkle just enough to enhance the flavor, and avoid drowning your dish in a sea of spices. Your infrastructure will thank you for it!

Scenario 1: The “Configuration Chaos Carnival”
Ever felt like you’re juggling a dozen flaming torches while riding a unicycle on a tightrope? Welcome to the Configuration Chaos Carnival! You have configurations spread across multiple files, environments, and even secret management systems. Keeping track of which setting applies where is like herding cats during a fireworks display — chaotic, unpredictable and downright dangerous. One wrong move could set off a chain reaction of misconfigurations, turning your infrastructure into a virtual circus of errors. It’s enough to make even the most seasoned Cloud or DevOps engineer question their sanity.

Scenario 2: The “Secrets Slip-Up”

Picture this: you’re deploying a critical application to production, and everything is going smoothly. But as you reach the final stages, you realize you forgot to properly manage your secrets. Your database passwords are hardcoded in plain text, API keys are floating around in Slack channels, and SSH keys are stored in a folder cleverly named “Not_Secrets.” It’s a security nightmare waiting to happen, like leaving the keys to your Ferrari in the ignition with a sign saying “Free Joyrides.”

Scenario 3: Environment-specific Configuration

Another challenge arises when managing environment-specific configuration in Terraform. In a typical application deployment pipeline, you may have multiple environments such as development, staging and production. Each environment requires different configuration settings, such as database endpoints, API URLs or feature flags. Hardcoding these settings directly into Terraform code leads to maintenance overhead and potential errors when promoting code across environments.

resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
subnet_id = "subnet-029b2e75"
security_groups = ["${var.security_group_name}"]
tags = {
Name = "ExampleInstance"
}
}

In this example, the subnet_id and security_group_name are hardcoded. While this may work for a specific environment, it becomes cumbersome to manage when deploying to different environments with unique network configurations.

In conclusion, adhering to the “Config” principle of the 12 Factor App is paramount, especially in the context of Terraform code. By separating configuration from code, we mitigate the headaches of managing environment-specific settings. Leveraging tools like Terraform’s input variables, or even external configuration management systems, enables seamless configuration across development, staging and production environments. This approach not only streamlines maintenance, but also enhances the reliability and scalability of our infrastructure provisioning process. Embracing the “Config” principle empowers DevOps teams to efficiently manage dynamic infrastructure requirements while fostering a culture of agility and resilience.

Backing Services — Treat backing services as attached resources

They are like your trusty sous chefs — they handle the grunt work so you can focus on the main course. Whether it’s a database slicing and dicing your data or a CDN spreading your content far and wide, choose your sidekicks wisely. After all, no one wants a sous chef who burns the soufflé!

Scenario 1: The Vanishing Database Conundrum

Imagine this scenario: you’re in the final stages of deploying a new application to the Cloud. Everything seems to be going smoothly` until it’s time to connect to the database. You enter the credentials provided by your colleague, only to be met with a dreaded error message: “Connection refused.” After several frantic Slack messages and a few cups of coffee, you discover that the database instance has mysteriously vanished into the digital ether. Turns out, your colleague forgot to renew the subscription, and now you’re left scrambling to spin up a new instance, and migrate the data before the stakeholders start breathing down your neck. It’s like trying to catch smoke with a butterfly net — frustrating, futile, and just a tad ridiculous.

Scenario 2: The Shadowy Service Blackout

Picture this: you’re knee-deep in troubleshooting a production issue that’s causing your application to crash more frequently than a Windows 95 computer. After hours of digging through logs and scratching your head, you finally uncover the culprit — a third-party service that your application relies on for critical functionality. But here’s the kicker: the service provider has suddenly gone dark, with no updates on their status page, and no response to your frantic support tickets. Now you’re stuck in a digital purgatory, waiting for the service to resurface like a submarine in distress. Meanwhile, your users are flooding your inbox with complaints, and your boss is giving you the stink eye from across the office. It’s a lesson in the importance of vetting and monitoring backing services, lest you find yourself adrift in a sea of uncertainty.

Scenario 3: Managing Database Credentials in Terraform Code

DevOps engineers face challenges in securely managing database credentials in Cloud infrastructure provisioning. To follow the 12 Factor App’s “Backing Service” principle, backing services like databases should be treated as attached resources. However, hardcoding sensitive information into Terraform configurations violates security best practices and makes the infrastructure less portable and maintainable. To address this, Terraform can be used to retrieve database credentials from secure secret management services like AWS Secrets Manager or HashiCorp Vault, separating infrastructure provisioning concerns from sensitive data management, adhering to the principle of treating backing services as attached resources.

data "external" "database_credentials" {
program = ["bash", "${path.module}/scripts/get_database_credentials.sh"]
}

resource "aws_db_instance" "example" {
# Other configuration options…
username = data.external.database_credentials.result.username
password = data.external.database_credentials.result.password
# Database instance configuration…
}

In this example, get_database_credentials.sh script retrieves database credentials from a secure source and outputs them in a format that Terraform can consume. By separating credential management from infrastructure code, you adhere to the principles of security, scalability, and portability advocated by the 12 Factor App.

In wrapping up, the “Backing Services” principle from the 12 Factor App provides a crucial framework for managing Infrastructure resources, e.g. databases securely in Cloud infrastructure provisioning. DevOps engineers often grapple with the challenge of safeguarding sensitive credentials, while ensuring infrastructure portability and maintainability. Terraform emerges as a powerful ally in this regard, enabling the separation of concerns by retrieving credentials from secure secret management services like AWS Secrets Manager or HashiCorp Vault. By adhering to this principle, we not only enhance security, but also streamline the management of backing services, fostering a robust and agile Cloud infrastructure ecosystem. Let’s embrace Terraform’s potential to uphold these principles and propel our Cloud and DevOps endeavors to new heights.

Build, Release, Run — Strictly separate build and run stages

Ah, the three musketeers of deployment — build, release and run. Like a well-choreographed dance routine, they work in harmony to bring your creation to life. But beware the rogue dancer who steps on everyone’s toes — keep your deployments smooth and your audiences applauding!

Scenario 1: The “Release Roulette”
Imagine this scenario: you’re preparing to deploy a new feature to production. You’ve meticulously built and tested the code on your local machine, but as soon as it hits the production environment, chaos ensues. The application crashes, users start complaining, and you’re left scrambling to figure out what went wrong. Turns out, the code that worked perfectly in your development environment doesn’t play nice with the dependencies and configurations in the production environment. It’s like trying to fit a square peg into a round hole, except the peg is your code and the hole is production. This release roulette not only disrupts the user experience, but also leaves you questioning your life choices as a DevOps engineer.

Scenario 2: The “Version Vortex”
Picture this: you’re knee-deep in managing multiple versions of your application across different environments. You have one version running in development, another in staging, and a different one in production. Keeping track of which version is where feels like playing a game of “Whac-A-Mole” with your sanity. You make a change to fix a bug in the staging environment, only to realize it’s the wrong version, and now you’ve introduced a new bug into production. It’s a never-ending version vortex that sucks you in deeper with each deployment, leaving you feeling more lost than a tourist without a map. Trying to maintain consistency and control across environments becomes a constant battle, with version numbers swirling around you like a tornado of confusion.

Scenario 3: Configuration Drift in Production Environment

Cloud and DevOps engineers face the challenge of maintaining consistency between different environments, particularly in dynamic Cloud infrastructure. The “Build, Release, Run” principle is crucial in ensuring environment parity by separating the build phase, where infrastructure configurations are defined in Terraform code, from the release and run phases, where these configurations are applied to different environments. This helps mitigate the risk of configuration drift.

A continuous delivery approach with Terraform pipelines enables automated deployments from a centralized source of truth, such as a version-controlled repository. Changes to the infrastructure are tested in lower environments before being promoted to production, reducing the likelihood of unexpected configuration drift. Tools like Terraform Enterprise offer features like state locking and version control, providing visibility and control over changes made to the production environment, thus maintaining consistency and reliability.

In conclusion, adopting the “Build, Release, Run” principle within Terraform coding not only addresses the challenge of maintaining consistency across various Cloud environments, but also fortifies the reliability of your infrastructure. By segregating the build phase from release and run phases, you effectively combat configuration drift, ensuring that what you build is exactly what you release and run. Embracing continuous delivery methodologies through Terraform pipelines automates deployments, fostering a culture of agility and reliability. With tools like Terraform Enterprise providing robust features such as state locking and version control, you gain unparalleled visibility and control over your infrastructure changes. In essence, integrating 12 Factor App principles into Terraform workflows elevates not just efficiency, but the integrity of your Cloud infrastructure.

More Reads

Part 1

Part 3

Part 4

--

--

Manish Warang
Engineered @ Publicis Sapient

Cloud Architect | Writing about cloud solutions, architecture, and innovation. Follow for insights and practical tips.