Policy Management

Attestation policy promotion workflows, staging probes, and architecture decision records

3
workflows
3
ADRs
3
profiles
PR
promotion gate

KMS Staging Probe

Workflow: kms-phala-staging-probe.yaml

Deploys a staging KMS instance, runs an attestation probe, extracts measurements, and generates policy candidates for promotion.

What It Does

The staging probe is the first step in any KMS policy change. It creates a controlled environment to extract and validate measurements before they reach production.

1

Deploy staging KMS

Spins up a digest-pinned KMS container on a Phala Cloud staging CVM. Waits for the health endpoint to report the expected version.

2

Run attestation probe

Sends POST /attest to the staging KMS and captures the returned TDX quote.

3

Extract measurements

Parses the TDX quote to extract MRTD, RTMR0–3, and TCB status. These become the measurement candidates.

4

Compute compose hash

Calculates the SHA-256 hash of the Docker Compose configuration used for deployment. This hash is included in the attestation artifacts for reproducibility.

5

Generate policy candidates

Writes the extracted measurements into a measurement-policy-candidates.json file formatted for direct promotion into the release policy.

6

Tear down staging

Destroys the staging KMS container. The measurement candidates and attestation artifacts are uploaded as workflow artifacts.

Required Secrets & Inputs

Secrets

PHALA_CLOUD_API_KEY
API key for provisioning/managing staging CVMs on Phala Cloud.
GH_RELEASE_TOKEN
GitHub token with read access to the mero-tee releases for fetching policy files.
COSIGN_KEY
Cosign private key for signing probe output artifacts.

Inputs

kms_version
The KMS release tag to probe (e.g. v0.4.0).
kms_image_digest
Full digest-pinned image reference for the KMS container.
profile
Target profile: debug, debug-read-only, or locked-read-only.
staging_cvm_id
Optional. Reuse an existing staging CVM instead of provisioning a new one.
Running the Probe Manually
1

Trigger via GitHub Actions

gh workflow run kms-phala-staging-probe.yaml \
  -f kms_version=v0.4.0 \
  -f kms_image_digest="ghcr.io/calimero-network/mero-kms-phala@sha256:abc123..." \
  -f profile=locked-read-only
2

Monitor execution

gh run watch

The workflow typically completes in 5–8 minutes. Watch for the “Probe Results” step output.

3

Download artifacts

gh run download <run-id> -n probe-artifacts

The artifact bundle contains measurement-policy-candidates.json, the compose hash, and signed attestation quotes.

Outputs
measurement-policy-candidates.json
Extracted MRTD, RTMR0–3 values and TCB status for the probed KMS instance. Formatted for direct insertion into the release policy file.
compose-hash.txt
SHA-256 hash of the Docker Compose configuration used. Enables reproducibility verification.
attestation-quote.bin
Raw TDX attestation quote from the staging KMS. Can be independently verified via ITA.
attestation-quote.json
Parsed attestation quote in JSON format with human-readable fields.
probe-report.md
Human-readable summary of the probe run including pass/fail status, timing, and measurement comparison.
Promotion Path to Release

After a successful probe, the measurement candidates follow this promotion path:

1

Probe completes successfully

Measurement candidates are extracted and uploaded as artifacts.

2

Policy promotion PR

Candidates are copied into kms-phala-attestation-policy.{profile}.json. A PR is opened (automatically by the probe workflow or manually).

3

Security review

Two approvals from the security team. Reviewers verify the diff matches expected measurement changes.

4

Merge & release

The merged policy is consumed by the next release build. The release workflow bundles the policy into the GitHub release assets.

KMS Policy Promotion

PR-based promotion of measurement candidates from the staging probe into the release attestation policy. The policy files are the source of truth for which TDX measurements the KMS will accept.

Purpose & Flow

The attestation policy defines which MRTD, RTMR, and TCB values are acceptable. Policy changes are always PR-governed — there is no backdoor for policy updates.

Files Touched

Each profile has its own policy file:

kms-phala-attestation-policy.debug.json
kms-phala-attestation-policy.debug-read-only.json
kms-phala-attestation-policy.locked-read-only.json

Automatic Flow (from staging probe)

1

Staging probe generates candidates

The kms-phala-staging-probe.yaml workflow extracts measurements and produces measurement-policy-candidates.json.

2

Workflow opens a PR

A follow-up job creates a branch, copies candidates into the profile-specific policy file, and opens a PR with the policy-promotion label.

3

CI validates the PR

A CI check verifies the policy JSON is syntactically valid, contains the required fields, and the measurements are well-formed hex strings of the correct length.

4

Human review & merge

Two security-team approvals required. After merge, the policy is picked up by the next release.

