Skip to content

Commit dba5806

Browse files
authored
Support key rotation for KMIP KMS (#1641)
(cherry picked from commit ae7408d) Signed-off-by: jackyalbo <[email protected]>
1 parent 9b7fcfb commit dba5806

File tree

4 files changed

+94
-23
lines changed

4 files changed

+94
-23
lines changed

pkg/util/kms/kms_kmip.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const (
1414
KMIPEndpoint = "KMIP_ENDPOINT"
1515
KMIPSecret = "KMIP_CERTS_SECRET"
1616
KMIPUniqueID = "UniqueIdentifier"
17+
NewKMIPUniqueID = "UniqueIdentifierNew"
1718
KMIPTLSServerName = "TLS_SERVER_NAME"
1819
KMIPReadTimeOut = "READ_TIMEOUT"
1920
KMIPWriteTimeOut = "WRITE_TIMEOUT"
@@ -25,6 +26,9 @@ const (
2526

2627
// KMIP is a kmip driver
2728
type KMIP struct {
29+
UID string // NooBaa system UID
30+
name string // NooBaa system name
31+
ns string // NooBaa system namespace
2832
}
2933

3034
// NewKMIP is KMIP driver constructor
@@ -33,7 +37,7 @@ func NewKMIP(
3337
namespace string,
3438
uid string,
3539
) Driver {
36-
return &KMIP{}
40+
return &KMIP{uid, name, namespace}
3741
}
3842

3943
//
@@ -108,7 +112,7 @@ func (k *KMIP) DeleteContext() map[string]string {
108112
// Version returns the current driver KMS version
109113
// either single string or map, i.e. rotating key
110114
func (k *KMIP) Version(kms *KMS) Version {
111-
return &VersionSingleSecret{kms, nil}
115+
return &VersionRotatingSecret{VersionBase{kms, nil}, k.name, k.ns}
112116
}
113117

114118
// Register KMIP driver with KMS layer

pkg/util/kms/kms_kmip_storage.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"bytes"
66
"fmt"
7+
"strings"
78
"time"
89

910
"crypto/tls"
@@ -34,8 +35,6 @@ const (
3435
protocolMajor = 1
3536
protocolMinor = 4
3637

37-
// Expected secret data length in bits
38-
cryptographicLength = 256
3938
)
4039

4140
// KMIPSecretStorage is a KMIP backend Key Management Systems (KMS)
@@ -261,10 +260,15 @@ func (k *KMIPSecretStorage) GetSecret(
261260

262261
log := util.Logger()
263262

263+
lookfor := KMIPUniqueID // Addition to upgrade
264+
if strings.HasSuffix(secretID, "-root-master-key-backend") {
265+
lookfor = NewKMIPUniqueID
266+
}
267+
264268
// KMIP key uniqueIdentifier
265-
uniqueIdentifier, exists := k.secret.StringData[KMIPUniqueID]
269+
uniqueIdentifier, exists := k.secret.StringData[lookfor]
266270
if !exists {
267-
log.Errorf("KMIPSecretStorage.GetSecret() uniqueIdentifier %v does not exist in secret %v", KMIPUniqueID, k.secret)
271+
log.Errorf("KMIPSecretStorage.GetSecret() uniqueIdentifier %v does not exist in secret %v", lookfor, k.secret)
268272
return nil, secrets.NoVersion, secrets.ErrInvalidSecretId
269273
}
270274

@@ -305,9 +309,6 @@ func (k *KMIPSecretStorage) GetSecret(
305309
if getRespPayload.SymmetricKey.KeyBlock.KeyFormatType != kmip14.KeyFormatTypeRaw {
306310
return nil, secrets.NoVersion, fmt.Errorf("Unexpected KeyBlock format type actual %v, expected KeyFormatTypeRaw %v", getRespPayload.SymmetricKey.KeyBlock.KeyFormatType, kmip14.KeyFormatTypeRaw)
307311
}
308-
if getRespPayload.SymmetricKey.KeyBlock.CryptographicLength != cryptographicLength {
309-
return nil, secrets.NoVersion, fmt.Errorf("Unexpected KeyBlock crypto len actual %v, expected %v", getRespPayload.SymmetricKey.KeyBlock.CryptographicLength, cryptographicLength)
310-
}
311312
if getRespPayload.SymmetricKey.KeyBlock.CryptographicAlgorithm != kmip14.CryptographicAlgorithmAES {
312313
return nil, secrets.NoVersion, fmt.Errorf("Unexpected KeyBlock crypto algo actual %v, expected CryptographicAlgorithmAES %v", getRespPayload.SymmetricKey.KeyBlock.CryptographicAlgorithm, kmip14.CryptographicAlgorithmAES)
313314
}
@@ -329,10 +330,6 @@ func (k *KMIPSecretStorage) PutSecret(
329330
keyContext map[string]string,
330331
) (secrets.Version, error) {
331332
log := util.Logger()
332-
if _, exists := k.secret.StringData[KMIPUniqueID]; exists {
333-
log.Errorf("KMIPSecretStorage.PutSecret() Key UniqueIdentifier %v was not found in the secret", KMIPUniqueID)
334-
return secrets.NoVersion, secrets.ErrSecretExists
335-
}
336333

337334
// Register the key value the KMIP endpoint
338335
value := plainText[secretID].(string)
@@ -356,7 +353,7 @@ func (k *KMIPSecretStorage) PutSecret(
356353
KeyValue: &kmip.KeyValue{
357354
KeyMaterial: valueBytes,
358355
},
359-
CryptographicLength: cryptographicLength,
356+
CryptographicLength: len(valueBytes) * 8, // in bits
360357
CryptographicAlgorithm: kmip14.CryptographicAlgorithmAES,
361358
},
362359
},
@@ -380,7 +377,7 @@ func (k *KMIPSecretStorage) PutSecret(
380377
return secrets.NoVersion, err
381378
}
382379

383-
k.secret.StringData[KMIPUniqueID] = registerRespPayload.UniqueIdentifier
380+
k.secret.StringData[NewKMIPUniqueID] = registerRespPayload.UniqueIdentifier
384381
if !util.KubeUpdate(k.secret) {
385382
log.Errorf("Failed to update KMS secret %v in ns %v", k.secret.Name, k.secret.Namespace)
386383
return secrets.NoVersion, fmt.Errorf("Failed to update KMS secret %v in ns %v", k.secret.Name, k.secret.Namespace)
@@ -396,8 +393,12 @@ func (k *KMIPSecretStorage) DeleteSecret(
396393
) error {
397394
log := util.Logger()
398395

396+
lookfor := KMIPUniqueID // Addition to upgrade
397+
if strings.HasSuffix(secretID, "-root-master-key-backend") {
398+
lookfor = NewKMIPUniqueID
399+
}
399400
// Find the key ID
400-
uniqueIdentifier, exists := k.secret.StringData[KMIPUniqueID]
401+
uniqueIdentifier, exists := k.secret.StringData[lookfor]
401402
if !exists {
402403
log.Errorf("KMIPSecretStorage.DeleteSecret() No uniqueIdentifier in the secret")
403404
return secrets.ErrInvalidSecretId
@@ -437,8 +438,8 @@ func (k *KMIPSecretStorage) DeleteSecret(
437438
return fmt.Errorf("Unexpected uniqueIdentifier %v in destroy response , expected %v", destroyRespPayload.UniqueIdentifier, uniqueIdentifier)
438439
}
439440

440-
delete(k.secret.Data, KMIPUniqueID)
441-
delete(k.secret.StringData, KMIPUniqueID)
441+
delete(k.secret.Data, lookfor)
442+
delete(k.secret.StringData, lookfor)
442443
if !util.KubeUpdate(k.secret) {
443444
log.Errorf("Failed to update KMS secret %v in ns %v", k.secret.Name, k.secret.Namespace)
444445
return fmt.Errorf("Failed to update KMS secret %v in ns %v", k.secret.Name, k.secret.Namespace)

pkg/util/kms/kms_version.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package kms
22

33
import (
4+
"encoding/base64"
5+
"encoding/json"
46
"fmt"
57
"sort"
68
"strconv"
@@ -44,7 +46,7 @@ func (v *VersionSingleSecret) Get() error {
4446
s, _, err := v.k.GetSecret(v.k.driver.Path(), v.k.driver.GetContext())
4547
if err != nil {
4648
// handle k8s get from non-existent secret
47-
if strings.Contains(err.Error(), "not found") {
49+
if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "does not exist") {
4850
return secrets.ErrInvalidSecretId
4951
}
5052
return err
@@ -107,17 +109,33 @@ func (v *VersionRotatingSecret) Get() error {
107109
s, _, err := v.k.GetSecret(v.BackendSecretName(), v.k.driver.GetContext())
108110
if err != nil {
109111
// handle k8s get from non-existent secret
110-
if strings.Contains(err.Error(), "not found") {
112+
if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "does not exist") {
111113
return secrets.ErrInvalidSecretId
112114
}
113115
return err
114116
}
115117

118+
if (v.k.driver.Name() == "KMIPSecret") {
119+
encodedData, ok := s[v.BackendSecretName()]
120+
if !ok {
121+
return secrets.ErrInvalidSecretData
122+
}
123+
data := map[string]string{}
124+
decodedString, err := base64.StdEncoding.DecodeString(encodedData.(string))
125+
if err != nil {
126+
return secrets.ErrInvalidSecretData
127+
}
128+
err = json.Unmarshal(decodedString, &data)
129+
if err != nil {
130+
return secrets.ErrInvalidSecretData
131+
}
132+
v.data = data
133+
return nil
134+
}
116135
rc := map[string]string{}
117136
for k, v := range s {
118137
rc[k] = v.(string)
119138
}
120-
121139
v.data = rc
122140
return nil
123141
}
@@ -139,7 +157,17 @@ func (v *VersionRotatingSecret) Set(val string) error {
139157
s[ActiveRootKey] = key
140158
s[key] = val
141159
v.data = s
142-
_, err := v.k.PutSecret(v.BackendSecretName(), toInterfaceMap(s), v.k.driver.SetContext())
160+
var err error
161+
if (v.k.driver.Name() == "KMIPSecret") {
162+
jsonData, err := json.Marshal(s)
163+
encodedString := base64.StdEncoding.EncodeToString(jsonData)
164+
if err != nil {
165+
return err
166+
}
167+
_, err = v.k.PutSecret(v.BackendSecretName(), map[string]interface{}{v.BackendSecretName(): encodedString}, v.k.driver.SetContext())
168+
return err
169+
}
170+
_, err = v.k.PutSecret(v.BackendSecretName(), toInterfaceMap(s), v.k.driver.SetContext())
143171
return err
144172
}
145173

pkg/util/kms/test/kmip/kms_kmip_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func checkExternalSecret(noobaa *nbv1.NooBaa, expectExists bool) {
4141
secret.Namespace = noobaa.Namespace
4242
secret.Name = k.TokenSecretName
4343
Expect(util.KubeCheck(secret)).To(BeTrue())
44-
_, exists := secret.StringData[kms.KMIPUniqueID]
44+
_, exists := secret.StringData[kms.NewKMIPUniqueID]
4545
Expect(exists == expectExists).To(BeTrue())
4646
}
4747

@@ -119,4 +119,42 @@ var _ = Describe("KMS - KMIP", func() {
119119
Expect(util.KubeDelete(noobaa)).To(BeTrue())
120120
})
121121
})
122+
123+
Context("Verify Rotate", func() {
124+
noobaa := getMiniNooBaa()
125+
noobaa.Spec.Security.KeyManagementService = simpleKmsSpec(tokenSecretName, apiAddress)
126+
noobaa.Spec.Security.KeyManagementService.EnableKeyRotation = true
127+
noobaa.Spec.Security.KeyManagementService.Schedule = "* * * * *" // every min
128+
129+
Specify("Verify API Address", func() {
130+
Expect(apiAddressFound).To(BeTrue())
131+
})
132+
Specify("Create key rotate schedule system", func() {
133+
Expect(util.KubeCreateFailExisting(noobaa)).To(BeTrue())
134+
})
135+
Specify("Verify KMS condition Type", func() {
136+
Expect(util.NooBaaCondition(noobaa, nbv1.ConditionTypeKMSType, "kmip")).To(BeTrue())
137+
})
138+
Specify("Verify KMS condition status Init", func() {
139+
Expect(util.NooBaaCondStatus(noobaa, nbv1.ConditionKMSInit)).To(BeTrue())
140+
})
141+
Specify("Restart NooBaa operator", func() {
142+
podList := &corev1.PodList{}
143+
podSelector, _ := labels.Parse("noobaa-operator=deployment")
144+
listOptions := client.ListOptions{Namespace: options.Namespace, LabelSelector: podSelector}
145+
146+
Expect(util.KubeList(podList, &listOptions)).To(BeTrue())
147+
Expect(len(podList.Items)).To(BeEquivalentTo(1))
148+
Expect(util.KubeDelete(&podList.Items[0])).To(BeTrue())
149+
})
150+
Specify("Verify KMS condition status Sync", func() {
151+
Expect(util.NooBaaCondStatus(noobaa, nbv1.ConditionKMSSync)).To(BeTrue())
152+
})
153+
Specify("Verify KMS condition status Key Rotate", func() {
154+
Expect(util.NooBaaCondStatus(noobaa, nbv1.ConditionKMSKeyRotate)).To(BeTrue())
155+
})
156+
Specify("Delete NooBaa", func() {
157+
Expect(util.KubeDelete(noobaa)).To(BeTrue())
158+
})
159+
})
122160
})

0 commit comments

Comments
 (0)