This folder contains the ARM template reference for deploying oa-verifier as an Azure Confidential Container.
All deployments must use the CI/CD pipeline via GitHub Actions. This ensures:
- Reproducible builds with Nix
- Proper CCE policy generation with regex patterns for secrets
- Sigstore signing for provenance verification
- Consistent attestation hashes
The build-and-sign workflow handles everything automatically:
- Build: Nix builds reproducible container image
- Sign: Image signed with Sigstore (keyless, GitHub OIDC)
- Push: Published to GHCR and ACR
- Policy: CCE policy generated with secret protection (regex patterns)
- Deploy: Container deployed to Azure Confidential Containers
- Verify: Attestation verified against build
Push to main, or manually trigger:
# Via GitHub CLI
gh workflow run build-and-sign.ymlaci-template.json- Reference ARM template (CCE policy generated by CI/CD)
| Secret | Description |
|---|---|
ACR_USERNAME |
Azure Container Registry username |
ACR_PASSWORD |
Azure Container Registry password |
AZURE_CREDENTIALS |
Azure service principal credentials (JSON) |
STATION_REGISTRY_URL |
Station registry service URL |
STATION_REGISTRY_SECRET |
Station registry API secret |
CHALLENGE_MIN_INTERVAL |
Min seconds between privacy checks (default: 300) |
CHALLENGE_MAX_INTERVAL |
Max seconds between privacy checks (default: 600) |
SUBMIT_KEY_OWNERSHIP_GRACE_SECONDS |
Grace window for ownership checks near key expiry (default: 300) |
| Secret | Description |
|---|---|
TLS_DOMAIN |
Custom domain for Let's Encrypt cert |
ACME_EMAIL |
Email for Let's Encrypt notifications |
ACME_DNS_PROVIDER |
DNS provider (e.g., cloudflare) |
CF_API_TOKEN |
Cloudflare DNS API token |
az ad sp create-for-rbac --name "oa-verifier-deploy" \
--role contributor \
--scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} \
--sdk-auth# Verify Sigstore signature
cosign verify ghcr.io/OWNER/oa-verifier@sha256:DIGEST \
--certificate-identity-regexp='https://github.com/OWNER/REPO/.*' \
--certificate-oidc-issuer='https://token.actions.githubusercontent.com'
# Verify GitHub attestation
gh attestation verify oci://ghcr.io/OWNER/oa-verifier@sha256:DIGEST --owner OWNERNote: CI compares attested policy hash against the source-built policy hash. Full JWT signature verification should still be performed by external auditors using the verify_at certificates from /attestation.
Source Code (GitHub)
↓ [Nix reproducible build]
Container Image (signed by Sigstore)
↓ [Policy generated from image layers]
CCE Policy (regex patterns for secrets)
↓ [SHA256 hash]
Policy Hash (measured by AMD SEV-SNP hardware)
↓ [Returned in attestation]
MAA Token (signed by Azure)
The CI/CD workflow generates CCE policies with regex patterns for secret environment variables:
// Secrets use regex patterns - actual values NOT in policy
{"pattern": "STATION_REGISTRY_SECRET=.+", "strategy": "re2"}
// Non-secrets use exact matches
{"pattern": "MAA_ENDPOINT=http://localhost:8080/attest/maa", "strategy": "string"}This ensures:
- Secret values are never embedded in the CCE policy
- Policy hash remains constant regardless of secret values
- Attestation verification works without exposing secrets
See ../docs/ATTESTATION.md for zero-trust verification instructions.