Important
While this page describes and summarizes important aspects of the composition of AVM modules, it may not reference All of the shared and language specific requirements.
Therefore, this guide MUST be used in conjunction with the Terraform specifications. ALL AVM modules (Resource and Pattern modules) MUST meet the respective requirements described in these specifications!
Important
Before jumping on implementing your contribution, please review the AVM Module specifications, in particular the Terraform specification pages, to make sure your contribution complies with the AVM module’s design and principles.
Repositories
Each Terraform AVM module will have its own GitHub Repository in the Azure
GitHub Organization as per SNFR19.
This repo will be created by the Module Owners and the AVM Core team collaboratively, including the configuration of permissions as per SNFR9
Directory and File Structure
Below is the directory and file structure expected for each AVM Terraform repository/module.
See template repo here.
tests/
- (for unit tests and additional tests if required - e.g. tflint etc.)unit/
- (optional, may use further sub-directories if required)
modules/
- (for sub-modules only if used)examples/
- (all examples must deploy without successfully without requiring input - these are customer facing)<at least one folder>
- (at least one example that uses the variable defaults minimum/required parameters/variables only)<other folders for examples as required>
/...
- (Module files that live in the root of module directory)_header.md
- (required for documentation generation)_footer.md
- (required for documentation generation)main.tf
locals.tf
variables.tf
outputs.tf
terraform.tf
README.md
(autogenerated)main.resource1.tf
(If a larger module you may chose to use dot notation for each resource)locals.resource1.tf
Directory and File Structure
/ root
│
├───.github/
│ ├───actions/
│ │ ├───avmfix/
│ │ │ └───action.yml
│ │ ├───docs-check/
│ │ │ └───action.yml
│ │ ├───e2e-getexamples/
│ │ │ └───action.yml
│ │ ├───e2e-testexamples/
│ │ │ └───action.yml
│ │ ├───linting/
│ │ │ └───action.yml
│ │ └───version-check/
│ │ └───action.yml
│ ├───policies/
│ │ ├───avmrequiredfiles.yml
│ │ └───branchprotection.yml
│ ├───workflows/
│ │ ├───e2e.yml
│ │ ├───linting.yml
│ │ └───version-check.yml
│ ├───CODEOWNERS
│ └───dependabot.yml
├───.vscode/
│ ├───extensions.json
│ └───settings.json
├───examples/
│ ├───<example_folder>/
│ │ ├───README.md
│ │ ├───_footer.md
│ │ ├───_header.md
│ │ ├───main.tf
│ │ └───variables.tf
│ ├───.terraform-docs.yml
│ └───README.md
├───modules/
│ └───README.md
├───tests/
│ └───README.md
├───.gitignore
├───.terraform-docs.yml
├───CODE_OF_CONDUCT.md
├───LICENSE
├───Makefile
├───README.md
├───SECURITY.md
├───SUPPORT.md
├───_footer.md
├───_header.md
├───avm
├───avm.bat
├───locals.tf
├───main.privateendpoint.tf
├───main.telemetry.tf
├───main.tf
├───outputs.tf
├───terraform.tf
└───variables.tf
Code Styling
This section points to conventions to be followed when developing a module.
Casing
Use snake_casing
as per TFNFR3.
Make sure to review all specifications of Category: Inputs/Outputs
within the Terraform specification pages.
Tip
See examples in specifications SNFR14 and TFFR14.
Resources
Resources are primarily leveraged by resource modules to declare the primary resource of the main resource type deployed by the AVM module.
Make sure to review all specifications covering resource properties and usage.
Tip
See examples in specifications SFR1 and RMFR1.
Outputs
Make sure to review all specifications of Category: Inputs/Outputs
within the Terraform specification pages.
Tip
See examples in specification RMFR7 and TFFR2.
Interfaces
Note
This section is only relevant for contributions to resource modules.
To meet RMFR4 and RMFR5 AVM resource modules must leverage consistent interfaces for all the optional features/extension resources supported by the AVM module primary resource.
Please refer to the Terraform Interfaces page.
Telemetry
To meet SFR3 & SFR4.
We use a telemetry provider modtm.
This is a lightweight telemetry provider that sends telemetry data to Azure Application Insights via a HTTP POST front end service.
The telemetry provider is included in the module by default and is enabled by default.
You do not need to change the configuration included in the template repo.
You must make sure to have the modtm
provider in your required_providers
.
The linter will check this for you.
However, inside your terraform.tf
file please make sure you have this entry:
terraform {
required_providers {
# .. other required providers as needed
modtm = {
source = "Azure/modtm"
version = "~> 0.3"
}
}
}
Eventual Consistency
When creating modules, it is important to understand that the Azure Resource Manager (ARM) API is sometimes eventually consistent.
This means that when you create a resource, it may not be available immediately.
A good example of this is data plane role assignments.
When you create such a role assignment, it may take some time for the role assignment to be available.
We can use an optional time_sleep
resource to wait for the role assignment to be available before creating resources that depend on it.
# In variables.tf...
variable "wait_for_rbac_before_foo_operations" {
type: object({
create = optional(string, "30s")
destroy = optional(string, "0s")
})
default = {}
description = <<DESCRIPTION
This variable controls the amount of time to wait before performing foo operations.
It only applies when `var.role_assignments` and `var.foo` are both set.
This is useful when you are creating role assignments on the bar resource and immediately creating foo resources in it.
The default is 30 seconds for create and 0 seconds for destroy.
DESCRIPTION
}
# In main.tf...
resource "time_sleep" "wait_for_rbac_before_foo_operations" {
count = length(var.role_assignments) > 0 && length(var.foo) > 0 ? 1 : 0
depends_on = [
azurerm_role_assignment.this
]
create_duration = var.wait_for_rbac_before_foo_operations.create
destroy_duration = var.wait_for_rbac_before_foo_operations.destroy
# This ensures that the sleep is re-created when the role assignments change.
triggers = {
role_assignments = jsonencode(var.role_assignments)
}
}
resource "azurerm_foo" "this" {
for_each = var.foo
depends_on = [
time_sleep.wait_for_rbac_before_foo_operations
]
# ...
}
High-level contribution flow
---
config:
nodeSpacing: 20
rankSpacing: 20
diagramPadding: 50
padding: 5
flowchart:
wrappingWidth: 300
padding: 5
layout: elk
elk:
mergeEdges: true
nodePlacementStrategy: LINEAR_SEGMENTS
---
flowchart TD
A(1 - Fork the module source repository)
click A "/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#1-fork-the-module-source-repository"
B(2 - Setup your Azure test environment)
click B "/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#2-prepare-your-azure-test-environment"
C(3 - Implement your contribution)
click C "/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#3-implement-your-contribution"
D{4 - Pre-commit<br>checks successful?}
click D "/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#4-run-pre-commit-checks"
E(5 - Create a pull request to the upstream repository)
click E "/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#5-create-a-pull-request-to-the-upstream-repository"
A --> B
B --> C
C --> D
D -->|yes|E
D -->|no|C
GitFlow for contributors
The GitFlow process outlined here depicts and suggests a way of working with Git and GitHub. It serves to synchronize the forked repository with the original upstream repository. It is not a strict requirement to follow this process, but it is highly recommended to do so.
---
config:
logLevel: debug
gitGraph:
rotateCommitLabel: false
---
gitGraph LR:
commit id:"fork"
branch fork/main
checkout fork/main
commit id:"checkout feature" type: HIGHLIGHT
branch feature
checkout feature
commit id:"checkout fix"
branch fix
checkout main
merge feature id: "Pull Request 'Feature'" type: HIGHLIGHT
checkout fix
commit id:"Patch 1"
commit id:"Patch 2"
checkout main
merge fix id: "Pull Request 'Fix'" type: HIGHLIGHT
Tip
When implementing the GitFlow process as described, it is advisable to configure the local clone of your forked repository with an additional remote for the upstream repository. This will allow you to easily synchronize your locally forked repository with the upstream repository. Remember, there is a difference between the forked repository on GitHub and the clone of the forked repository on your local machine.

