Provisioning quickstart#

Use this guide to create a first policy-gated Resource with a customer-owned runner and Terraform state.

Navigate: left navigation → Provisioning.


What you need#

Before opening Reply CMP, prepare:

  • a GitHub or Azure DevOps repository where you can commit the runner files;

  • an Azure subscription containing an existing Storage account and private Blob container for Terraform state;

  • an Azure workload identity that can manage the target resources and read, write and lease blobs in that container;

  • permission in Reply CMP to manage Provisioning modules, credentials and Deployments;

  • permission to configure the selected pipeline or workflow.

Choose the package that matches your runner. Each ZIP contains the complete runner contract and a small Azure Storage module you can use for the first test.

Azure DevOps starter

Includes azure-pipelines.yml, runner scripts and a locked example module.

GitHub starter

Includes the Actions workflow, runner scripts and the same example module.

Important

Keep the runner files on a protected branch. Never commit PATs, private keys, Terraform state, plans, tfvars, storage keys or SAS tokens.

1. Prepare the repository#

  1. Extract the ZIP into an empty repository.

  2. Review and commit all files, including .terraform.lock.hcl files.

  3. Push to a protected branch such as main.

  4. Create the pipeline or enable the workflow described in the package README.md.

The starter already pins the production Reply CMP endpoint in the protected runner file. Do not move the pin into a secret or runtime dispatch input. Change it only when Reply CMP support gives you an explicit non-production endpoint.

The sample module is in registry/modules/azure-storage-account. Create a protected tag for its first version:

git tag module/azure-storage/v1.0.0
git push origin module/azure-storage/v1.0.0

2. Prepare the state container#

Reply CMP connects an existing Azure Blob container; it does not create one.

Confirm that the Storage account has:

  • Microsoft Entra authentication only and shared-key access disabled;

  • anonymous Blob access disabled and a private state container;

  • secure HTTPS traffic only;

  • TLS 1.2 or later;

  • Blob versioning enabled;

  • Blob and container soft delete enabled for at least 14 days;

  • network access from the selected runner.

The endpoint may be public or private. Use a public endpoint with a hosted runner, or a private endpoint/firewall with a runner that has the required network path. In both cases state access remains private and requires Microsoft Entra authorization.

Grant the runner’s Azure workload identity Storage Blob Data Contributor at the narrowest practical scope, normally the state container. Do not create a state blob name: Reply CMP generates a unique key for the Deployment.

3. Store the repository or dispatch credential#

Open Provisioning → Module registry → Credentials → Add credential.

  1. Enter a purpose-based name, such as ado-provisioning or github-provisioning.

  2. Choose the credential type.

  3. Enter the secret once.

  4. Optionally choose the next rotation date.

  5. Select Store credential.

Add provisioning credential panel with name, credential type, token and optional rotation date

Secret values are accepted once and are never displayed again.#

For a private module repository, this credential reads source. For a runner, it starts only the configured pipeline or workflow. Terraform never receives it.

4. Register the example module#

Open Module registry → Modules → Register module.

Enter:

  • a stable module name, for example azure-storage-account;

  • display name Azure Storage account;

  • cloud provider Azure;

  • the repository provider and repository root URL;

  • module path registry/modules/azure-storage-account;

  • default ref main;

  • the credential created above when the repository is private.

Keep the initial schema supplied by the starter. Registration creates one module record for this one path; it does not register every folder in the repository.

Register tenant module panel organised into module identity, source and input schema sections

The repository URL points to the repository root; Module path identifies the reusable Terraform folder.#

Open the new module and select Add version:

  1. enter version 1.0.0;

  2. enter ref module/azure-storage/v1.0.0;

  3. keep Terraform 1.15.8;

  4. submit the version, inspect its exact commit and validation evidence, then approve it.

Reply CMP reads schema.json and .terraform.lock.hcl from the selected commit. There is no checksum field to complete in the UI.

5. Create a Deployment#

Open Provisioning → Deployments → New deployment.

  1. Enter a unique name and a region label used for filtering.

  2. Select at least one cloud Connection.

  3. When the same provider is connected more than once, give each connection a clear alias such as default, network or data.

  4. Select Create deployment.

New deployment panel with name, region label and Azure, AWS and GCP connection selectors

Cloud Connections can be selected during creation and changed later from Resources.#

Reply CMP opens the new Deployment on Runner & state. Plan and Apply remain unavailable until both sections are ready.

6. Connect the runner#

Select Change runner and choose Azure DevOps or GitHub Actions.

  1. Select the stored Azure DevOps credential.

  2. Select or type the organisation, project and numeric pipeline ID.

  3. Select or type the federated Azure service connection used by Terraform.

  4. Under Secretless Reply CMP callback, select Create connection. Reply CMP creates or reuses the tenant claim identity and the callback-only service connection.

  5. When the card turns green, select Use runner.

If automatic connection creation fails, the panel reveals the exact values and steps for creating a draft workload-identity connection manually. Do not create a client secret.

  1. Create a protected GitHub Environment.

  2. Add AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_SUBSCRIPTION_ID as Environment variables.

  3. Select the stored GitHub credential and enter owner, repository, workflow path, protected ref and Environment.

  4. Keep id-token: write in the workflow and configure the displayed workload-identity federation.

  5. Select Use runner.

Configure runner panel with Azure DevOps discovery, federated infrastructure connection and a green connected callback status

Dropdowns are editable: choose a discovered value or type the exact value when discovery is unavailable.#

7. Connect Terraform state#

Select Change state.

  1. Select an Azure Connection. Reply CMP uses it only to list and validate Storage resources through Azure management APIs.

  2. Select the resource group, Storage account and Blob container.

  3. Check State authentication. It shows the workload identity the runner will use to access the container.

  4. Select Validate storage.

  5. Correct any failed protection, validate again, then select Use state.

  6. Select Save configuration on the Runner & state page.

Connect existing Terraform state panel with cascading Azure selectors, state authentication and required protections

No storage key, SAS token or connection string is entered in Reply CMP.#

If another Deployment already uses the intended runner and Storage account, Reuse setup can prefill both sections. The new Deployment still receives its own state key and operation history.

8. Create a guardrail and Resource#

Open Provisioning → Policy guardrails → New guardrail. For a safe first rule:

  1. choose Limit resource deletions;

  2. set maximum deletions to 0;

  3. choose Block apply;

  4. enter a clear name and leave the guardrail enabled;

  5. select Create guardrail.

Return to the Deployment → Resources → Create resource. Select the approved module version, target connection alias and complete the guided form. Save the Resource. It remains Draft until Apply succeeds.

9. Plan and Apply#

  1. Select the rocket action in the Deployment header.

  2. Enable Plan only and confirm the runner and state shown in the panel.

  3. Start the operation.

  4. Open Operations, expand the newest entry and review the policy result.

  5. Select Open runner logs to inspect the complete, color-preserving Terraform output grouped by phase in Azure DevOps or GitHub.

  6. If the plan is correct, open the action again with Plan only disabled and start Apply.

  7. Confirm the Resource becomes Latest and the Deployment becomes Valid.

Apply deployment panel showing the exact runner and Terraform state before dispatch

Always verify the runner and state before starting an operation.#

For an existing Deployment that already has live resources, do not start Apply until you have completed the legacy state migration.