@@ -40,6 +40,7 @@ import (
40
40
"github.com/coder/quartz"
41
41
"github.com/coder/serpent"
42
42
43
+ "github.com/coder/coder/v2/coderd/cryptokeys"
43
44
"github.com/coder/coder/v2/coderd/entitlements"
44
45
"github.com/coder/coder/v2/coderd/idpsync"
45
46
"github.com/coder/coder/v2/coderd/runtimeconfig"
@@ -185,9 +186,6 @@ type Options struct {
185
186
TemplateScheduleStore * atomic.Pointer [schedule.TemplateScheduleStore ]
186
187
UserQuietHoursScheduleStore * atomic.Pointer [schedule.UserQuietHoursScheduleStore ]
187
188
AccessControlStore * atomic.Pointer [dbauthz.AccessControlStore ]
188
- // AppSecurityKey is the crypto key used to sign and encrypt tokens related to
189
- // workspace applications. It consists of both a signing and encryption key.
190
- AppSecurityKey workspaceapps.SecurityKey
191
189
// CoordinatorResumeTokenProvider is used to provide and validate resume
192
190
// tokens issued by and passed to the coordinator DRPC API.
193
191
CoordinatorResumeTokenProvider tailnet.ResumeTokenProvider
@@ -251,6 +249,12 @@ type Options struct {
251
249
252
250
// OneTimePasscodeValidityPeriod specifies how long a one time passcode should be valid for.
253
251
OneTimePasscodeValidityPeriod time.Duration
252
+
253
+ // Keycaches
254
+ AppSigningKeyCache cryptokeys.SigningKeycache
255
+ AppEncryptionKeyCache cryptokeys.EncryptionKeycache
256
+ OIDCConvertKeyCache cryptokeys.SigningKeycache
257
+ Clock quartz.Clock
254
258
}
255
259
256
260
// @title Coder API
@@ -352,6 +356,9 @@ func New(options *Options) *API {
352
356
if options .PrometheusRegistry == nil {
353
357
options .PrometheusRegistry = prometheus .NewRegistry ()
354
358
}
359
+ if options .Clock == nil {
360
+ options .Clock = quartz .NewReal ()
361
+ }
355
362
if options .DERPServer == nil && options .DeploymentValues .DERP .Server .Enable {
356
363
options .DERPServer = derp .NewServer (key .NewNode (), tailnet .Logger (options .Logger .Named ("derp" )))
357
364
}
@@ -444,6 +451,49 @@ func New(options *Options) *API {
444
451
if err != nil {
445
452
panic (xerrors .Errorf ("get deployment ID: %w" , err ))
446
453
}
454
+
455
+ fetcher := & cryptokeys.DBFetcher {
456
+ DB : options .Database ,
457
+ }
458
+
459
+ if options .OIDCConvertKeyCache == nil {
460
+ options .OIDCConvertKeyCache , err = cryptokeys .NewSigningCache (ctx ,
461
+ options .Logger .Named ("oidc_convert_keycache" ),
462
+ fetcher ,
463
+ codersdk .CryptoKeyFeatureOIDCConvert ,
464
+ )
465
+ if err != nil {
466
+ options .Logger .Critical (ctx , "failed to properly instantiate oidc convert signing cache" , slog .Error (err ))
467
+ }
468
+ }
469
+
470
+ if options .AppSigningKeyCache == nil {
471
+ options .AppSigningKeyCache , err = cryptokeys .NewSigningCache (ctx ,
472
+ options .Logger .Named ("app_signing_keycache" ),
473
+ fetcher ,
474
+ codersdk .CryptoKeyFeatureWorkspaceAppsToken ,
475
+ )
476
+ if err != nil {
477
+ options .Logger .Critical (ctx , "failed to properly instantiate app signing key cache" , slog .Error (err ))
478
+ }
479
+ }
480
+
481
+ if options .AppEncryptionKeyCache == nil {
482
+ options .AppEncryptionKeyCache , err = cryptokeys .NewEncryptionCache (ctx ,
483
+ options .Logger ,
484
+ fetcher ,
485
+ codersdk .CryptoKeyFeatureWorkspaceAppsAPIKey ,
486
+ )
487
+ if err != nil {
488
+ options .Logger .Critical (ctx , "failed to properly instantiate app encryption key cache" , slog .Error (err ))
489
+ }
490
+ }
491
+
492
+ // Start a background process that rotates keys. We intentionally start this after the caches
493
+ // are created to force initial requests for a key to populate the caches. This helps catch
494
+ // bugs that may only occur when a key isn't precached in tests and the latency cost is minimal.
495
+ cryptokeys .StartRotator (ctx , options .Logger , options .Database )
496
+
447
497
api := & API {
448
498
ctx : ctx ,
449
499
cancel : cancel ,
@@ -464,7 +514,7 @@ func New(options *Options) *API {
464
514
options .DeploymentValues ,
465
515
oauthConfigs ,
466
516
options .AgentInactiveDisconnectTimeout ,
467
- options .AppSecurityKey ,
517
+ options .AppSigningKeyCache ,
468
518
),
469
519
metricsCache : metricsCache ,
470
520
Auditor : atomic.Pointer [audit.Auditor ]{},
@@ -606,7 +656,7 @@ func New(options *Options) *API {
606
656
ResumeTokenProvider : api .Options .CoordinatorResumeTokenProvider ,
607
657
})
608
658
if err != nil {
609
- api .Logger .Fatal (api . ctx , "failed to initialize tailnet client service" , slog .Error (err ))
659
+ api .Logger .Fatal (context . Background () , "failed to initialize tailnet client service" , slog .Error (err ))
610
660
}
611
661
612
662
api .statsReporter = workspacestats .NewReporter (workspacestats.ReporterOptions {
@@ -628,9 +678,6 @@ func New(options *Options) *API {
628
678
options .WorkspaceAppsStatsCollectorOptions .Reporter = api .statsReporter
629
679
}
630
680
631
- if options .AppSecurityKey .IsZero () {
632
- api .Logger .Fatal (api .ctx , "app security key cannot be zero" )
633
- }
634
681
api .workspaceAppServer = & workspaceapps.Server {
635
682
Logger : workspaceAppsLogger ,
636
683
@@ -642,11 +689,11 @@ func New(options *Options) *API {
642
689
643
690
SignedTokenProvider : api .WorkspaceAppsProvider ,
644
691
AgentProvider : api .agentProvider ,
645
- AppSecurityKey : options .AppSecurityKey ,
646
692
StatsCollector : workspaceapps .NewStatsCollector (options .WorkspaceAppsStatsCollectorOptions ),
647
693
648
- DisablePathApps : options .DeploymentValues .DisablePathApps .Value (),
649
- SecureAuthCookie : options .DeploymentValues .SecureAuthCookie .Value (),
694
+ DisablePathApps : options .DeploymentValues .DisablePathApps .Value (),
695
+ SecureAuthCookie : options .DeploymentValues .SecureAuthCookie .Value (),
696
+ APIKeyEncryptionKeycache : options .AppEncryptionKeyCache ,
650
697
}
651
698
652
699
apiKeyMiddleware := httpmw .ExtractAPIKeyMW (httpmw.ExtractAPIKeyConfig {
@@ -1434,6 +1481,9 @@ func (api *API) Close() error {
1434
1481
_ = api .agentProvider .Close ()
1435
1482
_ = api .statsReporter .Close ()
1436
1483
_ = api .NetworkTelemetryBatcher .Close ()
1484
+ _ = api .OIDCConvertKeyCache .Close ()
1485
+ _ = api .AppSigningKeyCache .Close ()
1486
+ _ = api .AppEncryptionKeyCache .Close ()
1437
1487
return nil
1438
1488
}
1439
1489
0 commit comments