Note
Each time in the following sections we refer to ‘your xyz’, it is an indicator that you have to change something in your own environment.
Prepare your developer environment
1. Fork the module source repository
Important
Each Terraform AVM module will have its own GitHub repository in the Azure
GitHub Organization as per SNFR19.
This repository will be created by the Module owners and the AVM Core team collaboratively, including the configuration of permissions as per SNFR9
Module contributors are expected to fork the corresponding repository and work on a branch from within their fork, before then creating a Pull Request (PR) back into the source repository’s main
branch.
To do so, simply navigate to your desired repository, select the 'Fork'
button to the top right of the UI, select where the fork should be created (i.e., the owning organization) and finally click ‘Create fork’.
Note
If the module repository you want to contribute to is not yet available, please get in touch with the respective module owner which can be tracked in the Terraform Resource Modules index see PrimaryModuleOwnerGHHandle
column.
Optional: The usage of local source branches
For consistent contributors but also Azure-org members in general it is possible to get invited as collaborator of the module repository which enables you to work on branches instead of forks. To get invited get in touch with the module owner since it’s the module owner’s decision who gets invited as collaborator.
2. Prepare your Azure test environment
AVM performs end-to-end (e2e) test deployments of all modules in Azure for validation. We recommend you to perform a local e2e test deployment of your module before you create a PR to the upstream repository. Especially because the e2e test deployment will be triggered automatically once you create a PR to the upstream repository.
Have/create an Azure Active Directory Service Principal with at least Contributor
& User Access Administrator
permissions on the Management-Group/Subscription you want to test the modules in. You might find the following links useful:
# Linux/MacOs
export ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) # or set <subscription_id>
export ARM_TENANT_ID=$(az account show --query tenantId --output tsv) # or set <tenant_id>
export ARM_CLIENT_ID=<client_id>
export ARM_CLIENT_SECRET=<service_principal_password>
# Windows/Powershell
$env:ARM_SUBSCRIPTION_ID = $(az account show --query id --output tsv) # or set <subscription_id>
$env:ARM_TENANT_ID = $(az account show --query tenantId --output tsv) # or set <tenant_id>
$env:ARM_CLIENT_ID = "<client_id>"
$env:ARM_CLIENT_SECRET = "<service_principal_password>"
Change to the root of your module repository and run ./avm docscheck
(Linux/MacOs) / avm.bat docscheck
(Windows) to verify the container image is working as expected or needs to be pulled first. You will need this later.

