Skip to content

feat(fernet): Unify credential/token key repositories#915

Merged
gtema merged 1 commit into
mainfrom
claude/adr-0019-keystone-compat-nfzp1z
Jul 4, 2026
Merged

feat(fernet): Unify credential/token key repositories#915
gtema merged 1 commit into
mainfrom
claude/adr-0019-keystone-compat-nfzp1z

Conversation

@gtema

@gtema gtema commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

Adds openstack-keystone-key-repository: a backend-agnostic KeySource
trait (FilesystemKeySource today, Vault-ready) plus
KeyRepository/CachedKeyRepository, implementing the key parsing,
key_hash, Null Key detection, and staged-rotation logic that previously
existed twice (once in credential-driver-sql, once, partially, in
token-driver-fernet).

  • credential-driver-sql's FernetKeyRepository becomes a thin async
    adapter over the shared crate; behavior-neutral (same
    MAX_ACTIVE_KEYS=3 hard cap).
  • token-driver-fernet gains full parity with the credential key
    repository: Null Key detection (new [fernet_tokens]
    insecure_allow_null_key config, default false), real key rotation
    (max_active_keys was previously unused), and an auto-refreshing cached
    key snapshot (CachedKeyRepository) replacing the old
    load-once-never-reload / reload-from-disk-every-call split — this
    removes the long-standing "TODO: implement fernet keys change watching"
    and makes token key rotation take effect without a service restart.
  • The filesystem key source watches for changes via inotify with a
    polling fallback (same debounce pattern as ConfigManager's existing
    config-file watcher), so the same watch/reload contract will hold for a
    future Vault-backed KeySource without changing
    KeyRepository/CachedKeyRepository.
  • keystone-manage gains token setup/token rotate (mirroring the
    existing credential setup/migrate/rotate; no migrate for
    tokens since they are never re-encrypted, just expire).
  • keystone's startup Null Key check now runs for both key repositories.

Assisted-By: Claude Sonnet 5 noreply@anthropic.com
Signed-off-by: Artem Goncharov artem.goncharov@gmail.com

Adds openstack-keystone-key-repository: a backend-agnostic KeySource
trait (FilesystemKeySource today, Vault-ready) plus
KeyRepository/CachedKeyRepository, implementing the key parsing,
key_hash, Null Key detection, and staged-rotation logic that previously
existed twice (once in credential-driver-sql, once, partially, in
token-driver-fernet).

- credential-driver-sql's FernetKeyRepository becomes a thin async
  adapter over the shared crate; behavior-neutral (same
MAX_ACTIVE_KEYS=3 hard cap).
- token-driver-fernet gains full parity with the credential key
  repository: Null Key detection (new [fernet_tokens]
insecure_allow_null_key config, default false), real key rotation
(max_active_keys was previously unused), and an auto-refreshing cached
key snapshot (CachedKeyRepository) replacing the old
load-once-never-reload / reload-from-disk-every-call split — this
removes the long-standing "TODO: implement fernet keys change watching"
and makes token key rotation take effect without a service restart.
- The filesystem key source watches for changes via inotify with a
  polling fallback (same debounce pattern as ConfigManager's existing
config-file watcher), so the same watch/reload contract will hold for a
future Vault-backed KeySource without changing
KeyRepository/CachedKeyRepository.
- keystone-manage gains `token setup`/`token rotate` (mirroring the
  existing `credential setup`/`migrate`/`rotate`; no `migrate` for
tokens since they are never re-encrypted, just expire).
- keystone's startup Null Key check now runs for both key repositories.

Assisted-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

