- Notifications
You must be signed in to change notification settings - Fork1k
feat: enable key rotation#15066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
b745c8e
b98bff0
0646b30
b73b210
7fe88ea
0323f79
7413907
2ea31ab
d0d168b
33cdb96
08570b7
b770762
7557ed2
fa9a75d
94987b6
76561ac
53dcf36
c656d00
e7cfb46
6432b0d
9ad187d
d16e98f
3809cd5
6d3c103
a3020fc
bfa88b7
495c28f
692bb36
4028995
6b9a3e4
5ee6ad5
886d87c
5261442
4a1d974
092a241
87828a2
6aa90bc
358aaa8
ad237ad
5798a33
200cd68
2194b4d
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -40,6 +40,7 @@ import ( | ||
"github.com/coder/quartz" | ||
"github.com/coder/serpent" | ||
"github.com/coder/coder/v2/coderd/cryptokeys" | ||
"github.com/coder/coder/v2/coderd/entitlements" | ||
"github.com/coder/coder/v2/coderd/idpsync" | ||
"github.com/coder/coder/v2/coderd/runtimeconfig" | ||
@@ -185,9 +186,6 @@ type Options struct { | ||
TemplateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore] | ||
UserQuietHoursScheduleStore *atomic.Pointer[schedule.UserQuietHoursScheduleStore] | ||
AccessControlStore *atomic.Pointer[dbauthz.AccessControlStore] | ||
// CoordinatorResumeTokenProvider is used to provide and validate resume | ||
// tokens issued by and passed to the coordinator DRPC API. | ||
CoordinatorResumeTokenProvider tailnet.ResumeTokenProvider | ||
@@ -251,6 +249,12 @@ type Options struct { | ||
// OneTimePasscodeValidityPeriod specifies how long a one time passcode should be valid for. | ||
OneTimePasscodeValidityPeriod time.Duration | ||
// Keycaches | ||
AppSigningKeyCache cryptokeys.SigningKeycache | ||
AppEncryptionKeyCache cryptokeys.EncryptionKeycache | ||
OIDCConvertKeyCache cryptokeys.SigningKeycache | ||
Clock quartz.Clock | ||
} | ||
// @title Coder API | ||
@@ -352,6 +356,9 @@ func New(options *Options) *API { | ||
if options.PrometheusRegistry == nil { | ||
options.PrometheusRegistry = prometheus.NewRegistry() | ||
} | ||
if options.Clock == nil { | ||
options.Clock = quartz.NewReal() | ||
} | ||
if options.DERPServer == nil && options.DeploymentValues.DERP.Server.Enable { | ||
options.DERPServer = derp.NewServer(key.NewNode(), tailnet.Logger(options.Logger.Named("derp"))) | ||
} | ||
@@ -444,6 +451,49 @@ func New(options *Options) *API { | ||
if err != nil { | ||
panic(xerrors.Errorf("get deployment ID: %w", err)) | ||
} | ||
fetcher := &cryptokeys.DBFetcher{ | ||
DB: options.Database, | ||
} | ||
if options.OIDCConvertKeyCache == nil { | ||
options.OIDCConvertKeyCache, err = cryptokeys.NewSigningCache(ctx, | ||
options.Logger.Named("oidc_convert_keycache"), | ||
fetcher, | ||
codersdk.CryptoKeyFeatureOIDCConvert, | ||
) | ||
if err != nil { | ||
options.Logger.Critical(ctx, "failed to properly instantiate oidc convert signing cache", slog.Error(err)) | ||
} | ||
} | ||
if options.AppSigningKeyCache == nil { | ||
options.AppSigningKeyCache, err = cryptokeys.NewSigningCache(ctx, | ||
options.Logger.Named("app_signing_keycache"), | ||
fetcher, | ||
codersdk.CryptoKeyFeatureWorkspaceAppsToken, | ||
) | ||
if err != nil { | ||
options.Logger.Critical(ctx, "failed to properly instantiate app signing key cache", slog.Error(err)) | ||
} | ||
} | ||
if options.AppEncryptionKeyCache == nil { | ||
options.AppEncryptionKeyCache, err = cryptokeys.NewEncryptionCache(ctx, | ||
options.Logger, | ||
fetcher, | ||
codersdk.CryptoKeyFeatureWorkspaceAppsAPIKey, | ||
) | ||
if err != nil { | ||
options.Logger.Critical(ctx, "failed to properly instantiate app encryption key cache", slog.Error(err)) | ||
} | ||
} | ||
// Start a background process that rotates keys. We intentionally start this after the caches | ||
// are created to force initial requests for a key to populate the caches. This helps catch | ||
// bugs that may only occur when a key isn't precached in tests and the latency cost is minimal. | ||
sreya marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
cryptokeys.StartRotator(ctx, options.Logger, options.Database) | ||
api := &API{ | ||
ctx: ctx, | ||
cancel: cancel, | ||
@@ -464,7 +514,7 @@ func New(options *Options) *API { | ||
options.DeploymentValues, | ||
oauthConfigs, | ||
options.AgentInactiveDisconnectTimeout, | ||
options.AppSigningKeyCache, | ||
), | ||
metricsCache: metricsCache, | ||
Auditor: atomic.Pointer[audit.Auditor]{}, | ||
@@ -606,7 +656,7 @@ func New(options *Options) *API { | ||
ResumeTokenProvider: api.Options.CoordinatorResumeTokenProvider, | ||
}) | ||
if err != nil { | ||
api.Logger.Fatal(context.Background(), "failed to initialize tailnet client service", slog.Error(err)) | ||
} | ||
api.statsReporter = workspacestats.NewReporter(workspacestats.ReporterOptions{ | ||
@@ -628,9 +678,6 @@ func New(options *Options) *API { | ||
options.WorkspaceAppsStatsCollectorOptions.Reporter = api.statsReporter | ||
} | ||
api.workspaceAppServer = &workspaceapps.Server{ | ||
Logger: workspaceAppsLogger, | ||
@@ -642,11 +689,11 @@ func New(options *Options) *API { | ||
SignedTokenProvider: api.WorkspaceAppsProvider, | ||
AgentProvider: api.agentProvider, | ||
StatsCollector: workspaceapps.NewStatsCollector(options.WorkspaceAppsStatsCollectorOptions), | ||
DisablePathApps: options.DeploymentValues.DisablePathApps.Value(), | ||
SecureAuthCookie: options.DeploymentValues.SecureAuthCookie.Value(), | ||
APIKeyEncryptionKeycache: options.AppEncryptionKeyCache, | ||
} | ||
apiKeyMiddleware := httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ | ||
@@ -1434,6 +1481,9 @@ func (api *API) Close() error { | ||
_ = api.agentProvider.Close() | ||
_ = api.statsReporter.Close() | ||
_ = api.NetworkTelemetryBatcher.Close() | ||
_ = api.OIDCConvertKeyCache.Close() | ||
_ = api.AppSigningKeyCache.Close() | ||
_ = api.AppEncryptionKeyCache.Close() | ||
return nil | ||
} | ||
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.