Encryption: Fix multiple data keys migration (#49848)
* Add migration * Migrator: Extend support to rename columns * Fix getting current key * Fix column name in migration * Fix deks reencryption * Fix caching * Add back separate caches for byName and byPrefix * Do not concatenate prefix with uid * Rename DataKey struc fields * SQLStore: Add deprecation comments for breaking migrations * Add comment * Minor corrections Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com>
This commit is contained in:
co-authored by
Joan López de la Franca Beltran
parent
8de4ffe61f
commit
4f8111e24e
@@ -146,11 +146,13 @@ func (s *SecretsService) EncryptWithDBSession(ctx context.Context, payload []byt
|
||||
|
||||
// If encryption featuremgmt.FlagEnvelopeEncryption toggle is on, use envelope encryption
|
||||
scope := opt()
|
||||
name := secrets.KeyName(scope, s.currentProviderID)
|
||||
label := secrets.KeyLabel(scope, s.currentProviderID)
|
||||
|
||||
id, dataKey, err := s.currentDataKey(ctx, name, scope, sess)
|
||||
var id string
|
||||
var dataKey []byte
|
||||
id, dataKey, err = s.currentDataKey(ctx, label, scope, sess)
|
||||
if err != nil {
|
||||
s.log.Error("Failed to get current data key", "error", err, "name", name)
|
||||
s.log.Error("Failed to get current data key", "error", err, "label", label)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -176,21 +178,21 @@ func (s *SecretsService) EncryptWithDBSession(ctx context.Context, payload []byt
|
||||
// currentDataKey looks up for current data key in cache or database by name, and decrypts it.
|
||||
// If there's no current data key in cache nor in database it generates a new random data key,
|
||||
// and stores it into both the in-memory cache and database (encrypted by the encryption provider).
|
||||
func (s *SecretsService) currentDataKey(ctx context.Context, name string, scope string, sess *xorm.Session) (string, []byte, error) {
|
||||
func (s *SecretsService) currentDataKey(ctx context.Context, label string, scope string, sess *xorm.Session) (string, []byte, error) {
|
||||
// We want only one request fetching current data key at time to
|
||||
// avoid the creation of multiple ones in case there's no one existing.
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
// We try to fetch the data key, either from cache or database
|
||||
id, dataKey, err := s.dataKeyByName(ctx, name)
|
||||
id, dataKey, err := s.dataKeyByLabel(ctx, label)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// If no existing data key was found, create a new one
|
||||
if dataKey == nil {
|
||||
id, dataKey, err = s.newDataKey(ctx, name, scope, sess)
|
||||
id, dataKey, err = s.newDataKey(ctx, label, scope, sess)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -199,16 +201,16 @@ func (s *SecretsService) currentDataKey(ctx context.Context, name string, scope
|
||||
return id, dataKey, nil
|
||||
}
|
||||
|
||||
// dataKeyByName looks up for data key in cache.
|
||||
// dataKeyByLabel looks up for data key in cache.
|
||||
// Otherwise, it fetches it from database, decrypts it and caches it decrypted.
|
||||
func (s *SecretsService) dataKeyByName(ctx context.Context, name string) (string, []byte, error) {
|
||||
func (s *SecretsService) dataKeyByLabel(ctx context.Context, label string) (string, []byte, error) {
|
||||
// 0. Get data key from in-memory cache.
|
||||
if entry, exists := s.dataKeyCache.getByName(name); exists {
|
||||
if entry, exists := s.dataKeyCache.getByLabel(label); exists && entry.active {
|
||||
return entry.id, entry.dataKey, nil
|
||||
}
|
||||
|
||||
// 1. Get data key from database.
|
||||
dataKey, err := s.store.GetCurrentDataKey(ctx, name)
|
||||
dataKey, err := s.store.GetCurrentDataKey(ctx, label)
|
||||
if err != nil {
|
||||
if errors.Is(err, secrets.ErrDataKeyNotFound) {
|
||||
return "", nil, nil
|
||||
@@ -229,13 +231,18 @@ func (s *SecretsService) dataKeyByName(ctx context.Context, name string) (string
|
||||
}
|
||||
|
||||
// 3. Store the decrypted data key into the in-memory cache.
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{id: dataKey.Id, name: dataKey.Name, dataKey: decrypted})
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{
|
||||
id: dataKey.Id,
|
||||
label: dataKey.Label,
|
||||
dataKey: decrypted,
|
||||
active: dataKey.Active,
|
||||
})
|
||||
|
||||
return dataKey.Id, decrypted, nil
|
||||
}
|
||||
|
||||
// newDataKey creates a new random data key, encrypts it and stores it into the database and cache.
|
||||
func (s *SecretsService) newDataKey(ctx context.Context, name string, scope string, sess *xorm.Session) (string, []byte, error) {
|
||||
func (s *SecretsService) newDataKey(ctx context.Context, label string, scope string, sess *xorm.Session) (string, []byte, error) {
|
||||
// 1. Create new data key.
|
||||
dataKey, err := newRandomDataKey()
|
||||
if err != nil {
|
||||
@@ -257,11 +264,11 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
|
||||
// 3. Store its encrypted value into the DB.
|
||||
id := util.GenerateShortUID()
|
||||
dbDataKey := secrets.DataKey{
|
||||
Id: id,
|
||||
Active: true,
|
||||
Name: name,
|
||||
Id: id,
|
||||
Provider: s.currentProviderID,
|
||||
EncryptedData: encrypted,
|
||||
Label: label,
|
||||
Scope: scope,
|
||||
}
|
||||
|
||||
@@ -276,7 +283,12 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
|
||||
}
|
||||
|
||||
// 4. Store the decrypted data key into the in-memory cache.
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{id: id, name: name, dataKey: dataKey})
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{
|
||||
id: id,
|
||||
label: label,
|
||||
dataKey: dataKey,
|
||||
active: true,
|
||||
})
|
||||
|
||||
return id, dataKey, nil
|
||||
}
|
||||
@@ -419,7 +431,12 @@ func (s *SecretsService) dataKeyById(ctx context.Context, id string) ([]byte, er
|
||||
}
|
||||
|
||||
// 3. Store the decrypted data key into the in-memory cache.
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{id: id, name: dataKey.Name, dataKey: decrypted})
|
||||
s.dataKeyCache.add(&dataKeyCacheEntry{
|
||||
id: dataKey.Id,
|
||||
label: dataKey.Label,
|
||||
dataKey: decrypted,
|
||||
active: dataKey.Active,
|
||||
})
|
||||
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user