Skip to content

Commit f476c98

Browse files
authored
Merge pull request #563 from saad-ali/fixCmekMatch
Fix Random CMEK Disk Creation Failure (disk already exists)
2 parents 82298d1 + 87a4a3f commit f476c98

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

pkg/gce-cloud-provider/compute/gce-compute.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const (
3535
operationStatusDone = "DONE"
3636
waitForSnapshotCreationTimeOut = 2 * time.Minute
3737
diskKind = "compute#disk"
38+
cryptoKeyVerDelimiter = "/cryptoKeyVersions"
3839
)
3940

4041
type GCECompute interface {
@@ -256,7 +257,9 @@ func ValidateDiskParameters(disk *CloudDisk, params common.DiskParameters) error
256257
return fmt.Errorf("actual disk replication type %v did not match expected param %s", disk.Type(), "regional-pd")
257258
}
258259

259-
if disk.GetKMSKeyName() != params.DiskEncryptionKMSKey {
260+
if !kmsKeyEqual(
261+
disk.GetKMSKeyName(), /* fetchedKMSKey */
262+
params.DiskEncryptionKMSKey /* storageClassKMSKey */) {
260263
return fmt.Errorf("actual disk KMS key name %s did not match expected param %s", disk.GetKMSKeyName(), params.DiskEncryptionKMSKey)
261264
}
262265

@@ -767,3 +770,21 @@ func (cloud *CloudProvider) waitForSnapshotCreation(ctx context.Context, snapsho
767770
}
768771
}
769772
}
773+
774+
// kmsKeyEqual returns true if fetchedKMSKey and storageClassKMSKey refer to the same key.
775+
// fetchedKMSKey - key returned by the server
776+
// example: projects/{0}/locations/{1}/keyRings/{2}/cryptoKeys/{3}/cryptoKeyVersions/{4}
777+
// storageClassKMSKey - key as provided by the client
778+
// example: projects/{0}/locations/{1}/keyRings/{2}/cryptoKeys/{3}
779+
// cryptoKeyVersions should be disregarded if the rest of the key is identical.
780+
func kmsKeyEqual(fetchedKMSKey, storageClassKMSKey string) bool {
781+
return removeCryptoKeyVersion(fetchedKMSKey) == removeCryptoKeyVersion(storageClassKMSKey)
782+
}
783+
784+
func removeCryptoKeyVersion(kmsKey string) string {
785+
i := strings.LastIndex(kmsKey, cryptoKeyVerDelimiter)
786+
if i > 0 {
787+
return kmsKey[:i]
788+
}
789+
return kmsKey
790+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package gcecloudprovider
16+
17+
import (
18+
"testing"
19+
20+
computev1 "google.golang.org/api/compute/v1"
21+
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
22+
)
23+
24+
func TestValidateDiskParameters(t *testing.T) {
25+
testCases := []struct {
26+
fetchedKMSKey string
27+
storageClassKMSKey string
28+
expectErr bool
29+
}{
30+
{
31+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key/cryptoKeyVersions/8",
32+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
33+
expectErr: false,
34+
},
35+
{
36+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
37+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
38+
expectErr: false,
39+
},
40+
{
41+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/garbage/cryptoKeyVersions/8",
42+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
43+
expectErr: true,
44+
},
45+
{
46+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/garbage",
47+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
48+
expectErr: true,
49+
},
50+
{
51+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/test-key",
52+
storageClassKMSKey: "projects/my-project/locations/us-west1/keyRings/TestKeyRing/cryptoKeys/test-key",
53+
expectErr: true,
54+
},
55+
{
56+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/foobar/cryptoKeyVersions/8",
57+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/foo",
58+
expectErr: true,
59+
},
60+
{
61+
fetchedKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/foobar",
62+
storageClassKMSKey: "projects/my-project/locations/us-central1/keyRings/TestKeyRing/cryptoKeys/foo",
63+
expectErr: true,
64+
},
65+
}
66+
67+
for i, tc := range testCases {
68+
// Arrange
69+
existingDisk := &CloudDisk{
70+
ZonalDisk: &computev1.Disk{
71+
Id: 546559531467326555,
72+
CreationTimestamp: "2020-07-24T17:20:06.292-07:00",
73+
Name: "test-disk",
74+
SizeGb: 500,
75+
Zone: "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c",
76+
Status: "READY",
77+
SelfLink: "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c/disks/test-disk",
78+
Type: "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c/diskTypes/pd-standard",
79+
DiskEncryptionKey: &computev1.CustomerEncryptionKey{
80+
KmsKeyName: tc.fetchedKMSKey,
81+
},
82+
LabelFingerprint: "42WmSpB8rSM=",
83+
PhysicalBlockSizeBytes: 4096,
84+
Kind: "compute#disk",
85+
},
86+
}
87+
88+
storageClassParams := common.DiskParameters{
89+
DiskType: "pd-standard",
90+
ReplicationType: "none",
91+
DiskEncryptionKMSKey: tc.storageClassKMSKey,
92+
}
93+
94+
// Act
95+
err := ValidateDiskParameters(existingDisk, storageClassParams)
96+
97+
// Assert
98+
if !tc.expectErr && err != nil {
99+
t.Fatalf("Test case #%v: ValidateDiskParameters did not expect error, but got %v", i, err)
100+
}
101+
if tc.expectErr && err == nil {
102+
t.Fatalf("Test case #%v: ValidateDiskParameters expected error, but got no error", i)
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)