mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
Identity: check NextSigningKey existence during key rotation (#13298)
* oidc: fix key rotation panic * refactor and update unit tests * add changelog
This commit is contained in:
committed by
GitHub
parent
dca55233b4
commit
8b72c3eb73
3
changelog/13298.txt
Normal file
3
changelog/13298.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
identity: Fixes a panic in the OIDC key rotation due to a missing nil check.
|
||||||
|
```
|
||||||
@@ -561,18 +561,10 @@ func (i *IdentityStore) pathOIDCCreateUpdateKey(ctx context.Context, req *logica
|
|||||||
}
|
}
|
||||||
i.Logger().Debug("generated OIDC public key to sign JWTs", "key_id", signingKey.Public().KeyID)
|
i.Logger().Debug("generated OIDC public key to sign JWTs", "key_id", signingKey.Public().KeyID)
|
||||||
|
|
||||||
nextSigningKey, err := generateKeys(key.Algorithm)
|
err = key.generateAndSetNextKey(ctx, i.Logger(), req.Storage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
key.NextSigningKey = nextSigningKey
|
|
||||||
key.KeyRing = append(key.KeyRing, &expireableKey{KeyID: nextSigningKey.Public().KeyID})
|
|
||||||
|
|
||||||
if err := saveOIDCPublicKey(ctx, req.Storage, nextSigningKey.Public()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
i.Logger().Debug("generated OIDC public key for future use", "key_id", nextSigningKey.Public().KeyID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := i.oidcCache.Flush(ns); err != nil {
|
if err := i.oidcCache.Flush(ns); err != nil {
|
||||||
@@ -1021,6 +1013,24 @@ func mergeJSONTemplates(logger hclog.Logger, output map[string]interface{}, temp
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateAndSetNextKey will generate new signing and public key pairs and set
|
||||||
|
// them as the NextSigningKey.
|
||||||
|
func (k *namedKey) generateAndSetNextKey(ctx context.Context, logger hclog.Logger, s logical.Storage) error {
|
||||||
|
signingKey, err := generateKeys(k.Algorithm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
k.NextSigningKey = signingKey
|
||||||
|
k.KeyRing = append(k.KeyRing, &expireableKey{KeyID: signingKey.Public().KeyID})
|
||||||
|
|
||||||
|
if err := saveOIDCPublicKey(ctx, s, signingKey.Public()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("generated OIDC public key for future use", "key_id", signingKey.Public().KeyID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (k *namedKey) signPayload(payload []byte) (string, error) {
|
func (k *namedKey) signPayload(payload []byte) (string, error) {
|
||||||
signingKey := jose.SigningKey{Key: k.SigningKey, Algorithm: jose.SignatureAlgorithm(k.Algorithm)}
|
signingKey := jose.SigningKey{Key: k.SigningKey, Algorithm: jose.SignatureAlgorithm(k.Algorithm)}
|
||||||
signer, err := jose.NewSigner(signingKey, &jose.SignerOptions{})
|
signer, err := jose.NewSigner(signingKey, &jose.SignerOptions{})
|
||||||
@@ -1477,16 +1487,6 @@ func (k *namedKey) rotate(ctx context.Context, logger hclog.Logger, s logical.St
|
|||||||
verificationTTL = overrideVerificationTTL
|
verificationTTL = overrideVerificationTTL
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate new key
|
|
||||||
nextSigningKey, err := generateKeys(k.Algorithm)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := saveOIDCPublicKey(ctx, s, nextSigningKey.Public()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Debug("generated OIDC public key for future use", "key_id", nextSigningKey.Public().KeyID)
|
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
// set the previous public key's expiry time
|
// set the previous public key's expiry time
|
||||||
for _, key := range k.KeyRing {
|
for _, key := range k.KeyRing {
|
||||||
@@ -1496,11 +1496,24 @@ func (k *namedKey) rotate(ctx context.Context, logger hclog.Logger, s logical.St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
k.KeyRing = append(k.KeyRing, &expireableKey{KeyID: nextSigningKey.KeyID})
|
if k.NextSigningKey == nil {
|
||||||
|
// keys will not have a NextSigningKey if they were generated before
|
||||||
|
// vault 1.9
|
||||||
|
err := k.generateAndSetNextKey(ctx, logger, s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// do the rotation
|
||||||
k.SigningKey = k.NextSigningKey
|
k.SigningKey = k.NextSigningKey
|
||||||
k.NextSigningKey = nextSigningKey
|
|
||||||
k.NextRotation = now.Add(k.RotationPeriod)
|
k.NextRotation = now.Add(k.RotationPeriod)
|
||||||
|
|
||||||
|
// now that we have rotated, generate a new NextSigningKey
|
||||||
|
err := k.generateAndSetNextKey(ctx, logger, s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// store named key (it was modified when rotate was called on it)
|
// store named key (it was modified when rotate was called on it)
|
||||||
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+k.name, k)
|
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+k.name, k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -921,6 +921,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
// don't set NextSigningKey to ensure its non-existence can be handled
|
||||||
&namedKey{
|
&namedKey{
|
||||||
name: "test-key",
|
name: "test-key",
|
||||||
Algorithm: "RS256",
|
Algorithm: "RS256",
|
||||||
@@ -928,7 +929,6 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
|||||||
RotationPeriod: 1 * cyclePeriod,
|
RotationPeriod: 1 * cyclePeriod,
|
||||||
KeyRing: nil,
|
KeyRing: nil,
|
||||||
SigningKey: jwk,
|
SigningKey: jwk,
|
||||||
NextSigningKey: jwk,
|
|
||||||
NextRotation: time.Now(),
|
NextRotation: time.Now(),
|
||||||
},
|
},
|
||||||
[]struct {
|
[]struct {
|
||||||
@@ -936,8 +936,8 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
|||||||
numKeys int
|
numKeys int
|
||||||
numPublicKeys int
|
numPublicKeys int
|
||||||
}{
|
}{
|
||||||
{1, 1, 1},
|
{1, 2, 2},
|
||||||
{2, 2, 2},
|
{2, 3, 3},
|
||||||
{3, 3, 3},
|
{3, 3, 3},
|
||||||
{4, 3, 3},
|
{4, 3, 3},
|
||||||
{5, 3, 3},
|
{5, 3, 3},
|
||||||
|
|||||||
Reference in New Issue
Block a user