Using Terraform to manage multi-cloud infrastructure
A multi-cloud estate can look impressive on a diagram and still be painful to operate. Terraform helps by turning provider APIs into declarative configuration, reviewable plans, and repeatable modules, but it cannot repair unclear ownership, incompatible service models, or weak recovery design on its own.
The useful goal is not to place every workload in every cloud. It is to make deliberate choices about portability, resilience, data residency, and operating cost. A small number of well-governed platforms is often safer than duplicated complexity, especially when teams support AWS, Microsoft Azure, and Google Cloud alongside established on-premises systems.
Australian organisations face concrete trade-offs. Sydney and Melbourne are major cloud hubs, while Brisbane users must balance latency, service availability, and connectivity. Privacy obligations also belong in the design: where relevant, the Privacy Act 1988, Australian Privacy Principles, and Notifiable Data Breaches scheme should shape logging, access, and recovery decisions.
The local market combines global hyperscalers with established managed-service providers and resellers, so a common engineering standard has practical value. Engineers can work from one Terraform workflow while each provider retains its own identity, compliance, and failure characteristics. The aim is a modest, observable foundation that expands only when a real business case supports another platform.
Define the purpose of a multi-cloud estate
Start by naming the outcomes that justify multiple clouds: access to a particular capability, contractual separation, geographic resilience, regulatory isolation, or reduced dependency on one vendor. Multi-cloud is not itself an outcome. Without a threshold, teams can add providers faster than they can learn their consoles, billing models, quotas, and incident procedures.
Build an inventory of applications, data classifications, dependencies, recovery objectives, and current cloud placement. Keep workloads where they have a clear purpose. A stateless service may run in two regions for availability, while a regulated dataset might remain in one jurisdiction; duplicating both would add expense without improving resilience.
Then define provider boundaries. For each workload, document who owns identity, networking, secrets, backups, monitoring, and cost control. Include an exit path and the maximum tolerable outage. These boundaries are more valuable than a blanket policy claiming that every application is portable, because portability is often constrained by proprietary databases, managed queues, or specialist hardware.
Model shared controls without erasing differences
Organise the Terraform code around business capabilities rather than provider resource names. A sensible layout can contain modules for identity, compute, storage, networking, and observability, plus separate environment and provider configuration. Shared policies then enforce naming, tagging, encryption, logging, and approved regions while each provider adapter handles its own API and credential flow.
Do not force unlike resources into a false abstraction. Object-storage semantics, key management, subnet models, and DNS vary enough that a common module may need carefully documented exceptions. Version provider constraints, publish module interfaces, and test each provider independently. This keeps a single workflow without pretending that AWS, Azure, and Google Cloud expose identical behaviour.
Small properties still benefit from deliberate DNS and lifecycle management. Before altering records for a site such as Vegan Danielle, capture the current zone, ownership details, TTLs, and fallback path in version control; apply the smallest possible change and verify propagation. The same discipline scales to production domains and cross-cloud failover records.
Keep state separated by environment and stored in an encrypted remote backend with locking. Never commit state files because they can contain sensitive values and provider metadata. Restrict access to the delivery pipeline and break-glass administrators, enable versioning, and rehearse state recovery before relying on it during an incident.
Make changes reviewable and recoverable
Run formatting, validation, security scanning, and a saved Terraform plan in CI for every pull request. Require peer review for production and apply only the reviewed artefact through a protected identity. Policy checks can reject public storage, unapproved regions, missing tags, or encryption settings before the plan reaches an operator.
Some changes also carry obligations outside the cloud console. A Brisbane event involving a casino night may need approval before it can proceed, which makes Queensland permit guidance a useful example of treating permissions as dependencies rather than administrative afterthoughts. Record the licence, owner, expiry, and renewal task alongside the infrastructure that supports the event.
Design rollback before rollout. Many cloud resources cannot be undone safely, so prefer versioned or immutable replacement, retain old instances until acceptance tests pass, and test database restoration rather than assuming snapshots work. A failed migration should have a stated trigger, an owner, and a rehearsed decision path instead of relying on an engineer improvising during the incident.
Monitor drift, cost, and service health
Monitoring should answer whether the declared platform is still true. Schedule read-only plans to reveal drift, then route meaningful differences to the owning team instead of automatically overwriting them. Track provider spend, forecast consumption, and attach service and environment metadata so unused resources can be traced. Dashboards must cover both provider-native signals and the cross-cloud view that local teams actually support.
Certificates are a common source of preventable outages, especially when one person owns renewal dates. A practical implementation of automated certificate renewal can use Let’s Encrypt and Certbot, but the surrounding workflow still needs alerting, deployment hooks, and rollback. Keep private keys in a secret store and confirm that renewal succeeds in every environment.
Local operating conditions deserve explicit thresholds. Australian support teams commonly hand work between Brisbane, Sydney, and Melbourne, whose state daylight-saving schedules do not all change together; alerts should carry a UTC timestamp as well as local time. For systems covered by Australian privacy law, preserve access and incident records that support assessment of a notifiable breach. Align broader controls with the ACSC Essential Eight where appropriate.
Build a pragmatic adoption sequence
An incremental sequence reduces the risk of a grand rebuild. Choose a low-risk service, document its current state, introduce a small module, and prove that planning, application, monitoring, and recovery all work before moving the next workload. The same standard should apply to a local managed-service provider: clear scopes, written handovers, and evidence that responsibilities do not disappear between client and supplier.
- Set a measurable provider-entry threshold, such as a required capability, resilience target, or contractual need, and record why another platform is justified.
- Use one remote state backend pattern per environment, with encryption, locking, versioning, restricted access, and a documented recovery procedure.
- Keep shared standards separate from provider adapters so policy changes do not require rewriting every resource definition.
- Require reviewed plans for production, retain audit evidence, and separate permissions for planning, approval, and deployment.
- Test restoration and failover regularly, including provider outages, failed DNS changes, expired credentials, and inaccessible state.
Create the repository for one non-critical service this week, connect it to an encrypted remote backend, and produce its first reviewed plan. That small deliverable will expose missing ownership, unsupported assumptions, and recovery gaps while the change remains cheap to adjust. Publish the resulting standard, then use it to evaluate the next provider instead of expanding the estate by habit.
Karl Katzke