🦢 Load Test Results

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-07-04 07:59:07 26-07-04 07:59:22 00:00:15 0 → 30
Maintaining 26-07-04 07:59:22 26-07-04 07:59:52 00:00:30 30
Decreasing 26-07-04 07:59:52 26-07-04 07:59:53 00:00:01 0 ← 30

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
DELETE DELETE /v3/auth/tokens 453 0 120.68 14 151 15.10 0.00
DELETE DELETE /v3/projects/:id (teardown) 2 0 80.00 68 92 0.07 0.00
DELETE DELETE /v3/users/:id (teardown) 3 0 44.33 36 50 0.10 0.00
GET 4125 0 114.05 81 218 137.50 0.00
GET GET /v3/auth/tokens (validate new) 451 0 120.98 43 154 15.03 0.00
GET GET /v3/projects/:id 644 0 93.00 78 117 21.47 0.00
GET GET /v3/projects/:id (catalog) 637 0 93.51 79 121 21.23 0.00
GET GET /v3/users/:id 900 0 100.11 86 129 30.00 0.00
GET GET /v3/users/:id (catalog) 706 0 100.15 86 129 23.53 0.00
POST POST /v3/auth/tokens 450 0 91.74 78 118 15.00 0.00
Aggregated 8371 0 107.70 14 218 279.03 0.00

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
DELETE DELETE /v3/auth/tokens 120 120 120 130 130 130 150 150
DELETE DELETE /v3/projects/:id (teardown) 68 68 68 92 92 92 92 92
DELETE DELETE /v3/users/:id (teardown) 47 47 47 47 50 50 50 50
GET 110 110 110 120 170 180 190 218
GET GET /v3/auth/tokens (validate new) 120 120 120 130 130 130 140 150
GET GET /v3/projects/:id 93 94 96 97 100 100 110 117
GET GET /v3/projects/:id (catalog) 93 94 96 97 100 100 110 120
GET GET /v3/users/:id 99 100 100 100 110 110 120 129
GET GET /v3/users/:id (catalog) 100 100 100 100 110 110 120 129
POST POST /v3/auth/tokens 91 93 94 95 98 100 110 118
Aggregated 100 100 110 120 130 170 190 218

Status Code Metrics

Method Name Status Codes
DELETE DELETE /v3/auth/tokens 453 [204]
DELETE DELETE /v3/projects/:id (teardown) 2 [204]
DELETE DELETE /v3/users/:id (teardown) 3 [204]
GET 4,125 [200]
GET GET /v3/auth/tokens (validate new) 451 [200]
GET GET /v3/projects/:id 644 [200]
GET GET /v3/projects/:id (catalog) 637 [200]
GET GET /v3/users/:id 900 [200]
GET GET /v3/users/:id (catalog) 706 [200]
POST POST /v3/auth/tokens 450 [200]
Aggregated 458 [204], 7,913 [200]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
ReadHeavy
0.0 0 0 0.00 0 0 0.00 0.00
0.1 699 0 112.55 96 140 23.30 0.00
0.2 700 0 93.47 81 126 23.33 0.00
0.3 699 0 94.61 81 122 23.30 0.00
TokenLifecycle
1.0 0 0 0.00 0 0 0.00 0.00
1.1 453 0 334.63 141 385 15.10 0.00
ValidateToken
2.0 0 0 0.00 0 0 0.00 0.00
2.1 683 0 176.80 125 218 22.77 0.00
UserCRUD
3.0 0 0 0.00 0 0 0.00 0.00
3.1 0 0 0.00 0 0 0.00 0.00
3.2 900 0 100.19 86 129 30.00 0.00
3.3 3 0 45.00 37 50 0.10 0.00
ProjectCRUD
4.0 0 0 0.00 0 0 0.00 0.00
4.1 0 0 0.00 0 0 0.00 0.00
4.2 644 0 93.07 78 117 21.47 0.00
4.3 2 0 80.00 68 92 0.07 0.00
UserRead
5.0 0 0 0.00 0 0 0.00 0.00
5.1 705 0 112.72 97 142 23.50 0.00
5.2 706 0 100.23 86 129 23.53 0.00
ProjectRead
6.0 0 0 0.00 0 0 0.00 0.00
6.1 639 0 94.38 81 126 21.30 0.00
6.2 637 0 93.58 79 121 21.23 0.00
Aggregated 7470 0 120.69 37 385 249.00 0.00

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
ReadHeavy 7 697 301.69 275 355 23.23 99.57
TokenLifecycle 5 448 335.73 309 385 14.93 89.60
ValidateToken 4 679 176.92 156 218 22.63 169.75
UserCRUD 3 897 100.21 86 129 29.90 299.00
ProjectCRUD 2 642 93.07 78 117 21.40 321.00
UserRead 5 704 213.46 194 255 23.47 140.80
ProjectRead 4 636 188.45 163 230 21.20 159.00
Aggregated 30 4703 191.49 78 385 156.77 1278.72

View full report

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

🐰 Bencher Report

