-
Notifications
You must be signed in to change notification settings - Fork 277
/
azure.bats
379 lines (274 loc) · 16 KB
/
azure.bats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#!/usr/bin/env bats
load helpers
BATS_TESTS_DIR=test/bats/tests/azure
WAIT_TIME=60
SLEEP_TIME=1
NAMESPACE=kube-system
NODE_SELECTOR_OS=linux
BASE64_FLAGS="-w 0"
if [[ "$OSTYPE" == *"darwin"* ]]; then
BASE64_FLAGS="-b 0"
fi
if [ $TEST_WINDOWS ]; then
NODE_SELECTOR_OS=windows
fi
if [ -z "$AUTO_ROTATE_SECRET_NAME" ]; then
export AUTO_ROTATE_SECRET_NAME=secret-$(openssl rand -hex 6)
fi
if [ -z "$IS_YAML_TEST" ]; then
export IS_YAML_TEST=false
fi
export KEYVAULT_NAME=${KEYVAULT_NAME:-csi-secrets-store-e2e}
export SECRET_NAME=${KEYVAULT_SECRET_NAME:-secret1}
export SECRET_VERSION=${KEYVAULT_SECRET_VERSION:-""}
export SECRET_VALUE=${KEYVAULT_SECRET_VALUE:-"test"}
export KEY_NAME=${KEYVAULT_KEY_NAME:-key1}
export KEY_VERSION=${KEYVAULT_KEY_VERSION:-7cc095105411491b84fe1b92ebbcf01a}
export KEY_VALUE_CONTAINS=${KEYVAULT_KEY_VALUE:-"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4K2FadlhJN2FldG5DbzI3akVScgpheklaQ2QxUlBCQVZuQU1XcDhqY05TQk5MOXVuOVJrenJHOFd1SFBXUXNqQTA2RXRIOFNSNWtTNlQvaGQwMFNRCk1aODBMTlNxYkkwTzBMcWMzMHNLUjhTQ0R1cEt5dkpkb01LSVlNWHQzUlk5R2Ywam1ucHNKOE9WbDFvZlRjOTIKd1RINXYyT2I1QjZaMFd3d25MWlNiRkFnSE1uTHJtdEtwZTVNcnRGU21nZS9SL0J5ZXNscGU0M1FubnpndzhRTwpzU3ZMNnhDU21XVW9WQURLL1MxREU0NzZBREM2a2hGTjF5ZHUzbjVBcnREVGI0c0FjUHdTeXB3WGdNM3Y5WHpnClFKSkRGT0JJOXhSTW9UM2FjUWl0Z0c2RGZibUgzOWQ3VU83M0o3dUFQWUpURG1pZGhrK0ZFOG9lbjZWUG9YRy8KNXdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t"}
export LABEL_VALUE=${LABEL_VALUE:-"test"}
export NODE_SELECTOR_OS=$NODE_SELECTOR_OS
# export the secrets-store API version to be used
# TODO (aramase) remove this once the upgrade tests are moved to use e2e-provider
export API_VERSION=$(get_secrets_store_api_version)
setup() {
if [[ -z "${AZURE_CLIENT_ID}" ]] || [[ -z "${AZURE_CLIENT_SECRET}" ]]; then
echo "Error: Azure service principal is not provided" >&2
return 1
fi
}
@test "install azure provider" {
# install the azure provider using the helm charts
helm repo add csi-provider-azure https://azure.github.io/secrets-store-csi-driver-provider-azure/charts
helm repo update
helm upgrade --install csi csi-provider-azure/csi-secrets-store-provider-azure --namespace $NAMESPACE \
--set "secrets-store-csi-driver.install=false" \
--set "windows.enabled=$TEST_WINDOWS" \
--set "logVerbosity=5" \
--set "logFormatJSON=true" \
# wait for azure-csi-provider pod to be running
kubectl wait --for=condition=Ready --timeout=150s pods -l app=csi-secrets-store-provider-azure --namespace $NAMESPACE
}
@test "create azure k8s secret" {
run kubectl create secret generic secrets-store-creds --from-literal clientid=${AZURE_CLIENT_ID} --from-literal clientsecret=${AZURE_CLIENT_SECRET}
assert_success
# label the node publish secret ref secret
run kubectl label secret secrets-store-creds secrets-store.csi.k8s.io/used=true
assert_success
}
@test "deploy azure secretproviderclass crd" {
envsubst < $BATS_TESTS_DIR/azure_v1_secretproviderclass.yaml | kubectl apply -f -
kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure -o yaml | grep azure"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
}
@test "CSI inline volume test with pod portability" {
envsubst < $BATS_TESTS_DIR/pod-secrets-store-inline-volume-crd.yaml | kubectl apply -f -
# The wait timeout is set to 300s only for this first pod in test to accomadate for the node-driver-registrar
# registration retries on windows nodes. Based on previous tests on windows nodes, the node-driver-registrar was
# restarted 5 times before succeeding which resulted in a wait timeout of 300s.
kubectl wait --for=condition=Ready --timeout=300s pod/secrets-store-inline-crd
run kubectl get pod/secrets-store-inline-crd
assert_success
}
@test "CSI inline volume test with pod portability - read azure kv secret from pod" {
wait_for_process $WAIT_TIME $SLEEP_TIME "kubectl exec secrets-store-inline-crd -- cat /mnt/secrets-store/$SECRET_NAME | grep '${SECRET_VALUE}'"
result=$(kubectl exec secrets-store-inline-crd -- cat /mnt/secrets-store/$SECRET_NAME)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
}
@test "CSI inline volume test with pod portability - read azure kv key from pod" {
result=$(kubectl exec secrets-store-inline-crd -- cat /mnt/secrets-store/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
}
@test "CSI inline volume test with pod portability - unmount succeeds" {
# On Linux a failure to unmount the tmpfs will block the pod from being
# deleted.
run kubectl delete pod secrets-store-inline-crd
assert_success
run kubectl wait --for=delete --timeout=${WAIT_TIME}s pod/secrets-store-inline-crd
assert_success
# Sleep to allow time for logs to propagate.
sleep 10
# save debug information to archive in case of failure
archive_info
# On Windows, the failed unmount calls from: https://github.com/kubernetes-sigs/secrets-store-csi-driver/pull/545
# do not prevent the pod from being deleted. Search through the driver logs
# for the error.
run bash -c "kubectl logs -l app=secrets-store-csi-driver --tail -1 -c secrets-store -n kube-system | grep '^E.*failed to clean and unmount target path.*$'"
assert_failure
}
@test "Sync with K8s secrets - create deployment" {
envsubst < $BATS_TESTS_DIR/azure_synck8s_v1_secretproviderclass.yaml | kubectl apply -f -
kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure-sync -o yaml | grep azure"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
envsubst < $BATS_TESTS_DIR/deployment-synck8s-azure.yaml | kubectl apply -f -
envsubst < $BATS_TESTS_DIR/deployment-two-synck8s-azure.yaml | kubectl apply -f -
kubectl wait --for=condition=Ready --timeout=90s pod -l app=busybox
}
@test "Sync with K8s secrets - read secret from pod, read K8s secret, read env var, check secret ownerReferences with multiple owners" {
POD=$(kubectl get pod -l app=busybox -o jsonpath="{.items[0].metadata.name}")
result=$(kubectl exec $POD -- cat /mnt/secrets-store/secretalias)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec $POD -- cat /mnt/secrets-store/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
result=$(kubectl get secret foosecret -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec $POD -- printenv | grep SECRET_USERNAME) | awk -F"=" '{ print $2}'
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl get secret foosecret -o jsonpath="{.metadata.labels.environment}")
[[ "${result//$'\r'}" == "${LABEL_VALUE}" ]]
result=$(kubectl get secret foosecret -o jsonpath="{.metadata.labels.secrets-store\.csi\.k8s\.io/managed}")
[[ "${result//$'\r'}" == "true" ]]
run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 2"
assert_success
}
@test "Sync with K8s secrets - delete deployment, check owner ref updated, check secret deleted" {
run kubectl delete -f $BATS_TESTS_DIR/deployment-synck8s-azure.yaml
assert_success
run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 1"
assert_success
run kubectl delete -f $BATS_TESTS_DIR/deployment-two-synck8s-azure.yaml
assert_success
run wait_for_process $WAIT_TIME $SLEEP_TIME "check_secret_deleted foosecret default"
assert_success
envsubst < $BATS_TESTS_DIR/azure_synck8s_v1_secretproviderclass.yaml | kubectl delete -f -
}
@test "Test Namespaced scope SecretProviderClass - create deployment" {
run kubectl create ns test-ns
assert_success
run kubectl create secret generic secrets-store-creds --from-literal clientid=${AZURE_CLIENT_ID} --from-literal clientsecret=${AZURE_CLIENT_SECRET} -n test-ns
assert_success
# label the node publish secret ref secret
run kubectl label secret secrets-store-creds secrets-store.csi.k8s.io/used=true -n test-ns
assert_success
envsubst < $BATS_TESTS_DIR/azure_v1_secretproviderclass_ns.yaml | kubectl apply -f -
kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure-sync -o yaml | grep azure"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure-sync -n test-ns -o yaml | grep azure"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
envsubst < $BATS_TESTS_DIR/deployment-synck8s-azure.yaml | kubectl apply -n test-ns -f -
kubectl wait --for=condition=Ready --timeout=60s pod -l app=busybox -n test-ns
}
@test "Test Namespaced scope SecretProviderClass - Sync with K8s secrets - read secret from pod, read K8s secret, read env var, check secret ownerReferences" {
POD=$(kubectl get pod -l app=busybox -n test-ns -o jsonpath="{.items[0].metadata.name}")
result=$(kubectl exec -n test-ns $POD -- cat /mnt/secrets-store/secretalias)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec -n test-ns $POD -- cat /mnt/secrets-store/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
result=$(kubectl get secret foosecret -n test-ns -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec -n test-ns $POD -- printenv | grep SECRET_USERNAME) | awk -F"=" '{ print $2}'
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret test-ns 1"
assert_success
}
@test "Test Namespaced scope SecretProviderClass - Sync with K8s secrets - delete deployment, check secret deleted" {
run kubectl delete -f $BATS_TESTS_DIR/deployment-synck8s-azure.yaml -n test-ns
assert_success
run wait_for_process $WAIT_TIME $SLEEP_TIME "check_secret_deleted foosecret test-ns"
assert_success
}
@test "Test Namespaced scope SecretProviderClass - Should fail when no secret provider class in same namespace" {
run kubectl create ns negative-test-ns
assert_success
run kubectl create secret generic secrets-store-creds --from-literal clientid=${AZURE_CLIENT_ID} --from-literal clientsecret=${AZURE_CLIENT_SECRET} -n negative-test-ns
assert_success
# label the node publish secret ref secret
run kubectl label secret secrets-store-creds secrets-store.csi.k8s.io/used=true -n negative-test-ns
assert_success
envsubst < $BATS_TESTS_DIR/deployment-synck8s-azure.yaml | kubectl apply -n negative-test-ns -f -
sleep 5
POD=$(kubectl get pod -l app=busybox -n negative-test-ns -o jsonpath="{.items[0].metadata.name}")
cmd="kubectl describe pod $POD -n negative-test-ns | grep 'FailedMount.*failed to get secretproviderclass negative-test-ns/azure-sync.*not found'"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
run kubectl delete -f $BATS_TESTS_DIR/deployment-synck8s-azure.yaml -n negative-test-ns
assert_success
run kubectl delete ns negative-test-ns
assert_success
}
@test "deploy multiple azure secretproviderclass crd" {
envsubst < $BATS_TESTS_DIR/azure_v1_multiple_secretproviderclass.yaml | kubectl apply -f -
kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure-spc-0 -o yaml | grep azure-spc-0"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/azure-spc-1 -o yaml | grep azure-spc-1"
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
}
@test "deploy pod with multiple secret provider class" {
envsubst < $BATS_TESTS_DIR/pod-azure-inline-volume-multiple-spc.yaml | kubectl apply -f -
kubectl wait --for=condition=Ready --timeout=60s pod/secrets-store-inline-multiple-crd
run kubectl get pod/secrets-store-inline-multiple-crd
assert_success
}
@test "CSI inline volume test with multiple secret provider class" {
result=$(kubectl exec secrets-store-inline-multiple-crd -- cat /mnt/secrets-store-0/secretalias)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec secrets-store-inline-multiple-crd -- cat /mnt/secrets-store-0/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
result=$(kubectl exec secrets-store-inline-multiple-crd -- cat /mnt/secrets-store-1/secretalias)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec secrets-store-inline-multiple-crd -- cat /mnt/secrets-store-1/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
result=$(kubectl get secret foosecret-0 -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec secrets-store-inline-multiple-crd -- printenv | grep SECRET_USERNAME_0) | awk -F"=" '{ print $2}'
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret-0 default 1"
assert_success
result=$(kubectl get secret foosecret-1 -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec secrets-store-inline-multiple-crd -- printenv | grep SECRET_USERNAME_1) | awk -F"=" '{ print $2}'
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret-1 default 1"
assert_success
}
@test "Test auto rotation of mount contents and K8s secrets - Create deployment" {
run kubectl create ns rotation
assert_success
run kubectl create secret generic secrets-store-creds --from-literal clientid=${AZURE_CLIENT_ID} --from-literal clientsecret=${AZURE_CLIENT_SECRET} -n rotation
assert_success
# label the node publish secret ref secret
run kubectl label secret secrets-store-creds secrets-store.csi.k8s.io/used=true -n rotation
assert_success
run az login -u ${AZURE_CLIENT_ID} -p ${AZURE_CLIENT_SECRET} -t ${TENANT_ID} --service-principal
assert_success
run az keyvault secret set --vault-name ${KEYVAULT_NAME} --name ${AUTO_ROTATE_SECRET_NAME} --value secret
assert_success
envsubst < $BATS_TESTS_DIR/rotation/azure_synck8s_v1_secretproviderclass.yaml | kubectl apply -n rotation -f -
envsubst < $BATS_TESTS_DIR/rotation/pod-synck8s-azure.yaml | kubectl apply -n rotation -f -
kubectl wait -n rotation --for=condition=Ready --timeout=60s pod/secrets-store-inline-rotation
run kubectl get pod/secrets-store-inline-rotation -n rotation
assert_success
}
@test "Test auto rotation of mount contents and K8s secrets" {
result=$(kubectl exec -n rotation secrets-store-inline-rotation -- cat /mnt/secrets-store/secretalias)
[[ "${result//$'\r'}" == "secret" ]]
result=$(kubectl get secret -n rotation rotationsecret -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "secret" ]]
run az keyvault secret set --vault-name ${KEYVAULT_NAME} --name ${AUTO_ROTATE_SECRET_NAME} --value rotated
assert_success
sleep 60
result=$(kubectl exec -n rotation secrets-store-inline-rotation -- cat /mnt/secrets-store/secretalias)
[[ "${result//$'\r'}" == "rotated" ]]
result=$(kubectl get secret -n rotation rotationsecret -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "rotated" ]]
run az keyvault secret delete --vault-name ${KEYVAULT_NAME} --name ${AUTO_ROTATE_SECRET_NAME}
assert_success
run az logout
assert_success
}
teardown_file() {
archive_provider "app=csi-secrets-store-provider-azure" || true
archive_info || true
#cleanup
run kubectl delete namespace rotation
run kubectl delete namespace test-ns
run kubectl delete secret secrets-store-creds
run kubectl delete pods secrets-store-inline-crd secrets-store-inline-multiple-crd --force --grace-period 0
}