Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: offline mode key rotation #408

Merged
merged 27 commits into from
Jun 25, 2024
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a036eae
refactor: add rotator component
cwaldren-ld Jun 12, 2024
6c29d17
tests
cwaldren-ld Jun 12, 2024
373c539
in progress
cwaldren-ld Jun 13, 2024
ee67b77
more refactoring
cwaldren-ld Jun 14, 2024
7f96b6b
plumbing key rotator
cwaldren-ld Jun 18, 2024
3669a07
it builds
cwaldren-ld Jun 18, 2024
4b7b2ba
updating tests
cwaldren-ld Jun 19, 2024
260640b
fix bug with immediate revocation
cwaldren-ld Jun 19, 2024
9fc465c
refactor the rotator to be more testable without any time dependency
cwaldren-ld Jun 20, 2024
74858da
update tests and add new configuration item
cwaldren-ld Jun 21, 2024
4c8d4aa
update docs
cwaldren-ld Jun 21, 2024
1e49590
lints
cwaldren-ld Jun 21, 2024
6191e58
remove old tests
cwaldren-ld Jun 21, 2024
84427b0
goimports
cwaldren-ld Jun 21, 2024
3666691
more tests
cwaldren-ld Jun 24, 2024
b300967
fix some nits
cwaldren-ld Jun 24, 2024
047bc27
fix envrep conversion
cwaldren-ld Jun 24, 2024
bf29380
comments & rename rotator.Query to rotator.StepTime
cwaldren-ld Jun 25, 2024
1b41db3
feat: offline mode key rotation
cwaldren-ld Jun 24, 2024
0242c46
plumb a new 'offline' bool throughout environment config
cwaldren-ld Jun 25, 2024
79d18fa
more comments
cwaldren-ld Jun 25, 2024
3498aff
Merge branch 'v8' into sc-246233/offline-mode-key-rotation
cwaldren-ld Jun 25, 2024
41d58b9
refactor the new offline bool out of EnvParams
cwaldren-ld Jun 25, 2024
2851a8f
refactoring
cwaldren-ld Jun 25, 2024
247f9dd
more offline mode integration tests
cwaldren-ld Jun 25, 2024
46c64a5
refactor tests into individual tests
cwaldren-ld Jun 25, 2024
6255451
reduce flakiness
cwaldren-ld Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
in progress
  • Loading branch information
cwaldren-ld committed Jun 18, 2024

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
commit 373c5392c991ff6d66de6e38269b73193b308ec1
4 changes: 2 additions & 2 deletions internal/credential/rotator.go
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ func (r *Rotator) Stop() {
}
}

func (r *Rotator) Deprecate(cred SDKCredential, expiry time.Time) bool {
func (r *Rotator) Deprecate(cred SDKCredential, expiry time.Time, onExpiry func(credential SDKCredential)) bool {
if existing, ok := r.timers[cred]; ok {
r.loggers.Warnf("Credential %s was marked for deprecation with an expiry time of %v, but it previously expired at %v", cred.Masked(), expiry, existing.expiry)
return false
@@ -60,7 +60,7 @@ func (r *Rotator) Deprecate(cred SDKCredential, expiry time.Time) bool {
state.timer = time.AfterFunc(expiry.Sub(r.now()), func() {
r.loggers.Info("Credential %s has expired", cred.Masked())
state.expired = true
r.expirations <- cred
onExpiry(cred)
})
r.timers[cred] = state
return true
16 changes: 12 additions & 4 deletions internal/envfactory/env_params.go
Original file line number Diff line number Diff line change
@@ -29,9 +29,8 @@ type EnvironmentParams struct {
MobileKey config.MobileKey

// ExpiringSDKKey is an additional SDK key that should also be allowed (but not surfaced as
// the canonical one), or "" if none. The expiry time is not represented here; it is managed
// by lower-level components.
ExpiringSDKKey config.SDKKey
// the canonical one).
ExpiringSDKKey ExpiringSDKKey

// TTL is the cache TTL for PHP clients.
TTL time.Duration
@@ -40,10 +39,19 @@ type EnvironmentParams struct {
SecureMode bool
}

type ExpiringSDKKey struct {
Key config.SDKKey
Expiration time.Time
}

func (e ExpiringSDKKey) Defined() bool {
return e.Key.Defined()
}

func (e EnvironmentParams) Credentials() credential.AutoConfig {
return credential.AutoConfig{
SDKKey: e.SDKKey,
ExpiringSDKKey: e.ExpiringSDKKey,
ExpiringSDKKey: e.ExpiringSDKKey.Key,
MobileKey: e.MobileKey,
}
}
17 changes: 12 additions & 5 deletions internal/envfactory/env_rep.go
Original file line number Diff line number Diff line change
@@ -62,6 +62,10 @@ type ExpiringKeyRep struct {
Timestamp ldtime.UnixMillisecondTime `json:"timestamp"`
}

func ToTime(millisecondTime ldtime.UnixMillisecondTime) time.Time {
return time.UnixMilli(int64(millisecondTime))
}

// ToParams converts the JSON properties for an environment into our internal parameter type.
func (r EnvironmentRep) ToParams() EnvironmentParams {
return EnvironmentParams{
@@ -72,11 +76,14 @@ func (r EnvironmentRep) ToParams() EnvironmentParams {
ProjKey: r.ProjKey,
ProjName: r.ProjName,
},
SDKKey: r.SDKKey.Value,
MobileKey: r.MobKey,
ExpiringSDKKey: r.SDKKey.Expiring.Value,
TTL: time.Duration(r.DefaultTTL) * time.Minute,
SecureMode: r.SecureMode,
SDKKey: r.SDKKey.Value,
MobileKey: r.MobKey,
ExpiringSDKKey: ExpiringSDKKey{
Key: r.SDKKey.Expiring.Value,
Expiration: ToTime(r.SDKKey.Expiring.Timestamp),
},
TTL: time.Duration(r.DefaultTTL) * time.Minute,
SecureMode: r.SecureMode,
}
}

2 changes: 1 addition & 1 deletion internal/relayenv/env_context.go
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ type EnvContext interface {
// DeprecateCredential marks an existing credential as not being a preferred one, without removing it or
// dropping any connections. It will no longer be included in the return value of GetCredentials(). This is
// used in Relay Proxy Enterprise when an SDK key is being changed but the old key has not expired yet.
DeprecateCredential(credential.SDKCredential)
DeprecateCredential(cred credential.SDKCredential, when time.Time)

// GetClient returns the SDK client instance for this environment. This is nil if initialization is not yet
// complete. Rather than providing the full client object, we use the simpler sdks.LDClientContext which
5 changes: 4 additions & 1 deletion internal/relayenv/env_context_impl.go
Original file line number Diff line number Diff line change
@@ -105,6 +105,7 @@ type envContextImpl struct {
initErr error
creationTime time.Time
filterKey config.FilterKey
keyRotator *credential.Rotator
}

// Implementation of the DataStoreQueries interface that the streams package uses as an abstraction of
@@ -181,6 +182,7 @@ func NewEnvContext(
dataStoreInfo: params.DataStoreInfo,
creationTime: time.Now(),
filterKey: params.EnvConfig.FilterKey,
keyRotator: credential.NewRotator(params.Loggers, time.Now),
}

bigSegmentStoreFactory := params.BigSegmentStoreFactory
@@ -519,11 +521,12 @@ func (c *envContextImpl) RemoveCredential(oldCredential credential.SDKCredential
}
}

func (c *envContextImpl) DeprecateCredential(credential credential.SDKCredential) {
func (c *envContextImpl) DeprecateCredential(credential credential.SDKCredential, when time.Time) {
c.mu.Lock()
defer c.mu.Unlock()
if _, found := c.credentials[credential]; found {
c.credentials[credential] = false
c.keyRotator.Deprecate(credential, when, c.RemoveCredential)
}
}

8 changes: 4 additions & 4 deletions relay/autoconfig_actions.go
Original file line number Diff line number Diff line change
@@ -34,10 +34,10 @@ func (a *relayAutoConfigActions) AddEnvironment(params envfactory.EnvironmentPar
}

if params.ExpiringSDKKey.Defined() {
if _, err := a.r.getEnvironment(sdkauth.NewScoped(params.Identifiers.FilterKey, params.ExpiringSDKKey)); err != nil {
env.AddCredential(params.ExpiringSDKKey)
env.DeprecateCredential(params.ExpiringSDKKey)
a.r.addConnectionMapping(sdkauth.NewScoped(params.Identifiers.FilterKey, params.ExpiringSDKKey), env)
if _, err := a.r.getEnvironment(sdkauth.NewScoped(params.Identifiers.FilterKey, params.ExpiringSDKKey.Key)); err != nil {
env.AddCredential(params.ExpiringSDKKey.Key)
env.DeprecateCredential(params.ExpiringSDKKey.Key, params.ExpiringSDKKey.Expiration)
a.r.addConnectionMapping(sdkauth.NewScoped(params.Identifiers.FilterKey, params.ExpiringSDKKey.Key), env)
}
}
}