3. Implement your contribution
To implement your contribution, we kindly ask you to first review the Terraform specifications and composition guidelines in particular to make sure your contribution complies with the repository’s design and principles.
Tip
To get a head start on developing your module, consider using the tooling recommended per spec TFNFR37. For example you can use the newres tool to help with creating variables.tf
and main.tf
if you’re developing a module using Azurerm provider.
4. Run Pre-commit Checks
Important
Make sure you have Docker installed and running on your machine.
Note
To simplify and help with the execution of commands like pre-commit
, pr-check
, docscheck
, fmt
, test-example
, etc. there is now a simplified avm script available distributed to all repositories via terraform-azurerm-avm-template
which combines all scripts from the avm_scripts folder in the tfmod-scaffold repository using avmmakefile.
The avm script also makes sure to pull the latest mcr.microsoft.com/azterraform:latest
container image before executing any command.
4.1. Run pre-commit and pr-check
The following commands will run all pre-commit checks and the pr-check.
# Running all pre-commit checks
# `pre-commit` runs depsensure fmt fumpt autofix docs
# `pr-check` runs fmtcheck tfvalidatecheck lint unit-test
## Linux/MacOs
./avm pre-commit
./avm pr-check
## Windows
avm.bat pre-commit
avm.bat pr-check
4.2 Run e2e tests
Currently you have two options to run e2e tests:
Note
With the help of the avm script and the commands ./avm test-example
(Linux/MacOs) / avm.bat test-example
(Windows) you will be able to run it in a more simplified way. Currently the test-example
command is not completely ready yet and will be released soon. Therefore please use the below docker command for now.
Run e2e tests with the help of the azterraform docker container image.
# Linux/MacOs
docker run --rm -v $(pwd):/src -w /src -v $HOME/.azure:/root/.azure -e TF_IN_AUTOMATION -e AVM_MOD_PATH=/src -e AVM_EXAMPLE=<example_folder> -e ARM_SUBSCRIPTION_ID -e ARM_TENANT_ID -e ARM_CLIENT_ID -e ARM_CLIENT_SECRET mcr.microsoft.com/azterraform:latest make test-example
# Powershell
docker run --rm -v ${pwd}:/src -w /src -v $HOME/.azure:/root/.azure -e TF_IN_AUTOMATION -e AVM_MOD_PATH=/src -e AVM_EXAMPLE=<example_folder> -e ARM_SUBSCRIPTION_ID -e ARM_TENANT_ID -e ARM_CLIENT_ID -e ARM_CLIENT_SECRET mcr.microsoft.com/azterraform:latest make test-example
Make sure to replace <client_id>
and <service_principal_password>
with the values of your service principal as well as <example_folder>
(e.g. default
) with the name of the example folder you want to run e2e tests for.
Run e2e tests with the help of terraform init/plan/apply
.
Simply run terraform init
and terraform apply
in the example
folder you want to run e2e tests for. Make sure to set the environment variables ARM_SUBSCRIPTION_ID
, ARM_TENANT_ID
, ARM_CLIENT_ID
and ARM_CLIENT_SECRET
before you run terraform init
and terraform apply
or make sure you have a valid Azure CLI session and are logged in with az login
.
5. Create a pull request to the upstream repository
Once you are satisfied with your contribution and validated it, submit a pull request to the upstream repository and work with the module owner to get the module reviewed by the AVM Core team, by following the initial module review process for Terraform Modules, described here. This is a prerequisite for publishing the module. Once the review process is complete and your PR is approved, merge it into the upstream repository and the Module owner will publish the module to the HashiCorp Terraform Registry.
5.1 Create the Pull Request [Contributor]
These steps are performed by the contributor:
- Navigate to the upstream repository and click on the
Pull requests
tab. - Click on the
New pull request
button. - Ensure the
base repository
is set to the upstream AVM repo. - Ensure the
base
branch is set to main
. - Ensure your
head repository
and compare
branch are set to your fork and the branch you are working on. - Click on the
Create pull request
button.
5.2 Review the Pull Request [Owner]
- IMPORTANT: The module owner must first check for any malicious code or changes to workflow files. If they are found, the owner should close the PR and report the contributor.
- Review the changes made by the contributor and determine whether end to end tests need to be run.
- If end to end tests do not need to be run (e.g. doc changes, small changes, etc) then so long as the static analysis passes, the PR can be merged to main.
- If end to end tests do need to be run, then follow the steps in 5.3.
5.3 Release Branch and Run End to End Tests [Owner]
- IMPORTANT: The module owner must first check for any malicious code or changes to workflow files. If they are found, the owner should close the PR and report the contributor.
- Create a release branch from
main
. Suggested naminmg convention is release/<description-of-change>
. - Open the PR created by the contributor and click
Edit
at the top right of the PR. - Change the
base
branch to the release branch you just created. - Wait for the PR checks to run, validate the code looks good and then merge the PR into the release branch.
- Create a new PR from the release branch to the
main
branch of the AVM module. - The end to end tests should trigger and you can approve the run.
- Once the end to end tests have passed, merge the PR into the
main
branch. - If the end to end tests fail, investigate the failure. You have two options:
- Work with the contributor to resolve the issue and ask them to submit a new PR from their fork branch to the release branch.
- Re-run the tests and merge to
main
. Repeat the loop as required.
- If the issue is a simple fix, resolve it directly in the release branch, re-run the tests and merge to
main
.
Common mistakes to avoid and recommendations to follow
- If you contribute to a new module then search and update
TODOs
(which are coming with the terraform-azurerm-avm-template) within the code and remove the TODO
comments once complete terraform.lock.hcl
shouldn’t be in the repository as per the .gitignore
file- Update the
support.md
file \_header.md
needs to be updatedsupport.md
needs to be updated- Exclude
terraform.tfvars
file from the repository
Subsections of Contribution Flow
This section describes the contribution flow for module owners who are responsible for creating and maintaining Terraform Module repositories.
Important
This contribution flow is for Module owners only.
As a Terraform Module Owner you need to be aware of the AVM contribution process overview & Terraform specifications (including Interfaces) as as these need to be considered during pull request reviews for the modules you own.
Info
Make sure module authors/contributors tested their module in their environment before raising a PR. The PR uses e2e checks with 1ES agents in the 1ES subscriptions. At the moment their is no read access to the 1ES subscription. Also if more than two subscriptions are required for testing, that’s currently not supported.
1. Owner Activities and Responsibilities
Familiarise yourself with the responsibilities as Module Owner outlined in Team Definitions & RACI and in the TF Issue Triage.
- Watch Pull Request (PR) and issue (questions/feedback) activity for your module(s) in your repository and ensure that PRs are reviewed and merged in a timely manner as outlined in SNFR11.
Info
Make sure module authors/contributors tested their module in their environment before raising a PR. Also because once a PR is raised a e2e GitHib workflow pipeline is required to be run successfully before the PR can be merged. This is to ensure that the module is working as expected and is compliant with the AVM specifications.
2. GitHub repository creation and configuration
Once your module has been approved and you are ready to start development, you need to request that a new repository be created for your module.
You do that by adding a comment to the issue with the #RFRC
tag. The Status: Ready For Repository Creation 📝 label will then be applied. This will trigger the creation of the repository and the configuration of the repository with the required settings.
Info
If you need your repository to be created urgently, please message the AVM Core team in the AVM Teams channel.
Once your module is ready for development, the Status: Repository Created 📄 label will be added to the issue and you’ll be notified it is ready.
3. Module Development Activities
You can now start developing your module, following standard guidance for Terraform module development.
Some useful things to know:
Pull Request
You can raise a pull request anytime, don’t wait until the end of the development cycle. Raise the PR after you first push your branch.
You can then use the PR to run end to end tests, check linting, etc.
Once readdy for review, you can request a review per step 4.
Grept
Grept is a linting tool for repositories, ensures predefined standards, maintains codebase consistency, and quality.
It’s using the grept configuration files from the Azure-Verified-Modules-Grept repository.
You can see here which files are synced from the terraform-azurerm-avm-template
repository.
Set environment variables and run Grept:
export GITHUB_REPOSITORY_OWNER=Azure
export GITHUB_REPOSITORY=Azure/terraform-azurerm-avm-res-<RP>-<modulename>"
./avm grept-apply
$env:GITHUB_REPOSITORY_OWNER="Azure"
$env:GITHUB_REPOSITORY="Azure/terraform-azurerm-avm-res-<RP>-<modulename>"
./avm grept-apply
Custom Variables and Secrets for end to end tests
The respoitory has an environment called test
, it has have approvals and secrets applied to it ready to run end to end tests.
- In the unusual cicumstance that you need to use your own tenant and subscription for end to end tests, you can override the secrets by setting
ARM_TENANT_ID_OVERRIDE
, ARM_SUBSCRIPTION_ID_OVERRIDE
, and ARM_CLIENT_ID_OVERRIDE
secrets. - If you need to supply additional secrets or variables for your end to end tests, you can add them to the
test
environment. They must be prefixed with TF_VAR_
, otherwise they will be ignored.
4. Review the module
Once the development of the module has been completed, get the module reviewed from the AVM Core team by following the AVM Review of Terraform Modules process here which is a pre-requisite for the next step.
5. Publish the module
Once a module has been reviewed and the PR is merged to main
. Follow the below steps to publish the module to the HashiCorp Registry.
Ensure your module is ready for publishing:
Create a release with a new tag (e.g. 0.1.0
) via Github UI.
- Go to the releases tab and click on
Draft a new release
. - Ensure that the
Target
is set to the main
branch. - Select
Choose a tag
and type in a new tag, such as 0.1.0
Make sure to create the tag from the main
branch. - Generate the release notes using the
Generate release notes
button.

