Repository Creation Process

Important

This page is for module owners only. If you are an external contributor, skip to the contribution flow.

Important

Every repository created through this process MUST use AzAPI for every control-plane resource and supported data-plane operation. AzureRM is permitted only for a specific unsupported data-plane/non-ARM API operation under the narrow TFFR3 exception. The exception must be documented and applies only to that operation in the root module, submodules, examples, end-to-end tests, Terraform tests, fixtures, and documentation snippets.

Important

If this process is not followed exactly, it may result in your repository and any in-progress code being permanently deleted.

1. Add yourself to the Module Owners Team and Open Source orgs

If you have already completed these steps, skip to step 2.

  1. Open the Open Source Portal and ensure your GitHub account is linked to your Microsoft account.
  2. Open the Open Source Portal and ensure you are a member of the Azure and Microsoft organizations.
  3. Request access via the Azure Verified Modules (AVM) Module Contributors access package. Approval adds you to the azure-verified-modules-module-contributors Entra group.
Info

Until your access request is approved, you can contribute by using JIT elevation.

2. Gather repository information

Gather the following approved values from the module request issue. avm init writes them to the root metadata.json in the repository’s first commit.

InformationDescription
Repository nameterraform-azure-avm-<type>-<name>, built from the approved module name avm-<type>-<name> (e.g. avm-res-network-virtualnetwork becomes terraform-azure-avm-res-network-virtualnetwork). It is also the name of your local folder.
Module typeresource, pattern, or utility, matching res, ptn, or utl in the module name.
Module display nameApproved display name, supplied as moduleDisplayName
Module descriptionApproved description, supplied as moduleDescription
Canonical typeApproved ARM resource type (e.g. Microsoft.Network/virtualNetworks) or pattern/utility taxonomy, supplied as canonicalType. Do not infer the value from the module name.
Ownersowners, a PowerShell string array of approved bare GitHub usernames or qualified @organization/team-slug entries
Telemetry ID prefixOptional telemetryIdPrefix. Supply the assigned identifier if the proposal has one. If you omit it, avm init mints one in the fleet format 46d3xtrf.<res|ptn>.<7 lowercase hex characters> for resource and pattern modules. Never hand-pick an identifier yourself. Utility modules do not use telemetry.
Alternative namesOptional alternativeNames, a PowerShell string array

Record every approved owner. An empty owner array is valid for an unowned module, subject to the proposal and ownership processes. Metadata does not grant access. Later ownership changes use the metadata review process.

3. Create the repository

Prerequisites:

Authenticate

gh auth login --hostname "github.com" --web --git-protocol "https" --scopes "workflow"

avm init needs the repo, read:org, and workflow scopes, and gh auth login requests the first two by default. If you are already signed in, run gh auth refresh --hostname "github.com" --scopes "workflow" instead. If you set GH_TOKEN, that token needs the same scopes.

Optional: use an AI agent

An AI agent such as GitHub Copilot CLI can guide you through the rest of this page with the avm-tf-module-repository-creation agent skill. The skill collects the approved values from the module request issue, runs avm init, tells you what to enter in the Open Source Portal, checks the result, and finishes with step 5. It asks for your approval before it creates the repository and before it changes anything in the Open Source Portal for you.

Install the skill for your user account with GitHub CLI 2.90.0 or later:

gh skill install Azure/azure-verified-modules-tools .github/skills/avm-tf-module-repository-creation --scope user

Then ask your agent, for example, to “create the Terraform module repository for avm-res-network-virtualnetwork”. The command installs the skill from the latest Avm.Authoring release, so it matches the released avm init. Run gh skill update avm-tf-module-repository-creation to update it later.

Run avm init

Run these commands from the folder that should contain the repository’s local folder. Replace the placeholders with the approved values.

$metadata = @{
    moduleDisplayName = "<approved display name>"
    moduleDescription = "<approved description>"
    canonicalType = "<approved ARM resource type or taxonomy>"
    owners = @("<approved individual handle>")
}

avm init -Ecosystem terraform -ModuleType resource -Path "./<repository name>" -InputObject $metadata -WhatIf

Use -ModuleType pattern or -ModuleType utility for pattern and utility modules. Add telemetryIdPrefix or alternativeNames to $metadata when needed. In an interactive terminal, you can omit -InputObject and enter the values when avm init prompts for them.

-WhatIf validates the values and lists the stages without making GitHub or filesystem changes. Review the output and obtain the required approval, then run the same command without -WhatIf. avm init then:

  1. Writes metadata.json to the folder. Later runs read the values from this file, so you only supply them once.
  2. Creates the public repository in the Azure organization.
  3. Pauses while you complete the Open Source Portal setup below and elevate with JIT.
  4. Grants the azure-verified-modules-module-contributors team push access and the azure-verified-modules-module-readers team triage access.
  5. Publishes the first commit to main: metadata.json, a minimal module scaffold, and the managed files, telemetry, and README added by avm pre-commit. _header.md starts with the module’s display name and description.
  6. Opens a pull request in microsoft/github-operations from your fork, requesting the Azure Verified Modules and Terraform Cloud GitHub App installations, and prints its link.
  7. Clones the repository into the folder.
  8. Reminds you of the two final Open Source Portal steps: tie the repository to the shared AVM JIT rule in step 4, then, last, leave jaredholgate and jatracey as the only Direct Owners in step 5. avm init cannot check these portal settings, so it lists both as manual every time it completes.

