IKeyRingStore Interface
The shared place the server's minted keys live, so every pod serves one key set rather than its own. Entries are encrypted to the custodian's key-encryption key before they get here, so this store holds ciphertext and never a secret.
public interface IKeyRingStoreRemarks
The port is three methods because the design needs no more. Key state is not stored, it is computed: given the entries and their creation times, every pod derives the same announced / active / retired projection by arithmetic, so there is nothing to update and no state machine to synchronise. The single operation that does need synchronising is creating the next key, since two pods would otherwise generate different material, and TryAddAsync(StoredKey, CancellationToken) carries that alone.
Because the entry is ciphertext we produced, the store's own protection is not what keeps the key safe: an implementation may be a database, a blob, a config map, or the custodian's own key-value engine, and the threat model does not change with the choice.
Methods
IKeyRingStore.LoadAsync(CancellationToken) Method
Reads every entry. The caller projects the key states from their creation times, so the store neither filters nor orders.
System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Abblix.Jwt.ExternalKeys.StoredKey>> LoadAsync(System.Threading.CancellationToken cancellationToken);Parameters
cancellationToken System.Threading.CancellationToken
Cancels the read.
Returns
System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<StoredKey>>
All entries currently in the ring.
IKeyRingStore.RemoveAsync(string, CancellationToken) Method
Removes an entry, idempotently: removing an absent id is not an error.
System.Threading.Tasks.Task RemoveAsync(string id, System.Threading.CancellationToken cancellationToken);Parameters
id System.String
The Id to remove.
cancellationToken System.Threading.CancellationToken
Cancels the write.
Returns
Remarks
Only ever called for a key already past every token it signed, so removal races are harmless: two pods removing the same expired entry is the same outcome as one.
IKeyRingStore.TryAddAsync(StoredKey, CancellationToken) Method
Inserts an entry if its Id is not taken, and reports whether this caller was the one that took it.
System.Threading.Tasks.Task<bool> TryAddAsync(Abblix.Jwt.ExternalKeys.StoredKey key, System.Threading.CancellationToken cancellationToken);Parameters
key StoredKey
The entry to insert.
cancellationToken System.Threading.CancellationToken
Cancels the write.
Returns
System.Threading.Tasks.Task<System.Boolean>
True when this caller inserted the entry; false when another pod had already claimed the id, in
which case the caller re-reads the ring and uses the winner's key.
Remarks
This is the whole of the coordination, and it must be atomic in the backing store: a unique index, a conditional create, a compare-and-set on absence. Two pods minting the same period both attempt the same id, exactly one gets true, and the loser discards the key it generated. An implementation that cannot insert atomically cannot back this port.