Tags: Modeling · Automation · Self-host Substrate: bare Terraform + GitHub Actions (greenfield, one stack per entity)
The canonical Terrantula pattern for greenfield multi-tenant SaaS infrastructure. If you're starting a fresh IaC repo and want Terrantula to drive it from day one, this is the layout. It exercises the full cascade: one command creates the entity graph and opens the right PRs in the right dependency order.
Every customer needs a dedicated AWS sub-account, an Argo CD project, a cluster binding, and the
tenant control-plane resources that compose all three. Each lives in its own Terraform stack with
its own state file, and the Tenant stack reads the upstreams via terraform_remote_state — so
it must apply after them.
One OnboardTenant command drives the whole cascade:
create-entity operation creates the Tenant entity (pending).createEntity rules create three more entities — AWSAccount, ArgoProject,
ClusterBinding — plus three relationships from the tenant to each. (4 entities, 3 relationships.)EntityType declares its applier, so four Apply Actions auto-fire: ApplyAWSAccount,
ApplyArgoProject, ApplyClusterBinding, and ApplyTenant.Action.dependsOn gates ordering. The three upstream applies fire immediately, each opening a
PR with one entity's Terraform. ApplyTenant depends on all three; it inspects the graph, sees
the upstreams aren't done, and transitions to blocked.postMergeDispatch fires a repository_dispatch event; one
entity-generic workflow runs terraform apply in that entity's directory and calls back.ApplyTenant, which
opens the tenant PR. Merge → dispatch → apply → callback → Tenant-acme becomes active.One command, the right four PRs in the right order, no human orchestration. Each workflow runs
terraform apply; Terrantula opens the PRs and never applies.
run-demo.sh boots a local stack, applies the blueprint, fires OnboardTenant, and asserts the
cascade graph. Without a real GitHub token the upstream PR opens fail with a 401 (expected); the
cascade-graph assertions still pass — 4 entities, 3 relationships, 4 Apply ActionRuns, and
ApplyTenant reaching blocked.
With real PRs against a fork of customer-iac-repo/:
The import-fixtures/ directory demonstrates how terrantula import-terraform
handles an existing cluster + tenant fleet where the tenant stacks reference
the cluster stack via terraform_remote_state.
Running the importer against both statefiles surfaces the cross-stack placement
join and suggests a runs_on derived relationship — without ever touching
Terraform or writing any entity properties. The suggestion is commented YAML
the operator can inspect, rename, and promote to the blueprint.
Key behaviors the fixtures demonstrate:
cluster
property is captured from the kubernetes_namespace resource's attribute.
No relationship is created automatically.tf_source_stack provenance label. When a tenant's cluster value
matches a terraform_remote_state output, the entity is labelled
tf_source_stack: clusters — tracing the cross-stack origin.(cross-stack via clusters) note in the suggestion. The importer
annotates each suggested rule whose join property is cross-stack-sourced.tenant_cluster and only hints at containment. The operator's
suggest_relationships.overrides in cross-stack-import.yaml is what
promotes it to runs_on with containment: true and many-to-one —
domain choices that belong to the operator, not the importer.--ci vs interactive. In --ci mode (or any non-TTY context) suggestions
are emitted as commented YAML. In a terminal, the importer prompts to accept
or reject each suggestion interactively.The cross-stack import section of run-demo.sh runs fully offline — no live
server, no API call. See the demo's
README.md
for the full walk-through including the exact importer output.
| File | What it is |
|---|---|
run-demo.sh | The end-to-end runner (local stack + cascade-graph assertions + cross-stack import section). |
terrantula/blueprint.yaml | 4 EntityTypes + 3 RelationshipTypes + 4 Apply + 4 Deprovision actions + OnboardTenant with cascadeRules. |
customer-iac-repo/README.md | The directory + workflow conventions the customer's repo follows. |
customer-iac-repo/.github/workflows/terrantula-entity-apply.yml | The entity-generic terraform apply workflow (one for the whole fleet). |
customer-iac-repo/infra/_modules/ | Reusable per-entity-type modules (aws-account, argo-project, cluster-binding, tenant). |
import-fixtures/cluster.tfstate | Cluster stack fixture: two argocd_cluster resources + outputs. |
import-fixtures/tenant.tfstate | Tenant stack fixture: kubernetes_namespace resources referencing cluster outputs via terraform_remote_state. |
import-fixtures/cross-stack-import.yaml | Mapping config with suggest_relationships.overrides (operator's domain choices). |
applier, dependsOn, and cascade.