Manual Flow

When the automatic flow is unavailable or a manual override is needed:

1

Download probe artifacts

Fetch measurement-policy-candidates.json from the probe run artifacts.

2

Update policy file

Copy the measurement values into the appropriate kms-phala-attestation-policy.{profile}.json file. Ensure the JSON structure matches the existing format.

3

Open PR with policy-promotion label

The label triggers the CI validation check. Without the label, the policy-specific checks do not run.

4

Obtain reviews and merge

Same review requirements as the automatic flow: two security-team approvals.

Review Requirements
  • Two approvals from members of the @calimero-network/security team.
  • Reviewers must verify the measurement values in the diff match those in the probe report.
  • Any modification to the policy JSON structure (not just values) requires an additional architecture review.
  • The policy-promotion label must be present for CI checks to run.
  • Merge is blocked until all CI checks pass and reviews are obtained.

Node Image GCP Policy Promotion

Publishes measured MRTD and RTMR values from probe VMs to the release, enabling runtime verification of deployed GCP confidential VMs.

Purpose

When a new GCP node image is built, a probe VM is launched from the image, and its TDX measurements are extracted. These measurements are the canonical reference for verifying that production VMs are running the expected code. The promotion workflow publishes these measurements as published-mrtds.json in the GitHub release.

Promotion Inputs
measurement-policy-candidates
JSON file containing MRTD and RTMR0–3 values extracted from the probe VM, keyed by profile. Generated by the release pipeline’s probe stage.
release_tag
The mero-tee release tag (e.g. mero-tee-v0.3.0) to attach the MRTD file to.
image_family
The GCP image family name that was probed (e.g. mero-tee-locked-read-only).
What It Does
1

Validate measurement candidates

Checks the input JSON for required fields, correct hex encoding, and expected lengths (MRTD: 48 bytes, RTMRs: 48 bytes each).

2

Assemble published-mrtds.json

Merges per-profile measurements into a single published-mrtds.json file with metadata (release tag, timestamp, image family).

3

Upload to GitHub release

Attaches published-mrtds.json to the specified release tag using gh release upload. Also updates the checksums file.

4

Sign the updated checksums

Re-signs checksums.txt with cosign to include the hash of the newly uploaded MRTD file.

Architecture Decision Records

Key architectural decisions governing attestation policy management, versioning, and release processes.

ADR-0001 KMS Profile Pinning

Context

The KMS must serve exactly one profile at a time. Misconfiguring the profile breaks cohort separation — a debug KMS could accidentally release keys to production nodes, or vice versa.

Decision

Pinned profile file + reject KMS_POLICY_PROFILE override

The KMS reads its profile from a pinned file (/etc/mero-kms/image-profile) baked into the container image at build time. The MERO_KMS_PROFILE environment variable is validated against the pinned file. If they disagree, the KMS refuses to start. This prevents accidental profile mismatches in deployment configurations.

Consequences

  • Each profile requires a separate KMS container image (already the case for measurement integrity).
  • Operators cannot override the profile at runtime — they must deploy the correct image.
  • Startup fails loudly on mismatch, preventing silent policy violations.
ADR-0002 Release Policy Source of Truth

Context

Attestation policy must be versioned, auditable, and tamper-evident. Multiple sources of truth (environment variables, config files, hardcoded values) create confusion and risk.

Decision

PR-governed policy files consumed at release

The canonical attestation policy lives in version-controlled JSON files (kms-phala-attestation-policy.{profile}.json) in the mero-tee repository. Changes require a PR with security-team review. The release workflow bundles these files into GitHub release assets, which the KMS fetches at startup.

Consequences

  • Policy changes are auditable via git history and PR reviews.
  • No out-of-band policy updates — all changes go through the PR process.
  • The USE_ENV_POLICY escape hatch exists for development but is blocked in production by CI checks.
  • Policy is immutable once released — changing it requires a new release.
ADR-0003 Version Sync Guard

Context

KMS and node image versions are tightly coupled. A KMS update may change measurements, requiring a corresponding policy update. Deploying one without the other creates a window where attestation fails.

Decision

Coupled KMS/node version bumps with CI guard

A CI check enforces that when the KMS version or node image version is bumped, the other is either bumped simultaneously or explicitly marked as unchanged. The check inspects the PR diff for version-related files and blocks merge if coupling constraints are violated.

Consequences

  • Prevents accidental partial rollouts where KMS and node versions are mismatched.
  • Adds friction to version bumps — both components must be considered even for single-component changes.
  • The CI guard can be overridden with a skip-version-sync label for genuine single-component updates, requiring a justification comment.
  • Release notes must document the version coupling for each release.