Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Internal / Gossip API

These endpoints carry inter-node CRDT replication traffic. They are served on the same port as the public OAuth2/OIDC endpoints and protected at the application layer — port-level firewall rules cannot isolate them without also blocking public clients.


Endpoints

MethodPathDescription
POST/api/gossip/syncAccept an incoming CRDT gossip push from a peer node. The body is a CMS SignedData(EnvelopedData) blob (ECDSA P-256 outer signature, ML-KEM-768 inner encryption). The receiver verifies the signature, decrypts, applies admission filters, merges the CRDT, and replies with its own state (delta or full, based on the request_delta_since field in the inbound envelope) in the same CMS format.
GET/api/gossip/kem-infoReturn this node’s ML-KEM-768 public key (base64url SPKI DER) and node_id. Unauthenticated. Returns 404 Not Found with {"registered": false} when this node has no CRDT entry yet (i.e. the node has not yet completed its first gossip round); callers should treat 404 as “not yet registered”.
GET/api/gossip/wrapping-keyReturn the cluster AEAD wrapping key sealed to the requester’s ML-KEM-768 public key (SignedData(EnvelopedData) DER, application/pkcs7-mime). The requester identifies itself via the X-Ahdapa-Node-Id header and must have a KEM key already in the CRDT. Unauthenticated at the HTTP level; confidentiality is ensured by the ML-KEM-768 encryption — the blob is useless without the requester’s private key.
POST/api/gossip/register-kemKerberos-authenticated self-registration of both the ML-KEM-768 public key and the ECDSA P-256 gossip signing public key. An IPA-enrolled peer presents Authorization: Negotiate <kerberos-token> (Kerberos AP-REQ for the local HTTP service) and a JSON body {"node_id":"<hostname>","kem_public_key_der":"<base64url-SPKI>","gossip_signing_pub_key_der":"<base64url-SPKI>"}. All three fields are required; missing or empty fields return 400. The server validates that the authenticated principal is HTTP/<hostname>@<REALM>, that node_id matches <hostname>, and (when gossip.kerberos_realm is set) that the principal’s realm matches. Both keys are stored in the CRDT in a three-case match: insert-fresh, upsert-signing-key-only, or no-op (both already present). Returns 503 when the GSSAPI server credential is unavailable or when the DB persist fails; 401 with WWW-Authenticate: Negotiate when no token is presented or invalid; 400 when required fields are missing; 403 on principal or allowlist rejection; and 200 OK on success.
GET/api/gossip/statsReturn runtime gossip statistics for this node. Unauthenticated. Returns a JSON object with node_id, crdt_generation, per-collection live counts under counts, configured and topology-discovered peers, active_signing_kid, kem_enrolled, gossip_signing_enrolled, and a gossip sub-object with started_at, rounds_completed, last_round_at, peer_last_sync (map of peer node_id → last inbound sync unix timestamp), persist_errors, and wrapping_key_pull_errors. See Gossip Protocol — Node statistics endpoint for the full response schema.

Access control

Gossip endpoints are protected by two independent mechanisms at the application layer. A rogue client that can reach the server port gains nothing from these endpoints without the corresponding cryptographic keys.

CMS authentication and encryption (/api/gossip/sync, /api/gossip/wrapping-key)

Every gossip sync payload is a CMS SignedData(EnvelopedData) structure:

  • The outer ECDSA P-256 signature is verified against the sender’s pinned gossip signing key stored in the CRDT. A node whose key is not pinned receives 401 Unauthorized regardless of the payload contents.
  • The inner ML-KEM-768 encryption is addressed to the receiving node’s public key. The encrypted payload is opaque to any party that does not hold the private key.

For /api/gossip/wrapping-key, the requester’s X-Ahdapa-Node-Id must match a node_id in the admission allowlist (see below); the response is itself an EnvelopedData blob encrypted to the requester’s ML-KEM-768 key, so the cluster wrapping key is never transmitted in the clear.

Node admission allowlist (allowed_node_ids)

The [gossip] section of the configuration controls which node_ids are permitted to exchange CRDT state:

[gossip]
# Static allowlist.  Only node_ids listed here may participate.
allowed_node_ids = ["ipa1.example.com", "ipa2.example.com"]

When ipa_topology = true, the allowlist is extended automatically with all replica hostnames discovered from the IPA replication topology, and updated every ipa_topology_interval_secs seconds. Entries from the static list and the topology-derived list are merged; the union fails closed — a node_id absent from both is denied.

Kerberos authentication (/api/gossip/register-kem)

Self-registration requires a valid Kerberos AP-REQ for the local HTTP service. Only HTTP/<hostname>@<REALM> service principals are accepted; user principals are rejected. When gossip.kerberos_realm is set, cross-realm principals are also rejected. The authenticated hostname is validated against the submitted node_id and against the allowlist before any key material is stored.

See Multi-node Cluster and Gossip Protocol for operational details.