Infrastructure as Code (IaC): Terraform, Ansible and Beyond
Manually provisioning servers and configuring networks through point-and-click consoles is slow, error-prone, and impossible to audit at scale. Infrastructure as Code (IaC) replaces those manual steps with version-controlled configuration files that describe your desired state, letting you spin up, modify, and tear down environments repeatably and reliably. This guide covers the core IaC concepts, compares the leading tools, and explains why MSPs and resellers should adopt IaC practices today.
What Is Infrastructure as Code?
Infrastructure as Code is the practice of defining and managing computing infrastructure — servers, networks, load balancers, databases, DNS records, and more — through machine-readable definition files rather than interactive configuration tools or manual processes. Just as software developers write application code that is versioned, tested, and reviewed, operations engineers write infrastructure code that goes through the same disciplined lifecycle. The result is infrastructure that can be reproduced identically across development, staging, and production environments with a single command.
For Australian IT resellers and MSPs, IaC is transformative because it removes the human variability that causes configuration drift — the gradual divergence between what you think your environment looks like and what it actually is. When every change is codified and committed to a repository, you gain a complete audit trail, the ability to roll back to any previous state, and the confidence that a disaster-recovery rebuild will produce an identical environment. This is especially critical for organisations operating under Australian privacy and data-sovereignty requirements where infrastructure consistency directly supports compliance obligations.
Declarative vs Imperative Approaches
IaC tools broadly fall into two paradigms: declarative and imperative. A declarative tool asks you to describe the desired end state — for example, "I want three virtual machines running Ubuntu 22.04 in the Sydney region with 8 GB of RAM each" — and the tool determines what steps are needed to achieve that state. If two VMs already exist, it creates one more. If all three exist but one has the wrong image, it recreates that single instance. Terraform and AWS CloudFormation are prime examples of declarative tools. The advantage is idempotency: you can run the same configuration repeatedly and always converge on the same result without unintended side effects.
An imperative tool, by contrast, tells the system how to achieve a result through a sequence of ordered steps — "create a VM, then install Nginx, then copy this config file, then restart the service." Ansible playbooks, while they support idempotent modules, are fundamentally imperative in their execution model: tasks run top-to-bottom in the order you specify. Shell scripts and many custom automation tools also fall into this camp. Imperative approaches can be more intuitive for procedural thinkers but require more care to ensure that running the script twice does not create duplicate resources or break an already-configured system.
Terraform: The Declarative Provisioning Standard
HashiCorp Terraform has become the de facto standard for multi-cloud infrastructure provisioning. Written in Go and using its own configuration language called HCL (HashiCorp Configuration Language), Terraform lets you define resources across AWS, Azure, GCP, VMware, and hundreds of other providers in a single, unified workflow. When you run terraform plan, the tool compares your desired state against a state file that records what was previously deployed, then calculates a precise execution plan showing which resources will be created, modified, or destroyed. Running terraform apply executes that plan. This plan-and-apply cycle gives teams visibility and control before any change touches live infrastructure.
Terraform state management is both a strength and a responsibility. The state file is the single source of truth mapping your configuration to real-world resources. For teams, storing state in a remote backend — such as an S3 bucket with DynamoDB locking, Azure Blob Storage, or Terraform Cloud — is essential to prevent conflicts when multiple engineers work on the same infrastructure. State files can contain sensitive data (passwords, access keys), so encryption at rest and strict access controls are non-negotiable. Australian MSPs managing infrastructure for multiple clients should use separate state files and backends per client to maintain isolation and meet privacy requirements.
Ansible: Agentless Configuration Management
Red Hat Ansible takes a fundamentally different approach. Rather than provisioning cloud resources through provider APIs, Ansible excels at configuring the operating system and software layer of servers that already exist. It is agentless — it connects to target machines over SSH (Linux) or WinRM (Windows) and executes modules that enforce the desired state of packages, files, services, users, and more. Playbooks are written in YAML, making them highly readable even for engineers who are not software developers. Roles and collections provide reusability, and Ansible Galaxy offers a community library of pre-built roles for common tasks like hardening CIS benchmarks or deploying monitoring agents.
For MSPs, Ansible is particularly powerful for day-two operations — patching, compliance remediation, user provisioning, and application deployment across fleets of servers. Because it requires no agent on the target hosts, it is straightforward to adopt without modifying client environments. Ansible Automation Platform (the commercial Red Hat product) adds a web UI, role-based access control, credential vaults, and job scheduling, making it suitable for teams that need governance around who can run what against which inventory. The open-source community edition remains free and is more than sufficient for smaller operations or proof-of-concept deployments.
Pulumi: Infrastructure as Real Code
Pulumi challenges the notion that infrastructure must be defined in domain-specific languages. Instead, it lets you write infrastructure definitions in general-purpose programming languages — Python, TypeScript, Go, C#, and Java. This means you can use loops, conditionals, functions, classes, and the full ecosystem of libraries available in your chosen language. For teams with strong software engineering backgrounds, Pulumi feels natural: you get IDE autocompletion, type checking, unit testing with standard frameworks, and packaging via pip, npm, or NuGet. The trade-off is a steeper learning curve for operations engineers who are more comfortable with YAML or HCL than with imperative programming constructs.
Terraform vs Ansible vs Pulumi at a Glance
| Feature | Terraform | Ansible | Pulumi |
|---|---|---|---|
| Primary purpose | Cloud resource provisioning | Configuration management | Cloud resource provisioning |
| Language | HCL (domain-specific) | YAML playbooks | Python, TypeScript, Go, C#, Java |
| Paradigm | Declarative | Imperative (with idempotent modules) | Declarative |
| State management | State file (local or remote) | No state file | State file (Pulumi Cloud or self-managed) |
| Agent required | No | No (agentless via SSH/WinRM) | No |
| Multi-cloud support | Excellent (700+ providers) | Good (via modules) | Excellent |
| Licensing | BSL 1.1 (OpenTofu fork is MPL 2.0) | GPL (community) / subscription (Platform) | Apache 2.0 (engine) / SaaS (Pulumi Cloud) |
Version Control for Infrastructure
The "as Code" part of IaC only delivers its full value when infrastructure definitions live in a version control system like Git. Every change should be made through a branch, reviewed via a pull request, and merged only after automated checks pass. This workflow — sometimes called GitOps when applied to Kubernetes — ensures that the Git repository is the single source of truth for what your infrastructure should look like. If an engineer makes a manual change outside of the code, the next pipeline run will detect and correct the drift, enforcing consistency.
Repository structure matters as your IaC codebase grows. A common pattern is to separate modules (reusable building blocks like a VPC module or a database module) from environments (dev, staging, production) that compose those modules with environment-specific variables. Terraform workspaces or directory-based separation both work; the key is consistency. MSPs serving multiple clients should consider a monorepo per client or a shared-modules repo with per-client environment repos, depending on the degree of customisation required. Tagging releases of shared modules ensures that upgrading one client does not inadvertently affect another.
Benefits of IaC for MSPs and Resellers
Pros
- Repeatability — deploy identical environments for every client without manual steps
- Auditability — every change is tracked in Git with author, timestamp, and rationale
- Speed — new environments can be provisioned in minutes rather than days
- Disaster recovery — rebuild production from code after a catastrophic failure
- Consistency — eliminates configuration drift and "works on my machine" problems
- Scalability — manage hundreds of client environments with the same codebase
Cons
- Learning curve — engineers must learn new tools and adopt code-review discipline
- State management complexity — Terraform state files require careful handling
- Initial investment — converting existing manual infrastructure to code takes time
- Tooling fragmentation — choosing between competing tools can cause analysis paralysis
Getting Started: A Practical Roadmap
If your team has never used IaC, start small. Pick a non-critical internal project — perhaps a development environment or a lab network — and define it in Terraform. Store the code in Git, set up a basic CI pipeline that runs terraform plan on every pull request, and require peer review before merging. This builds confidence and muscle memory without risking production workloads. Once the team is comfortable, graduate to managing staging and then production infrastructure. Layer in Ansible for post-provisioning configuration, and establish a module library that encapsulates your organisation's best practices — secure VPC layouts, hardened OS baselines, standard monitoring agent deployment — so that every new project inherits those standards automatically.
Infrastructure as Code is not about replacing sysadmins with developers. It is about giving operations teams the same tools — version control, peer review, automated testing — that have made software delivery faster and more reliable for decades.