diff --git a/adr/0021-multiple-identities-alsoknownas.md b/adr/0021-multiple-identities-alsoknownas.md new file mode 100644 index 0000000..b8824c6 --- /dev/null +++ b/adr/0021-multiple-identities-alsoknownas.md @@ -0,0 +1,83 @@ +# ADR 0021: Support Multiple Identities via `alsoKnownAs` in the Trust Manifest + +## Status +Proposed + +## Date +2026-07-24 (Proposed) + +**Participants:** Alexander Shenshin (DSR Corporation), Darrel Miller (Microsoft), Jeffrey Damick (Amazon), Junjie Bu (Google), Ramiz Polic (Cisco), Sam Betts (Cisco) + +## Context +A catalog entry can declare exactly one cryptographic identity through the `trustManifest.identity` field (with an optional `identityType` hint). Real artifacts frequently hold more than one verifiable identity at the same time, for example: + +- a SPIFFE ID (`spiffe://acme.com/ns/finance/sa/finance-a2a-pod`) for runtime/workload identity, and +- a DID (`did:web:acme-corp.com`) for organizational/publisher-anchored identity. + +There is no first-class place to list additional identities. Authors are forced to add them through `attestations[]` or `metadata`, where consumers do not reliably look for them and cannot treat them as verifiable subject identities ([issue #52](https://github.com/Agent-Card/ai-catalog/issues/52)). The workarounds are inadequate: + +- **Attestations are limiting.** An `Attestation` is a typed claim with evidence, designed for compliance documents. There is no standard attestation type meaning "this is another identity of the same subject", so alternate identities cannot be discovered or pinned programmatically. +- **Metadata is opaque.** Per the spec, consumers SHOULD ignore metadata keys they do not recognize, so a second identity placed there is invisible and non-interoperable. +- **Conflicts with the domain-alignment rule.** The rule binding the `identity` trust domain to the publisher domain of the entry's `identifier` is written for a single identity and gives no guidance for identities in other trust domains. + +Use cases requiring multiple identities include: co-equal runtime and publisher identities, relying parties that can only resolve a subset of identity schemes, and migration/rotation between identity schemes without breaking existing consumers. + +A key constraint shaped this decision: **declared identities MUST be verifiable through the trust bundle.** An identity claim a consumer cannot verify is worse than no claim at all. + +## Decision +The Trust Manifest gains an OPTIONAL `alsoKnownAs` member: an array of Identity Alias objects, each asserting an alternative identity of the **same subject** as the canonical `identity` field through a REQUIRED `identity` URI and an OPTIONAL `identityType` hint. + +```json +"trustManifest": { + "identity": "spiffe://acme.com/ns/finance/sa/finance-agent-pod", + "identityType": "spiffe", + "alsoKnownAs": [ + { + "identity": "did:web:acme-corp.com:agent:finance", + "identityType": "did" + } + ], + "signature": "eyJhbGciOiJFUzI1NiJ9..detached-jws-signature" +} +``` + +Normative rules: + +1. `identity` remains the single **canonical** subject identifier, used for referencing and equivalence checking. Aliases are co-equal for verification purposes but never canonical. Aliases MAY also record former identifiers of the subject, preserving continuity after a rename or a migration between identities or schemes. +2. `alsoKnownAs` MUST NOT contain two aliases with the same `identity` value, and no alias `identity` may equal the canonical `identity`; element order carries no significance. +3. Each alias MAY carry its own `identityType` hint, OPTIONAL when the type is evident from the URI scheme. The top-level `identityType` describes only the canonical `identity`. +4. The domain-alignment rule applies only to `identity`. Aliases MAY belong to different trust domains or identity schemes. +5. Aliases are publisher claims verified through the existing Trust Manifest `signature`, which covers `alsoKnownAs` as manifest content. Consumers MUST NOT rely on an alias from a manifest whose signature is absent or fails verification. Because the signature proves the publisher claims the alias (not that the alias's trust domain acknowledges the link), authorization decisions inside the alias's trust domain SHOULD additionally rely on proof of control native to the alias scheme (e.g., a DID Document back-reference or DNS TXT record); such proofs are out of scope. +6. A consumer MAY select any verified identity, canonical or alias, matching the schemes it can resolve, rather than rejecting an entry whose canonical identity uses an unsupported scheme. Signature verification itself always keys off the canonical `identity`. + +### Placement: inside the Trust Manifest, not on the Catalog Entry +We explicitly considered placing `alsoKnownAs` on the parent Catalog Entry (as a sibling of `identifier`) and rejected it: + +- **Signature coverage is decisive.** The Trust Manifest is the only signed unit in the specification, the detached JWS is computed over the JCS-canonicalized manifest content. Fields on the Catalog Entry are not covered by any signature, so under the spec's catalog-poisoning threat model an attacker who can modify the catalog document could inject or strip entry-level aliases undetected. Inside the manifest, aliases are forgery-proof at trust Layer 2, satisfying the "verifiable through the trust bundle" constraint. +- **Separation of concerns (ADR-0015).** The entry's `identifier` is a logical *name* (`urn:air:...`) for discovery and routing; cryptographic *identities* live in the Trust Manifest. Alternative identities are identities, so they belong beside `identity`, not beside the URN. +- **Ecosystem precedent.** W3C DID Core defines `alsoKnownAs` on the DID Document with the same publisher-asserted, same-subject semantics adopted here. (DID Core uses plain URIs; this specification adopts a structured object so each alias can carry an explicit `identityType` hint, mirroring the canonical `identity`/`identityType` pair.) +- **Reuse for hosts.** Host Info carries a `trustManifest` too, so hosts gain multi-identity support without adding a new field to two parent structures. + +The trade-off is that entries without a Trust Manifest cannot declare aliases. This is acceptable because an alias outside the trust bundle would be unverifiable by construction. + +## Rationale +- **Interoperability**: A standard, first-class shape means consumers can programmatically discover alternate identities instead of relying on per-publisher attestation or metadata conventions. +- **Simple equivalence checking**: Keeping a single canonical `identity` avoids forcing consumers to choose which of N identities "names" the entry. +- **Backward compatible**: `alsoKnownAs` is OPTIONAL and additive. Existing manifests remain valid; existing consumers that ignore the field lose nothing they had before. +- **Verifiability by construction**: Because the field lives inside the signed manifest content, no new signing mechanism is needed, the existing JCS + detached JWS procedure covers it. + +## Alternatives Considered +- **`identities[]`: an array of co-equal Identity objects** (each with `identity`, `identityType`, and optionally its own `signature`). Rejected: it makes equivalence checking harder, forces consumers to choose which identity to use when referencing the entry, and multiplies signature-verification paths. The variant dropping the primary `identity` entirely was also rejected as a breaking change to the existing spec. The adopted Identity Alias object retains the `identity`/`identityType` pair per alias, but keeps a single canonical `identity` and a single signature path. +- **`alsoKnownAs` as a plain URI array** (the W3C DID Core shape). Rejected: consumers would have to infer each alias's type from its URI scheme alone, which is ambiguous for schemes shared by multiple identity types (e.g., an `https:` URI may point to a JWK Set or be a `did:web` equivalent), and inconsistent with the explicit `identityType` hint available for the canonical identity. +- **`trustManifests[]`: multiple Trust Manifests per entry.** Fully independent trust metadata per identity (separate attestations, provenance, signatures). Rejected as disproportionate: the motivating use cases need equivalent identities for one subject, not parallel trust bundles, and multiple manifests reintroduce the "which manifest is authoritative?" problem at a larger scale. +- **`alsoKnownAs` on the Catalog Entry (parent structure).** Rejected for the placement reasons above, mainly that entry-level fields fall outside the signed trust bundle and therefore cannot satisfy the verifiability requirement. +- **Status quo (attestations/metadata workarounds).** Rejected as non-interoperable and non-verifiable, per the Context section. + +## Consequences +- **Specification**: The Trust Manifest optional members, verification procedures (new "Verifying Alternative Identities" section), CDDL schema, data model diagram, and examples are updated. +- **Consumers**: Clients that verify Trust Manifest signatures automatically gain tamper-proof alias coverage. Clients unaware of the field are unaffected. +- **Publishers**: Publishers currently smuggling secondary identities through `attestations[]` or `metadata` SHOULD migrate them to `alsoKnownAs`. +- **Future work**: If per-alias proofs become necessary (e.g., alias-side attestations or inline alias-specific signatures), they can be added as OPTIONAL members of the Identity Alias object without breaking the existing form. + +## Meeting Reference +Proposed from [issue #52](https://github.com/Agent-Card/ai-catalog/issues/52) discussion; `alsoKnownAs` was favored over an identities array in issue comments (2026-07). Update the Status and Date once the working group ratifies it. diff --git a/docs/guides/adding-trust.md b/docs/guides/adding-trust.md index 5c630cc..4c6fa8a 100644 --- a/docs/guides/adding-trust.md +++ b/docs/guides/adding-trust.md @@ -75,6 +75,7 @@ All other fields are optional: | Field | Description | |---|---| | `identityType` | Type hint for the identity URI: `"did"`, `"spiffe"`, `"dns"` | +| `alsoKnownAs` | Array of Identity Alias objects declaring alternative identities of the same subject | | `trustSchema` | Describes the trust framework applied | | `attestations` | Array of compliance and identity attestation objects | | `provenance` | Array of provenance links (source code, OCI digests) | diff --git a/specification/ai-catalog.md b/specification/ai-catalog.md index b8b3837..d70cead 100644 --- a/specification/ai-catalog.md +++ b/specification/ai-catalog.md @@ -526,6 +526,16 @@ payload, rather than inferred only from unsigned entry context. When a Trust Manifest appears on a Host Info object, `identity` SHOULD match the host's `identifier` field when present. +An artifact may legitimately hold more than one verifiable identity at +the same time, for example a SPIFFE ID for runtime workload identity +and a DID for publisher-anchored organizational identity, or it may +retain a former identifier after a rename or migration between +identities or schemes. Additional identities are declared through the +OPTIONAL `alsoKnownAs` member (see [Optional Members](#optional-members)). +The `identity` field remains the single canonical subject identifier: +consumers MUST use `identity` when referencing the artifact's trust +subject or checking identity equivalence between entries. + When multiple entries share the same `identifier` (with different `version` values), each entry MAY carry its own Trust Manifest. There is no requirement that all versions carry identical trust metadata — trust @@ -561,9 +571,46 @@ present. The following members are OPTIONAL: `identityType` -: A string providing a type hint for the identity URI (e.g., "did", +: A string providing a type hint for the `identity` URI (e.g., "did", "spiffe", "dns"). This field is OPTIONAL when the type is evident - from the URI scheme. + from the URI scheme. It describes only `identity`; each entry of + `alsoKnownAs` carries its own `identityType` member. + +`alsoKnownAs` +: An array of Identity Alias objects, each asserting an identity of + the same subject as `identity` under an alternative identity + scheme. An Identity Alias object MUST contain: + + `identity` + : A string containing a globally unique URI [[RFC3986]] that + identifies the same subject as the manifest's canonical + `identity`. + + An Identity Alias object MAY contain: + + `identityType` + : A string providing a type hint for the alias `identity` URI + (e.g., "did", "spiffe", "dns"). This member is OPTIONAL when + the type is evident from the URI scheme. + + The following rules apply: + + - An alias is an equivalent identity of the subject; the + manifest's `identity` alone remains canonical and is used for + referencing and equivalence checking. Aliases MAY also record + former identifiers of the subject, preserving continuity after + a rename or a migration between identities or schemes. + - The array is an unordered set: it MUST NOT contain two aliases + with the same `identity` value, and no alias `identity` may + equal the manifest's canonical `identity`. + - The domain-alignment rule defined in [Identity](#identity) + applies only to the canonical `identity`. Aliases MAY belong to + different trust domains or identity schemes. + - Aliases are publisher claims covered by the Trust Manifest + `signature`; no per-alias proof is required. Consumers MUST NOT + rely on an alias from a manifest whose signature is absent or + fails verification (see + [Verifying Alternative Identities](#verifying-alternative-identities)). `trustSchema` : A Trust Schema object as defined in [Trust Schema](#trust-schema-object). @@ -621,6 +668,12 @@ provenance: { "identity": "did:web:acme.com:agent:finance", "identityType": "did", + "alsoKnownAs": [ + { + "identity": "spiffe://acme.com/ns/finance/sa/finance-agent-pod", + "identityType": "spiffe" + } + ], "trustSchema": { "identifier": "urn:trust:acme-enterprise-v1", "version": "1.0", @@ -972,6 +1025,34 @@ Manifest signature. Consumers MUST treat `publisher` fields as advisory unless a verified `publisher-identity` attestation cryptographically binds `publisher.identifier` to the signed manifest's `identity`. +### Verifying Alternative Identities + +Aliases need no verification procedure of their own. Because the +signed payload covers `alsoKnownAs`, verifying the Trust Manifest +`signature` as described in +[Trust Manifest Signatures](#trust-manifest-signatures) also verifies +every listed alias: a valid signature proves that the publisher +controlling the canonical `identity` claims each alias as an +equivalent identity of the subject. Consumers MUST NOT rely on aliases +from a manifest whose signature is absent or fails verification. + +Signature verification itself always keys off the canonical identity: +the verification key is resolved from `identity` as described in +[Trust Manifest Signatures](#trust-manifest-signatures). A consumer +that cannot resolve the canonical identity scheme cannot verify the +signature and therefore cannot rely on any alias. + +Once the signature is verified, a consumer MAY use whichever identity, +canonical or alias, fits the identity schemes its tooling operates +on. For example, after verifying the signature through a resolvable +canonical DID `identity`, the consumer can use a SPIFFE ID alias to +match the artifact's runtime workload identity. + +Note that the signature proves the publisher claims the alias, not +that the alias's own trust domain acknowledges the link. Consumers +making authorization decisions inside the alias's trust domain MAY +additionally obtain proof of control native to the alias scheme. + ### Verifying Artifact Integrity When a Trust Manifest carries a `signature`, it MUST include a `subject` @@ -1537,6 +1618,7 @@ classDiagram class TrustManifest { identity string subject Subject + alsoKnownAs IdentityAlias[] trustSchema TrustSchema attestations Attestation[] provenance ProvenanceLink[] @@ -1548,6 +1630,10 @@ classDiagram type string digest string } + class IdentityAlias { + identity string + identityType string + } class TrustSchema { identifier string version string @@ -1569,6 +1655,7 @@ classDiagram CatalogEntry --> "0..1" TrustManifest : trustManifest HostInfo --> "0..1" TrustManifest : trustManifest TrustManifest --> "0..1" Subject : subject + TrustManifest --> "*" IdentityAlias : alsoKnownAs TrustManifest --> "0..1" TrustSchema : trustSchema TrustManifest --> "*" Attestation : attestations TrustManifest --> "*" ProvenanceLink : provenance @@ -1709,6 +1796,7 @@ Publisher = { TrustManifest = { identity: text, ? identityType: text, + ? alsoKnownAs: [* IdentityAlias], ? trustSchema: TrustSchema, ? attestations: [* Attestation], ? provenance: [* ProvenanceLink], @@ -1718,6 +1806,11 @@ TrustManifest = { ? extensions: { * text => any } } +IdentityAlias = { + identity: text, + ? identityType: text +} + TrustSchema = { identifier: text, version: text, @@ -1771,6 +1864,12 @@ artifact types including a nested catalog packaging related artifacts: "trustManifest": { "identity": "spiffe://acme.com/ns/finance/sa/finance-a2a-pod", "identityType": "spiffe", + "alsoKnownAs": [ + { + "identity": "did:web:acme-corp.com:agent:finance-a2a", + "identityType": "did" + } + ], "attestations": [ { "type": "publisher-identity", diff --git a/specification/respec-config.json b/specification/respec-config.json index 50c40ea..73702bd 100644 --- a/specification/respec-config.json +++ b/specification/respec-config.json @@ -3,7 +3,15 @@ "shortName": "ai-catalog", "edDraftURI": "https://ai-catalog.io/", "abstract": "This document defines the AI Catalog, a JSON format for discovering heterogeneous AI artifacts such as MCP servers, A2A agents, Claude Code plugins, datasets, and model cards. Each catalog entry declares the artifact's type via a media type and references or inlines the native artifact metadata, enabling a single discovery mechanism across protocols and platforms. The specification defines three conformance levels — Minimal, Discoverable, and Trusted — allowing implementations to start with a simple list of entries and progressively add host identity, well-known URI discovery, and verifiable trust metadata as needed. An optional Trust Manifest extension provides identity binding, compliance attestations, provenance tracking, and cryptographic signatures without wrapping or modifying the artifact's native format. Informative appendices define a substrate-neutral distribution-mapping contract and concrete bindings to OCI distribution registries and xRegistry, plus mappings to the MCP Registry server.json format and the Claude Code Plugins marketplace.", - "appendixHeaders": ["Data Model", "CDDL", "Example", "Mapping", "Acknowledgment", "Appendix", "IANA"], + "appendixHeaders": [ + "Data Model", + "CDDL", + "Example", + "Mapping", + "Acknowledgment", + "Appendix", + "IANA" + ], "localBiblio": { "xRegistry": { "title": "xRegistry: A Universal Registry Specification", @@ -11,6 +19,12 @@ "status": "Draft", "publisher": "CNCF" }, + "RFC3986": { + "title": "Uniform Resource Identifier (URI): Generic Syntax", + "href": "https://www.rfc-editor.org/rfc/rfc3986", + "status": "RFC", + "publisher": "IETF" + }, "RFC8785": { "title": "JSON Canonicalization Scheme (JCS)", "href": "https://www.rfc-editor.org/rfc/rfc8785",