NAME

Langertha::Skeid::KeyBroker - Pluggable API key resolution for Skeid nodes

VERSION

version 0.003

DESCRIPTION

The contract that turns a key reference (secret/skeid/remote/groq) into a secret, in memory, at the moment it is needed. Langertha::Skeid::KeyBroker::OpenBao is the implementation; this class is what code depends on.

Implement "resolve_key" in a subclass. Everything else — caching, request coalescing, the non-blocking entry point — is provided here, so a three-line broker gets them for free.

Two entry points, and which one is yours

"key_async" is the only one the request path may call. It answers from cache without touching the loop, and a miss is one round-trip however many requests are waiting on it.

"resolve_key" is what a subclass implements and what off-loop code (CLI, tests, setup scripts) may call directly. Calling it from a Mojolicious handler blocks every other in-flight request for the duration of the vault round-trip — see ADR 0005.

cache_ttl

How long a resolved key stays in memory, in seconds (default 300, 0 disables caching). Memory only: ADR 0003 forbids a disk cache, not this one. The cost of a stale key is one failed upstream call after a rotation; the cost of no cache is a vault round-trip on the request path, per request.

negative_cache_ttl

How long a failed resolution is remembered, in seconds (default 5, 0 disables). Short on purpose: it exists so a vault outage costs one round-trip per reference per few seconds instead of one per request, not to make a fixed misconfiguration stick.

resolve_key

my $key = $broker->resolve_key('secret/skeid/remote/groq');

What a subclass implements: resolve one reference, return the secret, die or return undef when it cannot. Blocking. Never call it from a request handler — call "key_async".

key_async

$broker->key_async($ref, sub {
  my ($key, $error) = @_;
  ...
});

The request path's entry point. The callback always runs exactly once, with the key, or with undef and a message. A cached answer calls back immediately and synchronously.

resolve_key_async

$broker->resolve_key_async($ref, sub { my ($key, $error) = @_; ... });

The non-blocking half of "resolve_key", for subclasses that can do better than blocking. The default implementation calls resolve_key and hands the result to the callback, which keeps a simple broker correct — but keeps it blocking. Langertha::Skeid::KeyBroker::OpenBao overrides it.

Callers want "key_async": this one is uncached and uncoalesced.

cached_key

my $hit = $broker->cached_key($ref);   # { key => …, error => … } or nothing

The live cache entry for a reference, or nothing when there is none or it has expired. Distinguishes "cached failure" from "not cached" — both would look like undef otherwise.

forget_key

$broker->forget_key($ref);   # one reference
$broker->forget_key;         # all of them

Drops cached resolutions, so the next request resolves again. What a key rotation calls.

needs_refresh

True when the broker's own credential has to be renewed before the next resolution. Always 0 here; Langertha::Skeid::KeyBroker::OpenBao overrides it.

refresh

Renews the broker's own credential. A no-op here; Langertha::Skeid::KeyBroker::OpenBao overrides it.

SEE ALSO

Langertha::Skeid::KeyBroker::OpenBao, "key_broker" in Langertha::Skeid, and ADR 0003 (secrets live in memory only) in the distribution repository.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha-skeid/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.