Skip to content

tractus-x-umbrella-iac

Infrastructure as Code for Tractus-X Umbrella, managed with OpenTofu + Terragrunt. Modular, multi-cloud- and multi-stage-ready, with a chained CI/CD pipeline that runs only the affected stacks and promotes changes through stages with a manual gate.

The whole pipeline uses the tofu binary: every terragrunt.hcl sets terraform_binary = "tofu" and providers come from the OpenTofu registry.

Structure

iac/
|-- modules/<cloud>/          # Reusable modules
|   |-- label/                # Name generator (Azure convention)
|   |-- resource-group/       # Resource group
|   |-- storage-account/      # Storage account
|   |-- storage-container/    # Blob container
|   |-- remote-state/         # Composition: resource-group + storage-account + storage-container
|   |-- networking/           # Network, subnet, security group
|   |-- identity/             # Managed identity
|   |-- dns/                  # DNS zone
|   `-- aks/                  # AKS: system + workloads pools, autoscaler
|-- bootstrap/<cloud>/<stage>/  # State backend bootstrap (run once, local backend)
`-- live/<cloud>/<stage>/       # App Terragrunt stacks (one state per folder)
    |-- networking/
    |-- identity/
    |-- dns/
    `-- aks/                  # depends on networking + identity

Resource names are generated by the label module from project + stage + region (in env.hcl) - nothing is hardcoded.

Prerequisites

Install locally (with your tool manager of choice, e.g. asdf / mise, or manually):

Tool Version
OpenTofu 1.9.0
Terragrunt 0.69.0
TFLint 0.52.0
Trivy latest
Checkov latest

CI pins its own versions in each workflow's env: block - keep them in sync.

make tools            # prints installed tofu / terragrunt / tflint versions

# Authenticate to your cloud and export the credentials the provider needs
# (e.g. the subscription/account id):
export ARM_SUBSCRIPTION_ID="<SUBSCRIPTION_ID>"

Bootstrap (one-time)

iac/bootstrap/<cloud>/<stage> creates the resource group + state Storage Account + container (composing the resource-group, storage-account, storage-container modules) on a local backend. It lives outside live/ and is a one-time, run-locally step (its local state is not persisted in CI). Everything else uses the remote backend it creates.

export ARM_CLIENT_ID=... ARM_CLIENT_SECRET=... ARM_TENANT_ID=... ARM_SUBSCRIPTION_ID=...
make bootstrap        # apply iac/bootstrap/azure/dev (once, locally)

After bootstrap, the app stacks (networking, identity, dns, aks) reference the resource group by name (generated by label), not via a state dependency - so CI never touches the bootstrap. Since the bootstrap lives outside live/, the CI run-all over live/ only sees the app stacks.

Commands (Makefile)

make help                       # list targets
make fmt-check lint             # formatting + tflint
make bootstrap                  # one-time: RG + state storage (local backend)
make plan-all                   # plan the app stacks
make UNIT=aks plan              # plan a single stack
make apply-all                  # apply the app stacks
make trivy checkov              # security + compliance

CI/CD

Three workflows in .github/workflows/, chained with workflow_run (Azure service-principal). Only the affected cloud/stage combos run, and apply promotes test -> dev -> prod with a manual gate:

PR        -> detect -> validate -> test                                           (plan comments on PR)
push main -> detect -> validate -> test -> plan -> apply-test -> apply-dev -> apply-prod (manual approval)
  1. iac-validate.yml: detect (affected combos) -> validate (make fmt-check + make lint + Trivy + Checkov + make validate-all) -> test (make test-all).
  2. iac-plan.yml: runs make plan-all for the affected combos; on PRs comments the plan.
  3. iac-apply.yml: apply-test, then apply-dev, then apply-prod (needs: apply-dev, environment: prod -> manual approval). Only on main.

The CI calls the same make targets used locally (single source of truth); only Trivy and Checkov run as dedicated marketplace actions. Full details (affected detection, promotion, multi-cloud) in .github/workflows/README.md.

  • New cloud/stage combos light up automatically once their iac/live/<cloud>/<stage>/ stacks are created - no workflow edits needed for a new stage of an existing cloud.
  • Set up Environments test, dev and prod (Settings -> Environments); add required reviewers to prod for the manual gate.
  • workflow_run workflows run with the definition from the default branch (main).

Design decisions

  • terraform_binary = "tofu" in the root and in the bootstrap stack (which does not include the root).
  • Naming via the label module - every resource name is generated from project + stage + region. The state backend names (RG + Storage Account) are reproduced in the root with the same convention, since the Terragrunt remote_state block cannot call a Terraform module.
  • Resource group create-or-reuse: create_resource_group + resource_group_name in env.hcl let you create a new RG or reuse an existing one (e.g. when the SP only has rights on that RG).
  • Backend bootstrap outside live/ (iac/bootstrap/, local backend), run once - see Bootstrap.
  • Identity -> AKS: the cluster consumes the identity module's managed identity and is granted the network role on the subnet (CNI requirement).
  • Tests run as the CI test job (make test-all, one tofu test per module) - not as apply hooks, to keep module tests isolated from live inputs.

About

Infrastructure as Code for the Tractus-X Umbrella Helm Chart

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages