Skip to content

Commit 34e62c9

Browse files
committed
add e2e test for sas token and key vault suppport #103
1 parent 7dda7ba commit 34e62c9

File tree

202 files changed

+27093
-105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

202 files changed

+27093
-105
lines changed

go.mod

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module sigs.k8s.io/blob-csi-driver
22

3-
go 1.17
3+
go 1.18
44

55
require (
66
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible
7+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0
78
github.com/Azure/go-autorest/autorest v0.11.27
89
github.com/Azure/go-autorest/autorest/adal v0.9.20
910
github.com/Azure/go-autorest/autorest/to v0.4.0
@@ -18,7 +19,7 @@ require (
1819
github.com/pborman/uuid v1.2.0
1920
github.com/pelletier/go-toml v1.9.4
2021
github.com/stretchr/testify v1.7.1
21-
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
22+
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
2223
google.golang.org/grpc v1.42.0
2324
google.golang.org/protobuf v1.27.1
2425
k8s.io/api v0.24.1
@@ -34,12 +35,19 @@ require (
3435
)
3536

3637
require (
38+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1
39+
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0
40+
)
41+
42+
require (
43+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
3744
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
3845
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
3946
github.com/Azure/go-autorest/autorest/mocks v0.4.2 // indirect
4047
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
4148
github.com/Azure/go-autorest/logger v0.2.1 // indirect
4249
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
50+
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // indirect
4351
github.com/aws/aws-sdk-go v1.38.49 // indirect
4452
github.com/beorn7/perks v1.0.1 // indirect
4553
github.com/bits-and-blooms/bitset v1.2.0 // indirect
@@ -53,6 +61,7 @@ require (
5361
github.com/fsnotify/fsnotify v1.5.4 // indirect
5462
github.com/go-logr/logr v1.2.0 // indirect
5563
github.com/gogo/protobuf v1.3.2 // indirect
64+
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
5665
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
5766
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
5867
github.com/google/go-cmp v0.5.6 // indirect
@@ -63,6 +72,7 @@ require (
6372
github.com/inconshreveable/mousetrap v1.0.0 // indirect
6473
github.com/jmespath/go-jmespath v0.4.0 // indirect
6574
github.com/json-iterator/go v1.1.12 // indirect
75+
github.com/kylelemons/godebug v1.1.0 // indirect
6676
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
6777
github.com/moby/spdystream v0.2.0 // indirect
6878
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -71,6 +81,7 @@ require (
7181
github.com/opencontainers/go-digest v1.0.0 // indirect
7282
github.com/opencontainers/runc v1.0.2 // indirect
7383
github.com/opencontainers/selinux v1.8.2 // indirect
84+
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
7485
github.com/pkg/errors v0.9.1 // indirect
7586
github.com/pmezard/go-difflib v1.0.0 // indirect
7687
github.com/prometheus/client_golang v1.12.1 // indirect
@@ -89,7 +100,7 @@ require (
89100
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
90101
go.opentelemetry.io/otel/trace v0.20.0 // indirect
91102
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
92-
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
103+
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
93104
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
94105
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
95106
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect

go.sum

Lines changed: 24 additions & 21 deletions
Large diffs are not rendered by default.

test/e2e/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ export set AZURE_CLIENT_SECRET=
1616
# If the the test is not for the public Azure, e.g. Azure China Cloud, then you need to set AZURE_CLOUD_NAME and AZURE_LOCATION.
1717
# For Azure Stack Clound, you need to set AZURE_ENVIRONMENT_FILEPATH for your cloud environment.
1818
# If you have an existing resource group created for the test, then you need to set variable AZURE_RESOURCE_GROUP.
19+
# If you are going to test reading storage account key(or sastoken) from Azure Key Vault, then you need to set variable AZURE_OBJECT_ID as the objectId of agentpool Managed Identity
1920
export set AZURE_CLOUD_NAME=
2021
export set AZURE_LOCATION=
2122
export set AZURE_ENVIRONMENT_FILEPATH=
2223
export set AZURE_RESOURCE_GROUP=
24+
export set AZURE_OBJECT_ID=
2325
```
2426

2527
### Run test

test/e2e/pre_provisioning_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,46 @@ var _ = ginkgo.Describe("[blob-csi-e2e] Pre-Provisioned", func() {
250250
}
251251
test.Run(cs, ns)
252252
})
253+
254+
ginkgo.It("should use Key Vault", func() {
255+
req := makeCreateVolumeReq("pre-provisioned-key-vault", ns.Name)
256+
resp, err := blobDriver.CreateVolume(context.Background(), req)
257+
if err != nil {
258+
ginkgo.Fail(fmt.Sprintf("create volume error: %v", err))
259+
}
260+
volumeID = resp.Volume.VolumeId
261+
ginkgo.By(fmt.Sprintf("Successfully provisioned blob volume: %q\n", volumeID))
262+
263+
volumeSize := fmt.Sprintf("%dGi", defaultVolumeSize)
264+
reclaimPolicy := v1.PersistentVolumeReclaimRetain
265+
volumeBindingMode := storagev1.VolumeBindingImmediate
266+
267+
pods := []testsuites.PodDetails{
268+
{
269+
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
270+
Volumes: []testsuites.VolumeDetails{
271+
{
272+
VolumeID: volumeID,
273+
FSType: "ext4",
274+
ClaimSize: volumeSize,
275+
ReclaimPolicy: &reclaimPolicy,
276+
VolumeBindingMode: &volumeBindingMode,
277+
VolumeMount: testsuites.VolumeMountDetails{
278+
NameGenerate: "test-volume-",
279+
MountPathGenerate: "/mnt/test-",
280+
},
281+
},
282+
},
283+
},
284+
}
285+
286+
test := testsuites.PreProvisionedKeyVaultTest{
287+
CSIDriver: testDriver,
288+
Pods: pods,
289+
Driver: blobDriver,
290+
}
291+
test.Run(cs, ns)
292+
})
253293
})
254294

255295
func makeCreateVolumeReq(volumeName, secretNamespace string) *csi.CreateVolumeRequest {
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
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+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package testsuites
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"os"
23+
"time"
24+
25+
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
26+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
27+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
28+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault"
29+
"github.com/onsi/ginkgo"
30+
v1 "k8s.io/api/core/v1"
31+
clientset "k8s.io/client-go/kubernetes"
32+
"k8s.io/kubernetes/test/e2e/framework"
33+
"sigs.k8s.io/blob-csi-driver/pkg/blob"
34+
"sigs.k8s.io/blob-csi-driver/test/e2e/driver"
35+
"sigs.k8s.io/blob-csi-driver/test/utils/credentials"
36+
)
37+
38+
var (
39+
subscriptionID string
40+
resourceGroupName string
41+
location string
42+
vaultName string
43+
TenantID string
44+
ObjectID string
45+
)
46+
47+
// PreProvisionedKeyVaultTest will provision required PV(s), PVC(s) and Pod(s)
48+
// Testing that the Pod(s) can be created successfully with provided Key Vault
49+
// which is used to store storage account name and key(or sastoken)
50+
type PreProvisionedKeyVaultTest struct {
51+
CSIDriver driver.PreProvisionedVolumeTestDriver
52+
Pods []PodDetails
53+
Driver *blob.Driver
54+
}
55+
56+
func (t *PreProvisionedKeyVaultTest) Run(client clientset.Interface, namespace *v1.Namespace) {
57+
e2eCred, err := credentials.ParseAzureCredentialFile()
58+
framework.ExpectNoError(err, fmt.Sprintf("Error ParseAzureCredentialFile: %v", err))
59+
60+
subscriptionID = e2eCred.SubscriptionID
61+
resourceGroupName = e2eCred.ResourceGroup
62+
location = e2eCred.Location
63+
TenantID = e2eCred.TenantID
64+
ObjectID = os.Getenv("AZURE_OBJECT_ID")
65+
framework.ExpectNotEqual(len(ObjectID), 0, "env AZURE_OBJECT_ID must be set")
66+
vaultName = "blobcsidriver-kv-test"
67+
68+
for _, pod := range t.Pods {
69+
for n, volume := range pod.Volumes {
70+
accountName, accountKey, _, containerName, err := t.Driver.GetStorageAccountAndContainer(context.TODO(), volume.VolumeID, nil, nil)
71+
framework.ExpectNoError(err, fmt.Sprintf("Error GetStorageAccountAndContainer from volumeID(%s): %v", volume.VolumeID, err))
72+
73+
azureCred, err := azidentity.NewDefaultAzureCredential(nil)
74+
framework.ExpectNoError(err)
75+
76+
vault, err := createVault(context.TODO(), azureCred)
77+
framework.ExpectNoError(err)
78+
defer cleanVault(context.TODO(), azureCred)
79+
80+
accountKeySecret, err := createSecret(context.TODO(), azureCred, accountName+"-key", accountKey)
81+
framework.ExpectNoError(err)
82+
83+
// TODO: test SAS token
84+
// accountSASSecret, err := createSecret(context.TODO(), azureCred, accountName+"-sas", accountSasToken)
85+
// framework.ExpectNoError(err)
86+
87+
pod.Volumes[n].ContainerName = containerName
88+
pod.Volumes[n].StorageAccountname = accountName
89+
pod.Volumes[n].KeyVaultURL = *vault.Properties.VaultURI
90+
pod.Volumes[n].KeyVaultSecretName = *accountKeySecret.Name
91+
tpod, cleanup := pod.SetupWithPreProvisionedVolumes(client, namespace, t.CSIDriver)
92+
// defer must be called here for resources not get removed before using them
93+
for i := range cleanup {
94+
defer cleanup[i]()
95+
}
96+
97+
ginkgo.By("deploying the pod")
98+
tpod.Create()
99+
defer tpod.Cleanup()
100+
ginkgo.By("checking that the pods command exits with no error")
101+
tpod.WaitForSuccess()
102+
ginkgo.By("sleep........")
103+
time.Sleep(5 * time.Minute)
104+
}
105+
}
106+
}
107+
108+
func createVault(ctx context.Context, cred azcore.TokenCredential) (*armkeyvault.Vault, error) {
109+
vaultsClient, err := armkeyvault.NewVaultsClient(subscriptionID, cred, nil)
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
pollerResp, err := vaultsClient.BeginCreateOrUpdate(
115+
ctx,
116+
resourceGroupName,
117+
vaultName,
118+
armkeyvault.VaultCreateOrUpdateParameters{
119+
Location: to.Ptr(location),
120+
Properties: &armkeyvault.VaultProperties{
121+
SKU: &armkeyvault.SKU{
122+
Family: to.Ptr(armkeyvault.SKUFamilyA),
123+
Name: to.Ptr(armkeyvault.SKUNameStandard),
124+
},
125+
TenantID: to.Ptr(TenantID),
126+
AccessPolicies: []*armkeyvault.AccessPolicyEntry{
127+
{
128+
TenantID: to.Ptr(TenantID),
129+
ObjectID: to.Ptr(ObjectID),
130+
Permissions: &armkeyvault.Permissions{
131+
Secrets: []*armkeyvault.SecretPermissions{
132+
to.Ptr(armkeyvault.SecretPermissionsGet),
133+
},
134+
},
135+
},
136+
},
137+
},
138+
},
139+
nil,
140+
)
141+
if err != nil {
142+
return nil, err
143+
}
144+
145+
resp, err := pollerResp.PollUntilDone(ctx, nil)
146+
if err != nil {
147+
return nil, err
148+
}
149+
return &resp.Vault, nil
150+
}
151+
152+
func cleanVault(ctx context.Context, cred azcore.TokenCredential) {
153+
err := deleteVault(ctx, cred)
154+
framework.ExpectNoError(err)
155+
156+
err = purgeDeleted(ctx, cred)
157+
framework.ExpectNoError(err)
158+
}
159+
160+
func deleteVault(ctx context.Context, cred azcore.TokenCredential) error {
161+
vaultsClient, err := armkeyvault.NewVaultsClient(subscriptionID, cred, nil)
162+
if err != nil {
163+
return err
164+
}
165+
166+
_, err = vaultsClient.Delete(ctx, resourceGroupName, vaultName, nil)
167+
if err != nil {
168+
return err
169+
}
170+
return nil
171+
}
172+
173+
func purgeDeleted(ctx context.Context, cred azcore.TokenCredential) error {
174+
vaultsClient, err := armkeyvault.NewVaultsClient(subscriptionID, cred, nil)
175+
if err != nil {
176+
return err
177+
}
178+
179+
pollerResp, err := vaultsClient.BeginPurgeDeleted(ctx, vaultName, location, nil)
180+
if err != nil {
181+
return err
182+
}
183+
184+
_, err = pollerResp.PollUntilDone(ctx, nil)
185+
if err != nil {
186+
return err
187+
}
188+
189+
return nil
190+
}
191+
192+
func createSecret(ctx context.Context, cred azcore.TokenCredential, secretName, secretValue string) (*armkeyvault.Secret, error) {
193+
secretsClient, err := armkeyvault.NewSecretsClient(subscriptionID, cred, nil)
194+
if err != nil {
195+
return nil, err
196+
}
197+
198+
secretResp, err := secretsClient.CreateOrUpdate(
199+
ctx,
200+
resourceGroupName,
201+
vaultName,
202+
secretName,
203+
armkeyvault.SecretCreateOrUpdateParameters{
204+
Properties: &armkeyvault.SecretProperties{
205+
Attributes: &armkeyvault.SecretAttributes{
206+
Enabled: to.Ptr(true),
207+
},
208+
Value: to.Ptr(secretValue),
209+
},
210+
},
211+
nil,
212+
)
213+
if err != nil {
214+
return nil, err
215+
}
216+
217+
return &secretResp.Secret, nil
218+
}

test/e2e/testsuites/specs.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ type VolumeDetails struct {
5252
DataSource *DataSource
5353
ContainerName string
5454
NodeStageSecretRef string
55+
StorageAccountname string
56+
KeyVaultURL string
57+
KeyVaultSecretName string
5558
}
5659

5760
type VolumeMode int
@@ -204,6 +207,15 @@ func (volume *VolumeDetails) SetupPreProvisionedPersistentVolumeClaim(client cli
204207
if volume.ContainerName != "" {
205208
attrib["containerName"] = volume.ContainerName
206209
}
210+
if volume.StorageAccountname != "" {
211+
attrib["storageAccountName"] = volume.StorageAccountname
212+
}
213+
if volume.KeyVaultURL != "" {
214+
attrib["keyVaultURL"] = volume.KeyVaultURL
215+
}
216+
if volume.KeyVaultSecretName != "" {
217+
attrib["keyVaultSecretName"] = volume.KeyVaultSecretName
218+
}
207219
nodeStageSecretRef := volume.NodeStageSecretRef
208220
pv := csiDriver.GetPersistentVolume(volume.VolumeID, volume.FSType, volume.ClaimSize, volume.ReclaimPolicy, namespace.Name, attrib, nodeStageSecretRef)
209221
tpv := NewTestPreProvisionedPersistentVolume(client, pv)

0 commit comments

Comments
 (0)