Skip to content

Azure CI/CD pipeline

How Nomain container images and Bicep templates flow from Nomain's supply chain into your Azure subscription, and the recommended customer-side pipeline that runs Bicep from a self-hosted Azure DevOps agent with private connectivity to the stamp.

Advanced reference

This is an operator-level reference for the Azure BYOC deployment pipeline. Specific commands, stages, and sizing recommendations may change between releases. For the wider stamp architecture and prerequisites, see BYOC on Azure.

Overview

Nomain ships container images and Bicep templates. The customer owns the deployment pipeline. The recommended pattern below pulls the supply chain into the customer's perimeter (no runtime dependency on Nomain ACR) and runs Bicep from a self-hosted agent that already has private connectivity to the stamp.

The pipeline has two halves that share the same Azure DevOps and self-hosted agent footprint: image mirroring on top, and Bicep deployment below it.

Image mirroring from Nomain ACR

Nomain publishes immutable, cosign-signed images to nomainregistry.azurecr.io (5 service images plus the Helm OCI charts). The customer pulls them into their own ACR, the dedicated registry inside the stamp's resource group, so the runtime never depends on Nomain ACR availability and the customer's supply-chain controls (Defender scan, Notary signature verification, ACR retention policy) apply.

PropertyRecommended setup
Mechanismaz acr import --source nomainregistry.azurecr.io/<image>:<tag> --image <image>:<tag> against the customer ACR. Native ACR feature, no extra runner-side state.
AuthenticationA scoped Nomain-issued pull token (read-only on nomainregistry.azurecr.io) is provisioned at customer onboarding. The token sits in your Key Vault and is referenced from the ADO pipeline as a secret variable.
CadenceOn every Nomain release (typically every 1-2 weeks). The pipeline can be triggered manually, on a schedule, or by a webhook from Nomain announcing the new tag.
Tag strategyMirror specific immutable semver tags only (e.g. 2026.05.0), never floating tags like latest or production. The Bicep values.yaml in your env pins the exact tag the App Services pull.
Signature verificationImages are cosign-signed against a Nomain public key. The mirror job can verify signatures pre-push, and ACR Trust Policies / Notary v2 can enforce them on pull (recommended for prod).
ScanningMicrosoft Defender for Cloud, Container Registries plan, scans the customer ACR on push, flagging CVEs before any App Service pulls the image.
RollbackPrevious tags stay in the customer ACR until the retention policy expires them. Rollback is a Bicep redeploy with the previous tag value, no re-pull from Nomain needed.

Net effect

After first onboarding, the runtime stamp has zero connectivity to Nomain ACR. Image pulls during scale-out, restart, or recovery all terminate at the customer's ACR Private Endpoint.

Azure DevOps is the recommended deployment tool for this BYOC pattern because customers in risk-sensitive environments usually already operate it, and because its self-hosted agent model maps cleanly onto the private-VNet posture of the stamp.

  • Aligns with existing Azure tenancy. Service connections to your Azure subscription use federated Workload Identity, so there are no service-principal secrets to rotate. Repos, pipelines, artifacts, and the agent pool live inside the same tenant boundary.
  • Self-hosted agent in your DevOps VNet. A VM (or VMSS scale set) running the ADO agent service, with its NIC in a dedicated DevOps VNet that is peered to the stamp VNet's deploymentSubnet. Bicep can reach private endpoints without any public route.
  • No public exposure. The pipeline talks to private endpoints: the App Service SCM endpoint, Key Vault data-plane, and ACR data-plane are all reached over the peered VNet using their privatelink.* DNS records. Microsoft-hosted agents cannot reach these and are not recommended.
  • Approval gates. ADO Environments give you native manual-approval gates between dev, staging, and prod, combined with Bicep's what-if dry-run in each stage as the change-control evidence.

Reference pipeline stages

StageWhat it doesRuns on
1. Lint & buildaz bicep build + bicep lint on the Bicep templates and per-env parameter files. No Azure write access needed.Microsoft-hosted agent (no private resources touched)
2. Mirror imagesaz acr import from Nomain ACR into customer ACR for the target release tag. Optional cosign signature verification step before importing.Self-hosted agent (DevOps VNet)
3. Bicep what-ifaz deployment sub what-if against the target subscription. Output published as a pipeline artifact for the approver to review.Self-hosted agent
Manual approvalADO Environment gate, required for staging and production deploys.(gate only)
4. Deployaz deployment sub create with the per-env Bicep parameter file. WorkOS / M2M secrets injected as pipeline secrets at this step.Self-hosted agent
5. Smoke testHTTPS probe against the webapp, healthcheck against each API, Postgres connectivity check via private endpoint. Failure rolls back to the previous Bicep deployment.Self-hosted agent
6. Tag & releaseTag the deployed commit in the ADO repo with the release version, attach Bicep what-if and smoke-test outputs as the audit trail.Microsoft-hosted agent

Self-hosted agent: sizing and placement

ItemRecommendation
Form factorVMSS scale set with 1-2 instances for HA. VM image: latest Ubuntu LTS with Azure CLI + Bicep + Docker pre-baked.
SizeStandard_D2s_v5 (2 vCPU / 8 GiB) is enough. Bicep deploys are I/O- and API-bound, not CPU-bound.
VNet placementDedicated DevOps VNet, peered to the stamp VNet. Reuse the same DevOps VNet across all environments (dev / staging / prod) so the agent pool is one set of nodes, not three.
IdentityVMSS bound to a user-assigned managed identity with Contributor on the stamp RG (or scoped down further with custom roles). No service-principal secrets in pipeline variables.
OutboundOnly needs egress to dev.azure.com (the ADO control plane). All other traffic is inbound from the peered VNet.
PatchingVMSS rolling reimage on a weekly schedule, or use Azure Image Builder with a baked-in image refreshed monthly.

If Azure DevOps isn't an option

GitHub Actions and GitLab CI both work with the same shape: Bicep plus a private agent in a peered VNet. The pipeline stages translate one-to-one. Microsoft-hosted runners and shared runners cannot complete the deploy because the App Service SCM endpoint is private. A self-hosted runner inside the VNet is required regardless of the CI platform you choose.

For the full stamp architecture, prerequisites, and secret handling that this pipeline deploys into, see BYOC on Azure.