Branchclaude/adr-0019-keystone-compat-nfzp1z
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
Command_Serde/apply/remove📈 view plot
🚷 view threshold
84,139.00 ns
(-72.13%)Baseline: 301,889.16 ns
1,713,921.13 ns
(4.91%)
Command_Serde/apply/set📈 view plot
🚷 view threshold
91,088.00 ns
(-64.16%)Baseline: 254,174.86 ns
1,029,665.77 ns
(8.85%)
Command_Serde/pack/delete📈 view plot
🚷 view threshold
126.15 ns
(+3.67%)Baseline: 121.68 ns
146.41 ns
(86.16%)
Command_Serde/pack/delete_index📈 view plot
🚷 view threshold
114.90 ns
(+4.40%)Baseline: 110.06 ns
131.64 ns
(87.28%)
Command_Serde/pack/set📈 view plot
🚷 view threshold
200.14 ns
(+2.40%)Baseline: 195.45 ns
239.26 ns
(83.65%)
Command_Serde/pack/set_index📈 view plot
🚷 view threshold
114.77 ns
(+4.35%)Baseline: 109.98 ns
131.28 ns
(87.42%)
Command_Serde/unpack/delete📈 view plot
🚷 view threshold
222.05 ns
(+15.39%)Baseline: 192.44 ns
234.58 ns
(94.66%)
Command_Serde/unpack/delete_index📈 view plot
🚷 view threshold
183.52 ns
(+14.89%)Baseline: 159.74 ns
197.90 ns
(92.73%)
Command_Serde/unpack/set📈 view plot
🚷 view threshold
275.18 ns
(+2.43%)Baseline: 268.65 ns
334.07 ns
(82.37%)
Command_Serde/unpack/set_index📈 view plot
🚷 view threshold
185.10 ns
(+16.31%)Baseline: 159.15 ns
196.27 ns
(94.31%)
Payload_encryption/pack/remove_cmd📈 view plot
🚷 view threshold
123.78 ns
(+6.64%)Baseline: 116.07 ns
141.45 ns
(87.51%)
Payload_encryption/pack/set_cmd📈 view plot
🚷 view threshold
194.75 ns
(-4.16%)Baseline: 203.20 ns
267.90 ns
(72.69%)
Payload_encryption/unpack/remove_cmd📈 view plot
🚷 view threshold
215.05 ns
(+4.94%)Baseline: 204.92 ns
253.57 ns
(84.81%)
Payload_encryption/unpack/set_cmd📈 view plot
🚷 view threshold
277.85 ns
(-1.32%)Baseline: 281.58 ns
352.87 ns
(78.74%)
Raft_1Node_Latency/prefix/1node📈 view plot
🚷 view threshold
4,433,800.00 ns
(+63.66%)Baseline: 2,709,221.72 ns
6,199,965.74 ns
(71.51%)
Raft_1Node_Latency/read/1node📈 view plot
🚷 view threshold
34,796.00 ns
(+70.39%)Baseline: 20,421.42 ns
69,089.27 ns
(50.36%)
Raft_1Node_Latency/remove/1node📈 view plot
🚷 view threshold
252,410.00 ns
(-56.18%)Baseline: 576,029.84 ns
2,322,079.28 ns
(10.87%)
Raft_1Node_Latency/write/1node📈 view plot
🚷 view threshold
272,340.00 ns
(-54.44%)Baseline: 597,758.91 ns
2,150,928.42 ns
(12.66%)
build_snapshot/default📈 view plot
🚷 view threshold
108,200.00 ns
(-2.53%)Baseline: 111,008.59 ns
162,450.62 ns
(66.60%)
fernet token/project📈 view plot
🚷 view threshold
1,494.70 ns
(+8.19%)Baseline: 1,381.51 ns
1,637.72 ns
(91.27%)
get_data_keyspace📈 view plot
🚷 view threshold
0.36 ns
(+14.05%)Baseline: 0.31 ns
0.36 ns
(98.08%)
get_db📈 view plot
🚷 view threshold
0.35 ns
(+12.51%)Baseline: 0.31 ns
0.36 ns
(96.86%)
get_fernet_token_timestamp/project📈 view plot
🚷 view threshold
145.78 ns
(+1.52%)Baseline: 143.59 ns
181.20 ns
(80.45%)
get_keyspace📈 view plot
🚷 view threshold
4.58 ns
(-5.23%)Baseline: 4.83 ns
9.76 ns
(46.92%)
🐰 View full continuous benchmarking report in Bencher

@gtema gtema merged commit 6deadcf into main Jul 4, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant