Skip to content

IaC Accelerator

The IaC Accelerator is a complete, working example of an infrastructure-as-code project that uses the Managed Templates modules. It is meant for teams that are new to the library or to infrastructure as code. You copy it into your own repository and adapt it. It lowers the entry barrier and gives you a structure, a deployment pipeline and automated updates of your module versions.

A reference project, not a product

The accelerator shows a recommended approach. Specialised cases are not its goal: adapt the files to your needs. The names, pool, service connections, subscriptions and registry in the files are placeholders that you must replace. The maintaining team tests and supports the accelerator itself, not the changes you make to your copy.

What it contains

Part Terraform Bicep
Project structure Root module per environment, a shared main module, local modules One main.bicep, one parameter file per environment, local modules
Deployment pipeline Plan stage, then an apply stage that waits for approval An optional what-if stage, then a deploy stage that waits for approval
Automated updates Renovate configuration and pipeline, for Azure DevOps or GitHub Actions The same
Module source git:: source with a version tag Container registry reference with a version

What it deploys

The example workload consists of the following resources. It is a spread of modules, not a recommended architecture.

Resource Module
Resource group Plain resource, named with the Azure naming module (Terraform)
User-assigned identity user_assigned_identity
Log Analytics workspace log_analytics_workspace
Key Vault, with an encryption key key_vault
Storage account, encrypted with the key storage_account
App Service plan and a Linux web app serverfarm, app_service_site_linux
Windows virtual machine virtual_machine_windows
SQL server sql_server
Recovery Services vault with a VM backup policy Local code in the accelerator (rsv), not a library module

The example connects to an existing spoke: it looks up the virtual network and the subnet, and places the private endpoints there. The default names follow the naming convention of the spoke canvas (Naming and tags): change them when your spoke uses other names. This means the accelerator works best in a spoke that the platform has created for you (What you get).

Structure

Terraform

environments/          One root module per environment (dev, prod). Entry point, providers, backend, variables.
main/                  Infrastructure for all environments: resources, module calls, data sources.
modules/               Project-specific modules.
pipelines/             terraform.yaml, templates for plan and apply, Renovate pipeline and workflow.
renovate.json          Example Renovate configuration.

Each directory in environments/ is a root module that calls the shared main module with environment-specific values. You can add environments by adding directories. The structure also lets you deploy from a workstation, over a VPN when resources have public access disabled. Decide whether you set the Terraform version constraints in main/terraform.tf or in each environment.

Bicep

main.bicep             The infrastructure, at subscription scope.
dev.bicepparam         Parameters of the dev environment.
prod.bicepparam        Parameters of the prod environment.
modules/               Local modules: the backup vault, and a module that looks up the spoke network.
pipelines/             bicep.yaml, a single-environment template, Renovate pipeline and workflow.
renovate.json          Example Renovate configuration.

Keep shared resources, naming and outputs in main.bicep, and environment-specific values in the parameter files.

Use it

  1. Copy the content of iac_accelerator/terraform/ or iac_accelerator/bicep/ of the library repository to your repository.
  2. Review and adjust all files. Search for the TODO comments, and for the repository address (Terraform) or the registry address (Bicep) that the files contain as an example. Replace them with yours.
  3. Adjust the pipeline definition to your CI/CD setup: agent pool, service connection names, subscriptions and the version of the tool (Terraform or Bicep).
  4. Create Azure DevOps environments that match your environment names (dev, prod), and add approvers for all of them, so that nothing changes without review of the previous result.
  5. Create service connections at subscription scope.
  6. Make sure the pipeline can read the library: see Give the pipeline access for Terraform and Give a Bicep pipeline access for Bicep. The Terraform pipeline already contains the git steps.
  7. Commit, push, add the pipeline file as a pipeline in Azure DevOps and run it.

Pass values from a variable group

Terraform Bicep
How List the variable group in the variables block, and map values with the envs parameter, for example TF_VAR_my_variable: $(variable-group-variable-name) Use variableGroupName for the group, secretToEnvMapping for secrets and bicepAdditionalParams for plain values
Secrets Mark them as secret in the group and as sensitive in Terraform Mark them as secret in the group, and map them with secretToEnvMapping so that they are not logged

Values that come from outside make it harder to run the code locally: provide them another way then (environment variables or a .tfvars file that is not committed).

The pipelines

Terraform pipeline

The pipeline has the parameters environment (dev or prod) and operation (apply or destroy). The template runs two stages: a plan stage, and a deploy stage that only runs when the plan contains changes. The deploy stage uses an Azure DevOps environment, so the approvers you configure must approve it. The apply uses the saved plan, and after an apply a refresh-only run stores API side effects in the state.

Bicep pipeline

The pipeline has stages for dev and prod, where prod depends on dev. Each stage can run a what-if first (the parameter runWhatIf, off by default, because the output can be noisy), then deploys with az deployment sub create. The Bicep version is installed from a pipeline variable.

Keep modules up to date

The accelerator includes a Renovate setup. Renovate checks the versions of the modules you use (and of the Terraform providers) and opens a pull request when a newer version exists. It reads the Bicep registry references and the Terraform git:: sources with tags of the form terraform/<module>/<version>, scoped per module, so that a module never gets a version from the tags of another module. Updates are grouped by update type.

Set it up as follows:

  1. Keep the pipeline or workflow that matches your platform (Azure DevOps or GitHub Actions) and delete the other.
  2. Replace the placeholders in renovate.json and in the pipeline (the registry, the repository, the agent pool).
  3. Give Renovate permission to create branches and pull requests. In Azure DevOps this is Contribute and Contribute to pull requests for the build identity of the pipeline. In GitHub Actions you need a GitHub App, because pull requests that the default token creates do not start other workflows.
  4. For Bicep, give the pipeline access to the registry through a service connection that uses workload identity federation. For Terraform modules in another repository, grant read access there too.
  5. Run it once with dryRun set to true. The default is false, and the weekly schedule runs it for real. Check that all files with references appear in the log and that no dependency has a skipReason.
  6. Then run it without dry-run. After the first real run, check that a pull request only changes the version string.

Read the changelog before you merge

A Renovate pull request changes the version, not your code. Check the changelog and the upgrade notes for major versions, and let your normal pipeline test the change in dev first.