If a stage fails, or you stop the command, fix the reported problem and run the same command again on the same machine. Each stage checks what already exists, so avm init continues where it stopped.

Complete Open Source Portal Setup

avm init pauses after creating the repository and prints the Open Source Portal link and these answers.

➕ If you see the Complete Setup link

Click Complete Setup and use the following settings:

QuestionAnswer
Classify the repositoryProduction
Assign a Service tree or Opt-outAzure Verified Modules / AVM
Direct ownersAdd yourself, jaredholgate, and jatracey. Add azure-verified-modules-module-owners as fallback security group. You add yourself temporarily so you can finish the setup; step 5 removes you.
Public open source licensed project?Yes
What type of open source?Sample code
LicenseMIT
All code created by your team?Yes
Telemetry?Yes, telemetry
Cryptography?No
Project nameAzure Verified Module (Terraform) for ‘module name’
Project version1
Project descriptionAzure Verified Module (Terraform) for ‘module name’. Part of AVM project - https://aka.ms/avm
Business goalsCreate IaC module accelerating Azure deployment using Microsoft best practice.
Used in a Microsoft product?Open source, can be leveraged in Microsoft services.
Security best practice?Yes, use just-in-time elevation
Maintainer / Write permissionsLeave empty
Repository template / .gitignoreUncheck both

Click Finish setup + start business review, then View repository, then Elevate your access.

➕ If you do NOT see the Complete Setup link
  1. Go to the Compliance tab and fill out:
    • Direct owners: Add yourself, jaredholgate, and jatracey. Add azure-verified-modules-module-owners as fallback. You add yourself temporarily so you can finish the setup; step 5 removes you.
    • Classify the repository: Production
    • Service tree: Azure Verified Modules / AVM
  2. Go back to Overview and click Elevate your access if available.

Return to the terminal and type yes to continue. If avm init asks you to elevate again later, click Elevate your access on the repository overview, then type yes.

Note

Maintain the module’s details and full owners array through metadata code-owner review. Complete the Open Source Portal, access-package, and JIT requirements separately.

4. Tie the repository to the shared AVM JIT rule

New repositories default to JIT v1. AVM repositories must use JIT v2 and be tied to the shared service-AVM-azure-verified-modules-module-owners rule, so that just-in-time elevation is governed centrally by the AVM team rather than by a repository-specific rule. Proposing the tie also upgrades the repository to JIT v2.

This is a one-off manual action in the Open Source Portal. Do it after avm init has published the first commit, because it changes how you elevate. You need Direct Owner access to the repository, configured in the previous step. If you do not have permission to propose the tie, skip this step and email avm@microsoft.com with the repository name so the AVM core team can complete it.

  1. Open the repository overview on the Open Source Portal: https://repos.opensource.microsoft.com/orgs/Azure/repos/<repository name>.
  2. Click Advanced JIT options, then select Propose a new tie.
  3. Under Propose tying a new rule to this repository, enter the Rule ID service-AVM-azure-verified-modules-module-owners and click Review.
  4. Confirm the details and click Create tie.

The result page shows whether the tie is active or waiting for approval. On a repository still using JIT v1, a tie proposed by a Direct Owner can become active immediately. Once it is active, the repository overview shows JIT version: JIT v2 and the shared rule.

Info

A pending tie must be approved by an owner of the service-AVM-azure-verified-modules-module-owners rule (an AVM core team member). Ask the AVM core team to approve it. Once approved, just-in-time elevation for the repository is governed by the shared AVM rule.

5. Leave only jaredholgate and jatracey as Direct Owners

Important

This is the last step of the setup. Do it once everything else is done: avm init has completed and the JIT tie from step 4 is in place. The app installation request can still be waiting for approval.

When the setup is finished, jaredholgate and jatracey must be the only individual Direct Owners. Remove everyone else, including yourself and whoever created the repository, and keep azure-verified-modules-module-owners as the fallback security group.

  1. Elevate to administrator: on the repository’s Just-in-time Access tab in the Open Source Portal, select Next, enter a justification, and select the elevate button.
  2. On the repository overview, under Direct Owners, select Change owners. The button is only shown while you are elevated.
  3. Remove every individual Direct Owner other than jaredholgate and jatracey. The first two owner slots are required, and Save stays disabled while either is empty. If removing someone empties a required slot, remove jaredholgate or jatracey from a later slot and add them to the empty required slot instead.
  4. Keep the azure-verified-modules-module-owners fallback security group, then select Save.
  5. Reload the overview and check that Individual Direct Owners lists only jaredholgate and jatracey.

If you cannot change the Direct Owners, email avm@microsoft.com with the repository name so the AVM core team can complete this step.

Info

Module owners retain day-to-day access through the azure-verified-modules-module-owners security group and just-in-time elevation, so you do not need to remain a Direct Owner.

What happens next

The GitHub Apps are installed once the app installation pull request is approved. Running avm init again shows whether the request is still pending.

After the app is installed, repository sync applies the shared repository configuration and managed files to complete the setup.

Sync reads the root metadata.json from the module repository’s default branch for the display name and full owner list.