Files
yovision/contracts/machine-identity/v1/README.md
T

4.5 KiB

Machine identity contract v1

yovision.machine-identity/v1 defines service-to-service identity for YoVision connectors. It is deliberately separate from Sense and Bell users, GoAdmin JWT/Cookie state, database roles and operating-system accounts.

Authentication mechanism

Every request uses HTTPS and one compact Ed25519 JWS in Authorization: Bearer <token>. The protected header is closed and contains alg=EdDSA, typ=YOVISION-MACHINE+JWT, kid and ver=yovision.machine-identity/v1. The closed claims object contains:

mTLS is not the primary v1 identity mechanism. A customer PKI may add mTLS later as transport hardening, but it cannot replace or weaken the v1 principal, audience, scope, request binding, replay and revocation checks.

  • one instance-specific iss/sub principal;
  • one exact service aud;
  • the minimum required scope values;
  • iat, nbf, exp and a single-use random jti;
  • uppercase HTTP method htm, normalized absolute-path reference htu, and lowercase SHA-256 body_sha256.

Tokens live for at most 300 seconds. Consumers allow at most 30 seconds of clock skew, verify the signature and active key/principal before authorization, then atomically consume jti until exp + skew. Retrying transport creates a new token and jti; business idempotency keys remain unchanged.

Production consumers persist the replay key (principal, jti) in their own durable store so a process restart cannot reopen the replay window. The checked-in process-local replay stores are adapter test/default primitives only; connector tasks must inject an atomic durable implementation and test restart behavior without sharing a database across products.

The v1 scopes are:

Caller Audience Scope
Sense yovision-brain source-config:write
Brain yovision-sense runtime-status:write
Brain or Sense yovision-bell events:ingest
Bell yovision-sense evidence:read

No wildcard audience or scope exists. A relay authenticates as its own transport principal and never replaces the original event producer identity.

Key lifecycle

Private Ed25519 keys are generated per product instance and stored outside the repository in an OS-protected file or secret store. Runtime configuration contains only the private-key path. Public registries are local consumer configuration, not a shared database.

Rotation first registers a new kid, switches the caller, and removes the old key after an overlap no longer than 24 hours. A disabled principal or revoked kid is rejected on every request, including tokens that have not expired. Emergency rollback disables the connector; it never enables a shared password, browser token, query token, plaintext transport or signature bypass.

Threat boundary

v1 protects against token modification, wrong audience/scope, expired or premature tokens, captured-token replay, key/principal revocation and accidental credential mixing. It does not protect a host after administrator/root compromise, a stolen usable private key before revocation, compromised TLS trust roots, endpoint implementation flaws or denial of service. Rate and body-size limits remain consumer responsibilities.

See ../transport/v1/README.md for HTTPS and request policy. Stable failures are defined in errors.md; callers and logs must expose only the stable code, principal/kid when already authenticated, and correlation ID—never the token, signature, private/public key material or complete Authorization header.

Compatibility

v1 is closed. New optional claims require all consumers to accept them before producers emit them. Any change to signing input, algorithm, claim meaning, replay semantics, maximum lifetime, audience or scope meaning publishes a new major version. Consumers keep the last accepted major during a controlled migration; rollback disables the new producer version without weakening verification.

Reproducible verification

From the repository root:

pwsh -NoProfile -File contracts/tests/machine-identity-v1/run.ps1

cd Sense/server
go test -race ./app/sense/integration/machine_identity

cd ../../Bell/server
go test -race ./app/bell/integration/machine_identity

The isolated contract test validates both JSON Schemas, the fixed Go/Python Ed25519 vector, request binding, exact audience/scope, expiry, replay, rotation overlap, revocation, bearer-only extraction and verified TLS policy. Product connector tasks remain responsible for injecting a durable replay store and testing restart recovery.