Introduction
In Infrastructure as Code (IaC), managing configuration and data presents specific challenges. While configuration can be stored in a version control system, structuring it according to a particular hierarchy—such as development, staging, and production or across different datacenters and regions—can be complex. Ensuring no drift and managing dependencies like networking configurations, security groups, and load balancers, especially across multiple cloud vendors, adds to the complexity. Testing configurations before deployment also poses challenges.
Data management might seem simpler, but it involves security, encryption, consistency, integrity, data governance, compliance, multi-cloud management, and backup and restoration concerns.
Effectively addressing these challenges requires a blend of best practices, automation, and robust tooling to ensure reliable and secure infrastructure deployments. While this post may not provide all the answers, it aims to inspire and guide you in optimizing your practices.

How to get a secure and compliant infrastructure through code?
This paper is for IT Managers, DevOps & Cloud engineers, and software architects involved in infrastructure management and deployment.
Terraform and OpenTofu: Central Tools in IaC
APIs have revolutionized datacenters, enabling the “Cloud” by exposing infrastructure management components. This standardization and interoperability facilitate automation, self-service, resource sharing, and elasticity, bridging the gap between applications and infrastructure.
However, abstraction and interoperability still need improvement. Major vendors like AWS, Google Cloud Platform, Azure, Alibaba Cloud, IBM Cloud, and Oracle Cloud Infrastructure have their unique methods for requesting and configuring resources, despite sharing abstract concepts like Virtual Machines or containers, storage, and load balancers.
Terraform, developed by HashiCorp in 2014, automates the provisioning of infrastructure, including servers, databases, and firewall policies. In August 2023, HashiCorp transitioned Terraform from the open-source Mozilla Public License (v2.0) to the more restrictive Business Source License (v1.1). This led to the community forking Terraform into OpenTofu, primarily differing in licensing and community maintenance.
Project vs Product
Like any tool, Terraform can be used in various ways. The key to structuring your IaC configuration lies in whether you’re managing a Project or a Product:
- Project:
- Temporary
- Deliverable-focused
- Less adaptable
- Product:
- Ongoing
- Value-driven
- Adaptable
For example, building a house is a project with a blueprint, materials, and a deadline. Maintaining and renovating the house over time is akin to managing a product.
In IaC terms:
- Projects:
- Provisioning and Configuration: Quickly and consistently spin up resources using building blocks.
- Repeatability and Consistency: Configure environments identically, allowing frequent teardown and rebuild.
- Products:
- Management and Maintenance: Ongoing management and maintenance of launched infrastructure.
- Scalability and Automation: Automatic scaling of infrastructure based on product demands.
Understanding whether you’re working on a project or a product helps guide your IaC strategy. Let’s explore how to optimize Terraform usage accordingly.
Optimizing Terraform Usage
Use Cases and Tips
Variables
Starting with a single main.tf file is fine initially, but as complexity grows, separating concerns becomes crucial for manageability:
- variables.tf: Declaration of variables
- outputs.tf: Outputs from resources
- provider.tf: Provider configurations
This leaves main.tf for module calls, local variables, and data sources. Avoid hardcoding variables; instead, store and fetch them from data sources to maintain flexibility.
Remote State
Initially, storing the state locally is acceptable for experimentation. However, with multiple collaborators, centralizing the state is essential. Use a backend with locking mechanisms to avoid conflicts during simultaneous state changes. Supported remote state backends include:
- Alibaba Cloud
- Amazon Route53
- Amazon S3
- Amazon SSM Parameter Store
- Azure DNS
- Google Cloud DNS
- Google Cloud Storage
- Consul
- Kubernetes (ConfigMap)
- OCI Object Storage
For more information, visit the Terraform remote state documentation.
Workspaces
Terraform workspaces manage multiple deployments of the same infrastructure code with different configurations on the same remote state backend. Workspaces isolate the state per deployment, allowing for isolated testing and reduced code duplication. However, workspaces are not ideal for:
- Access control: For separate configurations, credentials, and backend storage, use separate Terraform configurations.
- Managing complex systems with distinct architectural components.
- Debugging across environments, which can be challenging. Workspaces suit managing similar infrastructure with variations for different environments (e.g., multiple customers using the same product with distinct configurations). For mixing projects and products or complex infrastructure, prefer using modules.
Modules
Instead of workspaces, use reusable modules to represent common elements, and instantiate each instance in a separate configuration within a different backend. For more details, see the Terraform workspaces alternatives.
Managing Dynamic Resources
Dynamic blocks is a feature in Terraform that allows for reusable and dynamic configurations, reducing redundancy and improving maintainability. They act like loops, creating multiple nested blocks based on a list or map.
Benefits of Dynamic Blocks
- Reduced redundancy: Avoid repetitive configuration.
- Improved maintainability: Easier to read and modify code.
- Dynamic configuration: Create configurations based on variables or data sources.
Example Use Cases:
- Creating multiple web servers with different configurations.
- Defining security groups with varying rules for different environments.
- Configuring virtual machines with settings from an external data source.
Example:
hcl
resource "aws_instance" "web_server" {
for_each = {
web1 = {
name = "webserver-1"
ami = "ami-0123456789abcdef0"
instance_type = "t2.micro"
}
web2 = {
name = "webserver-2"
ami = "ami-fedcba0987654321"
instance_type = "t2.medium"
}
}
tags = {
Name = format("%s", each.key)
}
source_security_group_id = aws_security_group.web_server[each.key].id
}
resource "aws_security_group" "web_server" {
for_each = var.web_server_tags
name = each.value.Name
description = format("Security group for web server %s", each.value.Name)
}
variable "web_server_tags" {
type = map(object({
Name = string
}))
}
Tips for Using Dynamic Blocks:
- Use them strategically: Avoid overuse; prioritize clarity. Direct configuration might be preferable for simplicity.
- Maintain readability: Use descriptive iterator names and validate data with Terraform’s validation features.
- Add comments: Explain complex logic within dynamic blocks.
For complex configurations, consider using nested blocks cautiously to avoid excessive nesting, and explore alternative approaches such as modules or external data sources, which may be better suited for handling very complex logic.
Compatibility with Providers
As OpenTofu is a young fork of Terraform, existing providers should work seamlessly. However, future changes by HashiCorp might introduce incompatibilities. Providers are typically maintained by:
- HashiCorp: Official providers for popular platforms.
- HashiCorp Technology Partners: Companies partnering with HashiCorp to ensure quality.
- Terraform/OpenTofu Community: Maintains and updates various providers.
The split between official Terraform providers and those maintained by the OpenTofu community may grow, but those committed to OpenTofu will likely ensure their tools remain updated and functional.
Conclusion
When structuring IaC code, consider whether you’re managing a Product or a Project. Use workspaces for products with multiple instances but different configurations. For more complex scenarios, leverage common modules. Dynamic blocks keep your code concise and adaptable.