Skip to content

Replication cert lookup misses an IPv6-literal node identity (compact vs OpenSSL-expanded SAN key) #2261

Description

@dawsontoth

Summary

When a node's identity is a bare IPv6 literal (e.g. node.hostname: 2001:db8::1), getReplicationCert() cannot find that node's own certificate, because the lookup key and the stored key use different IPv6 spellings.

security/keys.ts:128 looks the context up by the identity string:

const cert = secureTarget.secureContexts.get(getThisNodeName());

getThisNodeName() returns the compact form (2001:db8::1), while secureContexts is keyed from certificate SAN text parsed out of the cert, and OpenSSL/X509 renders IPv6 SANs expanded (2001:DB8:0:0:0:0:0:1; ::1 becomes 0:0:0:0:0:0:0:1). The two never match, so the get returns undefined.

Impact

  • getReplicationCert() resolves empty for an IPv6-literal identity.
  • reviewSelfSignedCert() then treats the existing certificate as absent and regenerates it on every startup.
  • getReplicationCertAuth() (security/keys.ts:139(await getReplicationCert()).options.cert) can dereference an absent result.

Failure is silent in normal logs — the node looks healthy until replication TLS misbehaves — which is what makes it worth tracking rather than leaving as folklore.

Scope is narrow: it needs the node identity to be a bare IPv6 literal. A hostname or IPv4 identity is unaffected.

Not a regression

This is a pre-existing limitation of the cert lookup, not something #2223 introduced. It was surfaced by the cross-model review of #2223, which makes IPv6-literal identities viable (canonicalizing identity to the unbracketed form and bracketing only for URL construction) and therefore reachable. #2223 deliberately scoped this out, since fixing it means changing cert-context keying rather than identity resolution.

Suggested fix

Canonicalize IP keys identically on both insertion and lookup — normalize an IPv6 literal to one canonical form on both sides (e.g. via net.isIP + a shared normalizer, cf. normalizeIPv6 in resources/analytics/hostnames.ts) — or locate the replication context by its certificate-record name instead of by SAN text.

Worth adding a generate → parse → getReplicationCert() test over an IPv6 identity, since that path currently has no end-to-end coverage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    P2

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions