1
0

backport of commit 1484253e0ba27695d141b6ecea54eeca1da42e35 (#24408)

Co-authored-by: Austin Gebauer <34121980+austingebauer@users.noreply.github.com>
This commit is contained in:
hc-github-team-secure-vault-core 2023-12-06 16:38:30 -05:00 committed by GitHub
parent afc925b359
commit 8cf459b7f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 41 deletions

View File

@ -643,6 +643,7 @@ func (i *IdentityStore) initialize(ctx context.Context, req *logical.Initializat
}
if err := i.storeOIDCDefaultResources(ctx, req.Storage); err != nil {
i.logger.Error("failed to write OIDC default resources to storage", "error", err)
return err
}

View File

@ -108,6 +108,7 @@ var errNilNamespace = errors.New("nil namespace in oidc cache request")
const (
issuerPath = "identity/oidc"
oidcTokensPrefix = "oidc_tokens/"
namedKeyCachePrefix = "namedKeys/"
oidcConfigStorageKey = oidcTokensPrefix + "config/"
namedKeyConfigPath = oidcTokensPrefix + "named_keys/"
publicKeysConfigPath = oidcTokensPrefix + "public_keys/"
@ -983,7 +984,7 @@ func (i *IdentityStore) getNamedKey(ctx context.Context, s logical.Storage, name
}
// Attempt to get the key from the cache
keyRaw, found, err := i.oidcCache.Get(ns, "namedKeys/"+name)
keyRaw, found, err := i.oidcCache.Get(ns, namedKeyCachePrefix+name)
if err != nil {
return nil, err
}
@ -1005,7 +1006,7 @@ func (i *IdentityStore) getNamedKey(ctx context.Context, s logical.Storage, name
}
// Cache the key
if err := i.oidcCache.SetDefault(ns, "namedKeys/"+name, &key); err != nil {
if err := i.oidcCache.SetDefault(ns, namedKeyCachePrefix+name, &key); err != nil {
i.logger.Warn("failed to cache key", "error", err)
}
@ -1176,6 +1177,12 @@ func (i *IdentityStore) pathOIDCCreateUpdateRole(ctx context.Context, req *logic
return logical.ErrorResponse("the key parameter is required"), nil
}
if role.Key == defaultKeyName {
if err := i.lazyGenerateDefaultKey(ctx, req.Storage); err != nil {
return nil, fmt.Errorf("failed to generate default key: %w", err)
}
}
if template, ok := d.GetOk("template"); ok {
role.Template = template.(string)
} else if req.Operation == logical.CreateOperation {

View File

@ -1120,6 +1120,12 @@ func (i *IdentityStore) pathOIDCCreateUpdateClient(ctx context.Context, req *log
return logical.ErrorResponse("key %q does not exist", client.Key), nil
}
if client.Key == defaultKeyName {
if err := i.lazyGenerateDefaultKey(ctx, req.Storage); err != nil {
return nil, fmt.Errorf("failed to generate default key: %w", err)
}
}
if idTokenTTLRaw, ok := d.GetOk("id_token_ttl"); ok {
client.IDTokenTTL = time.Duration(idTokenTTLRaw.(int)) * time.Second
} else if req.Operation == logical.CreateOperation {
@ -2536,34 +2542,8 @@ func (i *IdentityStore) storeOIDCDefaultResources(ctx context.Context, view logi
i.Logger().Debug("wrote OIDC default provider")
}
// Store the default key
storageKey = namedKeyConfigPath + defaultKeyName
entry, err = view.Get(ctx, storageKey)
if err != nil {
return err
}
if entry == nil {
defaultKey := defaultOIDCKey()
// Generate initial key material for current and next keys
err = defaultKey.generateAndSetKey(ctx, i.Logger(), view)
if err != nil {
return err
}
err = defaultKey.generateAndSetNextKey(ctx, i.Logger(), view)
if err != nil {
return err
}
// Store the entry
entry, err := logical.StorageEntryJSON(storageKey, defaultKey)
if err != nil {
return err
}
if err := view.Put(ctx, entry); err != nil {
return err
}
i.Logger().Debug("wrote OIDC default key")
if _, err := i.ensureDefaultKey(ctx, view); err != nil {
return fmt.Errorf("error writing default key to storage: %w", err)
}
// Store the allow all assignment
@ -2586,6 +2566,71 @@ func (i *IdentityStore) storeOIDCDefaultResources(ctx context.Context, view logi
return nil
}
// ensureDefaultKey ensures that the OIDC default key is written to storage. If no
// error is returned, callers can be sure that it exists in storage. Note that it
// only writes the key's configuration to storage and does not generate key material
// for its current and next keys.
func (i *IdentityStore) ensureDefaultKey(ctx context.Context, storage logical.Storage) (*namedKey, error) {
key, err := i.getNamedKey(ctx, storage, defaultKeyName)
if err != nil {
return nil, err
}
if key != nil {
return key, nil
}
// The default key doesn't exist. Write it to storage.
defaultKey := defaultOIDCKey()
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+defaultKeyName, defaultKey)
if err != nil {
return nil, err
}
if err := storage.Put(ctx, entry); err != nil {
return nil, err
}
i.Logger().Debug("wrote OIDC default key")
return &defaultKey, nil
}
// lazyGenerateDefaultKey generates key material for the OIDC default key's current and
// next key if it hasn't already been generated. Must be called with the oidcLock write
// lock held.
func (i *IdentityStore) lazyGenerateDefaultKey(ctx context.Context, storage logical.Storage) error {
ns, err := namespace.FromContext(ctx)
if err != nil {
return err
}
defaultKey, err := i.ensureDefaultKey(ctx, storage)
if err != nil {
return err
}
if defaultKey.SigningKey == nil {
if err := defaultKey.generateAndSetKey(ctx, i.Logger(), storage); err != nil {
return err
}
if err := defaultKey.generateAndSetNextKey(ctx, i.Logger(), storage); err != nil {
return err
}
if err := i.oidcCache.Delete(ns, namedKeyCachePrefix+defaultKeyName); err != nil {
return err
}
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+defaultKeyName, defaultKey)
if err != nil {
return err
}
if err := storage.Put(ctx, entry); err != nil {
return err
}
}
return nil
}
func (i *IdentityStore) loadOIDCClients(ctx context.Context) error {
i.logger.Debug("identity loading OIDC clients")

View File

@ -1055,10 +1055,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
setSigningKey: true,
setNextSigningKey: true,
testCases: []testCase{
// Each cycle results in a key going in/out of its verification_ttl period
{1, 2, 2},
{2, 2, 4},
{3, 2, 4},
{4, 2, 4},
{2, 3, 3},
{3, 2, 2},
{4, 3, 3},
},
},
{
@ -1067,8 +1068,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
setSigningKey: false,
setNextSigningKey: true,
testCases: []testCase{
{1, 1, 2},
{2, 2, 4},
{1, 1, 1},
// key counts jump from 1 to 2 because the next signing key becomes
// the signing key, and no key is in its verification_ttl period
{2, 2, 2},
},
},
{
@ -1077,8 +1081,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
setSigningKey: true,
setNextSigningKey: false,
testCases: []testCase{
{1, 1, 2},
{2, 2, 4},
{1, 1, 1},
// key counts jump from 1 to 3 because the original signing key is
// still published and within its verification_ttl period
{2, 3, 3},
},
},
{
@ -1087,8 +1094,8 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
setSigningKey: false,
setNextSigningKey: false,
testCases: []testCase{
{1, 0, 2},
{2, 2, 4},
{1, 0, 0},
{2, 2, 2},
},
},
}
@ -1154,7 +1161,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
expectedKeyCount := testSet.testCases[i].numKeys
namedKeySamples[i].DecodeJSON(&testSet.namedKey)
actualKeyRingLen := len(testSet.namedKey.KeyRing)
if actualKeyRingLen < expectedKeyCount {
if actualKeyRingLen != expectedKeyCount {
t.Errorf(
"For key: %s at cycle: %d expected namedKey's KeyRing to be at least of length %d but was: %d",
testSet.namedKey.name,
@ -1165,7 +1172,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
}
expectedPublicKeyCount := testSet.testCases[i].numPublicKeys
actualPubKeysLen := len(publicKeysSamples[i])
if actualPubKeysLen < expectedPublicKeyCount {
if actualPubKeysLen != expectedPublicKeyCount {
t.Errorf(
"For key: %s at cycle: %d expected public keys to be at least of length %d but was: %d",
testSet.namedKey.name,