Elevate your respository access using the Open Source Management Portal.
Sign in to the HashiCorp Registry using GitHub.
Publish a module by selecting the Publish
button in the top right corner, then Module
Select the repository and accept the terms.
Info
Once a module gets updated and becomes a new version/release it will be automatically published with the latest published release version to the HashiCorp Registry.
Important
When an AVM Module is published to the HashiCorp Registry, it MUST follow the below requirements:
- Resource Module:
terraform-<provider>-avm-res-<rp>-<ARM resource type>
as per RMNFR1 - Pattern Module:
terraform-<provider>-avm-ptn-<patternmodulename>
as per PMNFR1
This section describes the process for AVM core team members who are responsible for creating Terraform Module repositories.
Important
This contribution flow is for AVM Core Team members only.
1. Find Issues Ready for Repository Creation
- When a module owner is ready to start development, they will add the Status: Ready For Repository Creation 📝 label to the proposal via a comment issue.
- To find issues that are ready for repository creation, click this link
- Open one of the issues to find the details you need.
- Module name: This will be in the format
avm-<type>-<name>
. e.g. avm-res-network-virtualnetwork
- Module owner GitHub handle: This will be in the content of the issue
- Module owner display name: You may need to look this up in the open source portal
- Module description: If this does not exist, then create one. The description will automtically be prefixed with
Terraform Azure Verified <module-type> Module for ...
, where <module-type>
is either Resource, Pattern, or Utility - Resource provider namespace: You may need to look this up if not included in the issue
- Resource type: You may need to look this up if not included in the issue
- Module alternative names: Consider if it would be useful to search for this module using other names. If so, add them here. This is a comma separated list of names
- Module comments: Any comments you want to add to the module index CSV file
- Owner secondary GitHub handle: This is optional. If the module owner has a secondary GitHub handle
- Owner secondary display name: This is optional. If the module owner has a secondary display name
2. Create the repository
Open a PowerShell terminal
Clone the https://github.com/Azure/terraform-azure-modules repository and navigate to the repository_creation_helper
folder
git clone "https://github.com/Azure/terraform-azure-modules"
cd ./terraform-azure-modules/repository_creation_helper
Install the GitHub CLI if you don’t already have it installed: https://cli.github.com
Login to GitHub CLI
gh auth login -h "github.com" -w -p "https" -s "delete_repo" -s "workflow" -s "read:user" -s "user:email"
Follow the prompts to login to your GitHub account.
Run the following command, replacing the values with the details you collected in step 1
# Required Inputs
$moduleProvider = "azurerm" # Only change this if you know why you need to change it (Allowed values: azurerm, azapi, azure)
$moduleName = "<module name>" # Replace with the module name (do not include the "terraform-azurerm" prefix)
$moduleDisplayName = "<module description>" # Replace with a short description of the module
$resourceProviderNamespace = "<resource provider namespace>" # Replace with the resource provider namespace of the module (NOTE: Leave empty for Pattern or Utility Modules)
$resourceType = "<resource type>" # Replace with the resource type of the module (NOTE: Leave empty for Pattern or Utility Modules)
$ownerPrimaryGitHubHandle = "<github user handle>" # Replace with the GitHub handle of the module owner
$ownerPrimaryDisplayName = "<user display name>" # Replace with the display name of the module owner
# Optional Metadata Inputs
$moduleAlternativeNames = "<alternative names>" # Replace with a comma separated list of alternative names for the module
$moduleComments = "<comments>" # Replace with any comments you want to add to the module
$ownerSecondaryGitHubHandle = "<github user handle>" # Replace with the GitHub handle of the module owner
$ownerSecondaryDisplayName = "<user display name>" # Replace with the display name of the module owner
./New-Repository.ps1 `
-moduleProvider $moduleProvider `
-moduleName $moduleName `
-moduleDisplayName $moduleDisplayName `
-resourceProviderNamespace $resourceProviderNamespace `
-resourceType $resourceType `
-ownerPrimaryGitHubHandle $ownerPrimaryGitHubHandle `
-ownerPrimaryDisplayName $ownerPrimaryDisplayName `
-moduleAlternativeNames $moduleAlternativeNames `
-moduleComments $moduleComments `
-ownerSecondaryGitHubHandle $ownerSecondaryGitHubHandle `
-ownerSecondaryDisplayName $ownerSecondaryDisplayName
For example:
# Required Inputs
$moduleProvider = "azurerm" # Only change this if you know why you need to change it (Allowed values: azurerm, azapi, azure)
$moduleName = "avm-res-network-virtualnetwork" # Replace with the module name (do not include the "terraform-azurerm" prefix)
$moduleDisplayName = "Virtual Networks" # Replace with a short description of the module
$resourceProviderNamespace = "Microsoft.Network" # Replace with the resource provider namespace of the module (NOTE: Leave empty for Pattern or Utility Modules)
$resourceType = "virtualNetworks" # Replace with the resource type of the module (NOTE: Leave empty for Pattern or Utility Modules)
$ownerPrimaryGitHubHandle = "jaredfholgate" # Replace with the GitHub handle of the module owner
$ownerPrimaryDisplayName = "Jared Holgate" # Replace with the display name of the module owner
# Optional Metadata Inputs
$moduleAlternativeNames = "VNet" # Replace with a comma separated list of alternative names for the module
$moduleComments = "" # Replace with any comments you want to add to the module
$ownerSecondaryGitHubHandle = "" # Replace with the GitHub handle of the module owner
$ownerSecondaryDisplayName = "" # Replace with the display name of the module owner
./New-Repository.ps1 `
-moduleProvider $moduleProvider `
-moduleName $moduleName `
-moduleDisplayName $moduleDisplayName `
-resourceProviderNamespace $resourceProviderNamespace `
-resourceType $resourceType `
-ownerPrimaryGitHubHandle $ownerPrimaryGitHubHandle `
-ownerPrimaryDisplayName $ownerPrimaryDisplayName `
-moduleAlternativeNames $moduleAlternativeNames `
-moduleComments $moduleComments `
-ownerSecondaryGitHubHandle $ownerSecondaryGitHubHandle `
-ownerSecondaryDisplayName $ownerSecondaryDisplayName
The script will stop and prompt you to fill out the Microsoft Open Source details,
Open the Open Source Portal using the link in the script output.
Click Complete Setup
, then use the following table to provide the settings:
Question | Answer |
---|
Classify the repository | Production |
Assign a Service tree or Opt-out | Azure Verified Modules / AVM |
Direct owners | Add the module owner and yourself as direct owners. Add the avm-team-module-owners as security group. |
Is this going to ship as a public open source licensed project | Yes, creating an open source licensed project |
What type of open source will this be | Sample code |
What license will you be releasing with | MIT |
Did your team write all the code and create all of the assets you are releasing? | Yes, all created by my team |
Does this project send any data or telemetry back to Microsoft? | Yes, telemetry |
Does this project implement cryptography | No |
Project name | Azure Verified Module (Terraform) for ‘module name’ |
Project version | 1 |
Project description | Azure Verified Module (Terraform) for ‘module name’. Part of AVM project - https://aka.ms/avm |
Business goals | Create IaC module that will accelerate deployment on Azure using Microsoft best practice. |
Will this be used in a Microsoft product or service? | This is open source project and can be leveraged in Microsoft service and product. |
Adopt security best practice? | Yes, use just-in-time elevation |
Maintainer permissions | Leave empty |
Write permissions | Leave empty |
Repository template | Uncheck |
Add .gitignore | Uncheck |
Click Finish setup + start business review
to complete the setup
Wait for it to process and then click View repository
If you don’t see the Elevate your access
button, then refresh the browser window
Click Elevate your access
and follow the prompts to elevate your access
Now head back over to the terminal and type yes
and hit enter to complete the repository configuration
Open the new repository in GitHub.com and verify it all looks good.
- On the home page
- The name is correct
- The description is correct
- The Terraform registry url looks good
- The repository has the template files in it
- In Setting
- The repository is public
- The Collaborators and teams are correct
3. Request the GitHub App Install
Create a new issue at https://github.com/microsoft/github-operations/issues/new?template=GitHub-App-Installation-Request.md
Update the issue with the following details:
Title: [GitHub App] Installation Request - Azure Verified Modules
Body - replace <repository url>
with the URL of the repository you created in step 2:
> __Note:__ If the app is listed on the [Auto-Approved list](https://docs.opensource.microsoft.com/github/apps/approvals/), you do not need to complete this form.
You complete these steps:
- [x] Confirm the app is not in the [Auto-Approved list](https://docs.opensource.microsoft.com/github/apps/approvals/)
- [x] Fill out and verify the information in this form
- [x] Update the title to reflect the org/repo and/or app name
- [x] Submit the native request within the GitHub user interface
Operations will help complete these steps:
- [ ] Approve the app if already requested on GitHub natively
- [ ] Close this issue
Finally, you'll complete any configuration with the app or your repo that is required once approved.
# My request
- GitHub App name: Azure Verified Modules
- GitHub organization in which the app would be installed: Azure
- Is this an app created by you and/or your team?
- [x] Yes, this is an app created by me and/or my team
- [ ] No, this is a Microsoft 1st-party app created by another team
- [ ] No, this is a 3rd-party marketplace app
- If this __is an app created by you and/or your team__, please provide some ownership information in case future questions come up:
- Service Tree ID: our service tree ID is: Unchanged
- A few specific individuals at Microsoft if we have questions (corporate email list):Unchanged
- An optional team discussion list: Unchanged
- Is this an app you/your team created to address [reduced PAT lifetimes](https://aka.ms/opensource/tsg/pat)?
- [x] Yes
- [ ] No
- Are you looking for this app to be installed on individual repos or all repos in an organization?
- [x] Individual repos: <repository url>
- [ ] All repos in an organization
- Does this app have any side-effects if it is installed into all repos in an organization? Side effects can include creating labels, issues, pull requests, automatic checks on PRs, etc.
- [ ] Yes, it has side effects and you should be careful if installing to all repos in an org
- [x] No side effects
- Please provide a description of the app's functionality and what are you trying to accomplish by utilizing this app:
Unchanged
- For any major permissions (org admin, repo admin, etc.), can you explain what they are and why they are needed?
Unchanged
- Any other notes or information can you provide about the app?
Submit the issue
4. Notify the Module Owner and Update the Issue Status
Add a comment to the issue you found in step 1 to let the module owner know that the repository has been created and is be ready for them to start development.
@<module owner> The module repository has now been created. You can find it at <repository url>.
The final step of repository configuration is still in progress, but you will be able to start developing your code immediately.
The final step is to create the environment and credentials require to run the end to end tests. If the environment called `test` is not available in 48 hours, please let me know.
Thanks
Add the Status: Repository Created 📄 label to the issue
Remove the Status: Ready For Repository Creation 📝 label from the issue
When you author your Azure Verified Module (AVM) Terraform module, you should ensure that it is well tested.
This document outlines the testing framework and tools that are used to test AVM Terraform modules.
Testing Framework Composition
For Terraform modules, we use the following tools:
Mandatory tooling:
- avmfix for advanced formatting
- Conftest, and Open Policy Agent (OPA) for well architected compliance
- grept (Go REPository linTer) for repository contents
- terraform-docs for documentation generation
- TFLint for spec compliance
Optional tooling:
Before Submitting a Pull Request
Before you submit a pull request to your module, you should ensure that the following checks are passed.
You can run the linting tools locally by running the following command:
Prerequisites
You need to have the following tools installed:
Linux / MacOS / WSL
./avm pre-commit
./avm pr-check
Windows
.\avm.bat pre-commit
.\avm.bat pr-check
Doing so will shorten the development cycle and ensure that your module is compliant with the AVM specifications.
GitHub Actions and Pull Requests
We centrally manage the test workflows for your Terraform modules.
We also provide a test environment (Azure Subscription) as part of the testing framework.
Linting
The linting.yml
workflow in your repo (.github/workflows/linting.yml
) is responsible for static analysis of your module.
It will run the following centralized tests:
avmfix
to ensure that your module is formatted correctly.terraform-docs
to ensure that your module documentation is up to date.TFLint
to ensure that your module is compliant with the AVM specifications.
End-to-end testing
The e2e.yml
workflow in your repo (.github/workflows/e2e.yml
) is responsible for end-to-end testing of your module examples.
It will run the following centralized test workflow: https://github.com/Azure/terraform-azurerm-avm-template/blob/main/.github/workflows/test-examples-template.yml.
It will run the following tasks:
- List all the module examples in the
examples
directory. - Conftest will check the plan for compliance with the well-architected framework using OPA.
- Your example will be tested for idempotency by running
terraform apply
and then terraform plan
again. - Your example will be destroyed by running
terraform destroy
.
Currently it is not possible to run the end-to-end tests locally, however you can run terraform apply
and terraform destroy
commands locally to test your module examples.
OPA (Open Policy Agent) & Conftest
Conftest is the first step in the AVM end-to-end testing framework.
It will check the plan for compliance with the well-architected framework using OPA.
The policies that we use are available here: https://github.com/Azure/policy-library-avm.
If you get failures, you should examine them to understand how you can make your example compliant with the well-architected framework.
Creating exceptions
In some circumstances, you may need to create an exception for a policy, you can do so by creating a .rego
file in the exceptions
sub-directory of your example.
For example, to exclude the rule called "configure_aks_default_node_pool_zones"
, create a file called exceptions/exception.rego
in your example, with the following content:
package Azure_Proactive_Resiliency_Library_v2
import rego.v1
exception contains rules if {
rules = ["configure_aks_default_node_pool_zones"]
}
TFLint
TFLint is used to check that your module is compliant with the AVM specifications.
We use a custom ruleset for TFLint to check for AVM compliance: https://github.com/Azure/tflint-ruleset-avm.
Excluding rules
If you need to exclude a rule from TFLint, you can do so by creating one of the following in the root of your module:
avm.tflint.override.hcl
- to override the rules for the root moduleavm.tflint.override_module.hcl
- to override the rules for submodulesavm.tflint.override_example.hcl
- to override the rules for examples
These files are HCL files that contain the rules that you want to override.
Here is some example syntax:
# Disable the required resource id output rule as this is a pattern module and it does not make sense here.
rule "required_output_rmfr7" {
enabled = false
}
Please include a comment in the file explaining why you are disabling the rule.
Excluding examples from end-to-end testing
If you have examples that you do not want to be tested, you can exclude them by creating a file called .e2eignore
in the example directory.
The contents of the file should explain why the example is excluded from testing.
Global test setup and teardown
Some modules require a global setup and teardown to be run before and after ALL examples.
We provide a way to do this by creating a file called examples/setup.sh
in the root of your module.
This script will be run before all examples are tested, and will be authorized with the same credentials as the examples.
You can optionally supply a teardown script that will be run after all examples are tested.
This should be called examples/teardown.sh
.
Pre and post scripts per-example
Some examples require pre and post commands that are specific to that example.
Use cases here can be to modify the example files to ensure unique names or to run some commands before or after the example is tested.
You can do this by creating a file called examples/example_name/pre.sh
in the example directory.
This script will be run before the example is tested, and will be authorized with the same credentials as the example.
You can optionally supply a post script that will be run after the example is tested.
This should be called examples/example_name/post.sh
.
The pre and post scripts are run in the context of the example directory, so you can use relative paths to access files.
Grept and the chore: repository governance
pull requests
We run a weekly workflow that checks the contents of your module and creates a pull request if it finds any issues.
If you see a pull request with the title chore: repository governance
, it means that the workflow has found some issues with your module, so please check the pull request and merge it to ensure you are compliant.
You do not need to release a new version of your module when you merge these pull requests, as they do not change the module code.
Overriding the default test subscription (using a different Azure environment)
If your module deploys resource that are not compatible with the default test subscription, you can override these defaults by setting additional environment secrets in your GitHub repository.
You might need to do this if:
- The resources you are deploying are constrained by quota or subscription limits.
- You need to deploy resources at scopes higher than subscription level (e.g. management group or tenant).
To override the Azure environment, you can specify the environment in your module’s configuration or set the following environment variables in your GitHub repository settings:
- Create a user-assigned managed identity in the Azure environment you want to use.
- Create GitHub federated credentials for the user-assigned managed identity in the Azure environment you want to use, using the github organization and repository of your module. Select entity type ’environment’ and add
test
for the name. - Create appropriate role assignments for the user-assigned managed identity in the Azure environment you want to use.
- Now, elevate you access to administrator by going to the open source portal: https://repos.opensource.microsoft.com/orgs/Azure/repos/REPOSITORY-NAME/jit.
- Then, go to the settings of your GitHub repository and select environments.
- Select the
test
environment. - Add the following secrets:
ARM_CLIENT_ID_OVERRIDE
- The client ID of the user-assigned managed identity.ARM_TENANT_ID_OVERRIDE
- The tenant ID of the user-assigned managed identity.ARM_SUBSCRIPTION_ID_OVERRIDE
- The subscription ID you want to use for the tests.
Authors may choose to use terraform test to run unit and integration tests on their modules.
Unit tests
Test files should be placed in the tests/unit
directory.
They can be run using the following command:
Authors SHOULD use unit tests with mocked providers.
This ensures that the tests are fast and do not require any external dependencies.
Integration tests
Integration tests should be placed in the tests/integration
directory.
They can be run using the following command:
Integration tests should deploy real resources and should be run against a real Azure subscription.
However, they are not fully integrated into the AVM GitHub Actions workflows.
Authors should run integration tests locally and ensure that they are passing but they will not be run automatically in the CI/CD pipeline.