Review zero-downtime credential rotation

src/credential-rotation-types.tsTypeScript
@@ -0,0 +1,66 @@
1+export interface DatabaseCredential {
2+ id: string;
3+ value: string;
4+ version: string;
5+}
6+
7+export type RotationPhase =
8+ | "candidate-created"
9+ | "candidate-published"
10+ | "replicas-notified"
11+ | "previous-revoked"
12+ | "complete";
13+
14+export interface RotationOperation {
15+ id: string;
16+ service: string;
17+ phase: RotationPhase;
18+ candidateId: string;
19+ candidateVersion: string;
20+ previousCredentialId: string;
21+}
22+
23+export interface RotationSecretStore {
24+ putNext(service: string, credential: DatabaseCredential): Promise<void>;
25+ verifyNext(service: string, version: string): Promise<void>;
26+ promoteNext(service: string): Promise<void>;
27+ readCurrent(service: string): Promise<DatabaseCredential>;
28+}
29+
30+export interface RotationDatabase {
31+ getPreferred(service: string): Promise<DatabaseCredential>;
32+ createCandidate(service: string): Promise<DatabaseCredential>;
33+ setPreferred(service: string, credentialId: string): Promise<void>;
34+ revoke(service: string, credentialId: string): Promise<void>;
35+}
36+
37+export interface ReplicaDirectory {
38+ requestRefresh(service: string, operationId: string, version: string): Promise<void>;
39+ waitForAcknowledgements(
40+ service: string,
41+ operationId: string,
42+ version: string,
43+ ): Promise<readonly string[]>;
44+ desiredReplicaIds(service: string): Promise<readonly string[]>;
45+}
46+
47+export interface RotationLease {
48+ acquire(service: string, operationId: string): Promise<boolean>;
49+ release(service: string, operationId: string): Promise<void>;
50+}
51+
52+export interface RotationOperationStore {
53+ loadIncomplete(service: string): Promise<RotationOperation | undefined>;
54+ save(operation: RotationOperation): Promise<void>;
55+}
56+
57+export interface RotationDependencies {
58+ database: RotationDatabase;
59+ secrets: RotationSecretStore;
60+ replicas: ReplicaDirectory;
61+ lease: RotationLease;
62+ operations: RotationOperationStore;
63+ newId(): string;
64+ now(): Date;
65+ sleep(milliseconds: number): Promise<void>;
66+}