The challenge
Coordinating four clouds from one configuration is genuinely tricky. Terraform forbids depends_on, count, and for_each on modules that carry their own provider blocks, and firing concurrent API calls across four providers invites intermittent failures.
Our approach
We use module composition: one root configuration composes four independently written single-cloud child modules via relative source paths. Each child owns its provider configuration, while the root declares all four providers so a single init installs them without duplication. We serialize the whole run with -parallelism=1, so exactly one cloud API operation executes at a time across the entire graph — eliminating cross-cloud races without hand-written dependencies.
Technical specifics
- Four VMs, one per cloud: AWS t3.micro (Amazon Linux 2023), Azure Spot Standard_B2ats_v2 (Ubuntu 24.04), GCP e2-micro (Ubuntu 24.04), OCI VM.Standard.E2.1.Micro (Ubuntu 24.04).
- No secrets in the repo — only account-scoping ids (project, compartment, subscription) in a gitignored tfvars.
- Outputs are public_ips and ssh_commands maps keyed by cloud, plus a helper script that queries all four cloud CLIs.
- Auth spans an AWS CLI profile, az login, GCP ADC, and the OCI config profile.
- Apply and destroy both run with -parallelism=1.
Example configuration
The root declares every provider and composes the four single-cloud modules; -parallelism=1 serializes the whole graph.
module "aws" { source = "../terraform-aws" name = var.name public_key_path = var.public_key_path }
module "azure" { source = "../terraform-azure" name = var.name public_key_path = var.public_key_path }
module "gcp" { source = "../terraform-gcp" name = var.name project_id = var.gcp_project_id }
module "oci" { source = "../terraform-oci" name = var.name compartment_id = var.oci_compartment_id }
output "ssh_commands" {
value = { aws = module.aws.ssh_command, azure = module.azure.ssh_command,
gcp = module.gcp.ssh_command, oci = module.oci.ssh_command }
}terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
google = { source = "hashicorp/google", version = "~> 6.0" }
oci = { source = "oracle/oci", version = "~> 6.0" }
}
}
# terraform apply -parallelism=1 # one cloud API op at a time — no races
# terraform destroy -parallelism=1Outcome
A single reproducible configuration stands up and tears down four VMs across four clouds with no race conditions and no explicit dependency chaining — at near-zero cost, with ready-to-use SSH commands as output.