Skip to content

5.10.2.3 Signing

The Signing domain of releases. The trust chain clients verify: the public keys of the TUF roles, whose private halves live in Cloud KMS, and the signed metadata documents with their signatures. Staff register, rotate and revoke keys but never sign: the system signs when a release becomes active. Clients fetch metadata by role. It is one API, with its own contract and its own version.

5.10.2.3.1 Versions

Version Status Prod URL Contract
v1 Proposed https://releases.moonitoring.com/signing/v1 signing/v1/openapi.yaml

The resources follow the data model. Adds the client reads of the TUF documents by role, which carry the signed and signatures JSON as the client verifies it.

5.10.2.3.2 Operations

Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.

Operation Request Who Capability
List signing keys GET /signing-keys Staff releases.releases.read
Register a signing key POST /signing-keys Staff releases.release_keys.manage
Rotate a signing key POST /signing-keys/{key_id}/rotate Staff releases.release_keys.manage
Revoke a signing key POST /signing-keys/{key_id}/revoke Staff releases.release_keys.manage
List encryption keys GET /encryption-keys Staff releases.releases.read
Register an encryption key POST /encryption-keys Staff releases.release_keys.manage
Rotate an encryption key POST /encryption-keys/{key_id}/rotate Staff releases.release_keys.manage
List signed metadata GET /signed-metadata Staff releases.releases.read
List a document's signatures GET /signed-metadata/{metadata_id}/signatures Staff releases.releases.read
Fetch the current metadata of a role GET /applications/{application_id}/channels/{channel_id}/metadata/{role} Installed clients none
Fetch a root version GET /applications/{application_id}/channels/{channel_id}/metadata/root/{version} Installed clients none

5.10.2.3.3 Contract v1

Proposed version

v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.

5.10.2.3.4 Rules Confirmed with the Implementation

Decided on 2026-11-05, from the choices made while building releases:

  • Lifetimes: root 365 days, targets 90, snapshot 30, timestamp 7. The sweeper renews each document two days before it expires, every hour, and alerts when a renewal fails: a timestamp that lapses stops every update.
  • The first root of a channel is signed by the sweeper as soon as the channel has registered keys, before its first release (decided 2026-11-10), so an installer can pin it from the start; it is root version 1, read by GET /applications/{application_id}/channels/{channel_id}/metadata/root/1.
  • Formats: a key id is the SHA-256 of the canonical JSON of the key object; a signature is hex DER ECDSA over the canonical JSON of signed; the targets document names <depot>/<manifest content hash>.manifest with the blob's length and SHA-256, and the release in custom.
  • Rotating an encryption key creates the new key from the input and marks the old one rotated_at; content encrypted with the old key stays readable.