Ankusa.Verifier.ClientCert (ankusa v0.7.0)

Copy Markdown View Source

The sender is whoever holds the client certificate the edge listener's mutual TLS handshake accepted (tls.verify: :verify_peer, Ankusa.Listener), for providers and internal systems that authenticate by certificate rather than by signing the body. Like Ankusa.Verifier.Token it says who is calling, not what the body is.

opts, at least one of:

  • :fingerprints — SHA-256 fingerprints of the DER certificates that may post to this source: 64 hex characters, any case, optional : separators (what openssl x509 -fingerprint -sha256 prints). A pin holds whatever the listener's CA bundle says.
  • :subjects — identities a certificate may carry, in the form Ankusa.Admin.Auth.MTLS.identities/1 produces: dns:<name>, email:<address>, uri:<uri>, ip:<address> (subject alternative names) or cn:<common name>. A subject pin trusts the listener's CA to have issued that identity only to the party meant: scope the listener's cacertfile to a CA that does, or pin fingerprints instead.

A certificate matching either list is accepted. Neither list set, a malformed fingerprint or a subject without a known prefix is :bad_pin for every hook, and a source declared in config refuses to boot (also when the edge listener has no verify: :verify_peer: without it no certificate ever arrives, see Ankusa.Verifier.validate_config!/1).

The certificate arrives as opts[:peer_cert], the DER the TLS handshake accepted (Plug.Conn.get_peer_data/1's :ssl_cert), put there by Ankusa.Edge.Router for a source with this verifier and nobody else. No certificate (a plain-HTTP listener, or a re-verification from the quarantine pen, which does not keep one) is :missing_signature; a certificate that cannot be parsed, with :subjects set and no fingerprint match, is :malformed_signature; a valid certificate nobody pinned is :no_match. Use on_verify_failure: reject for a certificate source: a quarantined hook cannot be released by replay.

Summary

Functions

The normalised form of a fingerprint (lowercase hex, no separators), or :error.

Human name of the scheme for telemetry.

Check opts the way verify/2 would use them, without a request: at least one pin, every fingerprint 64 hex characters, every subject a known identity form. :ok, or {:error, :bad_pin}.

Functions

normalize_fingerprint(fingerprint)

@spec normalize_fingerprint(term()) :: {:ok, String.t()} | :error

The normalised form of a fingerprint (lowercase hex, no separators), or :error.

scheme_name(opts)

@spec scheme_name(keyword()) :: String.t()

Human name of the scheme for telemetry.

validate_opts(opts)

@spec validate_opts(keyword()) :: :ok | {:error, :bad_pin}

Check opts the way verify/2 would use them, without a request: at least one pin, every fingerprint 64 hex characters, every subject a known identity form. :ok, or {:error, :bad_pin}.