# Registry Token Service Operations _Component_: `src/Registry/StellaOps.Registry.TokenService` The registry token service issues short-lived Docker registry bearer tokens after validating an Authority OpTok (DPoP/mTLS sender constraint) and the customer’s plan entitlements. It is fronted by the Docker registry’s `Bearer realm` flow. ## Configuration Configuration lives in `etc/registry-token.yaml` and can be overridden through environment variables prefixed with `REGISTRY_TOKEN_`. Key sections: | Section | Purpose | | ------- | ------- | | `authority` | Authority issuer/metadata URL, audience list, and scopes required to request tokens (default `registry.token.issue`). | | `signing` | JWT issuer, signing key (PEM or PFX), optional key ID, and token lifetime (default five minutes). The repository ships **`etc/registry-signing-sample.pem`** for local testing only – replace it with a private key generated and stored per-environment before going live. | | `registry` | Registry realm URL and optional allow-list of `service` values accepted from the registry challenge. | | `plans` | Plan catalogue mapping plan name → repository patterns and allowed actions. Wildcards (`*`) are supported per path segment. | | `defaultPlan` | Applied when the caller’s token omits `stellaops:plan`. | | `revokedLicenses` | Blocks issuance when the caller presents a matching `stellaops:license` claim. | Plan entries must cover every private repository namespace. Actions default to `pull` if omitted. ## Request flow 1. Docker/OCI client contacts the registry and receives a `401` with `WWW-Authenticate: Bearer realm=...,service=...,scope=repository:...`. 2. Client acquires an OpTok from Authority (DPoP/mTLS bound) with the `registry.token.issue` scope. 3. Client calls `GET /token?service=&scope=repository::` against the token service, presenting the OpTok and matching DPoP proof. 4. The service validates the token, plan, and requested scopes, then issues a JWT containing an `access` claim conforming to the Docker registry spec. All denial paths return RFC 6750-style problem responses (HTTP 400 for malformed scopes, 403 for plan or revocation failures). ## Monitoring The service emits OpenTelemetry metrics via `registry_token_issued_total` and `registry_token_rejected_total`. Suggested Prometheus alerts: | Metric | Condition | Action | |--------|-----------|--------| | `registry_token_rejected_total` | `increase(...) > 0` over 5 minutes | Investigate plan misconfiguration or licence revocation. | | `registry_token_issued_total` | Sudden drop compared to baseline | Confirm registry is still challenging with the expected realm/service. | Enable the built-in `/healthz` endpoint for liveness checks. Authentication and DPoP failures surface via the service logs (Serilog console output). ## Sample deployment ```bash dotnet run --project src/Registry/StellaOps.Registry.TokenService \ --urls "http://0.0.0.0:8085" curl -H "Authorization: Bearer " \ -H "DPoP: $(dpop-proof ...)" \ "http://localhost:8085/token?service=registry.localhost&scope=repository:stella-ops/public/base:pull" ``` Replace `` and `DPoP` with tokens issued by Authority. The response contains `token`, `expires_in`, and `issued_at` fields suitable for Docker/OCI clients.