@@ -18,16 +18,21 @@ package scope
18
18
19
19
import (
20
20
"context"
21
- "encoding/base64"
21
+ "os"
22
+ "reflect"
22
23
"testing"
23
24
25
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
26
+ "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
24
27
. "github.com/onsi/gomega"
28
+ "go.uber.org/mock/gomock"
25
29
corev1 "k8s.io/api/core/v1"
26
30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
31
"k8s.io/apimachinery/pkg/runtime"
28
32
"sigs.k8s.io/controller-runtime/pkg/client/fake"
29
33
30
34
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
35
+ "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure"
31
36
)
32
37
33
38
func TestAllowedNamespaces (t * testing.T ) {
@@ -202,20 +207,15 @@ func TestHasClientSecret(t *testing.T) {
202
207
}
203
208
204
209
func TestGetTokenCredential (t * testing.T ) {
205
- g := NewWithT (t )
206
-
207
- // Test cert data was generated with this command:
208
- // openssl req -x509 -noenc -days 3650 -newkey rsa:2048 --keyout - -subj /CN=localhost | base64
209
- encodedCertData := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRRGpyZEVyOVAwVGFVRVMKZHNwRTZjeW8yMk5VOHloUnJiWWxWOVZIMnZXdm5Qc1RoWGN4aG5kK2NVcWRORUJzd2h3Z0ZsVVFjZy9lU1Z4dwpyciszbmgrYkZUWldQY1krMUxRWXhmcEtHc3JDWFFmQjgyTERKSVpEWDRnSFlyV2YzWjI3MmpYTjFYZUZBS3RpCndES2dEWFh1UEg3cjVsSDd2QzNSWGVBZmZxTHdRSmhaZitOb0hOdHY5TUg5SWRVa1FmbURGWnRJL0NRekNyYjYKK3ZPUzZFbVVEL1EyRk5IQnpneENndUdxZ055QmNRYnhKOVFuZytaaklGdWhHWVhKbHN5UlV0ZXh5elRSNS92MApWTks4VXNaZ1JCRmhYcXJCdi9Sb0NDRyt4VkpZdG1kMFFzcnZOekRxRzZRbmpVQjIxelZYcXpLRWtXMmdSdGpYCmN3NHZZUWVoQWdNQkFBRUNnZ0VBUzZ4dGpnMG5Bb2trMGpTK1pPcEtsa01aQUZhemEzWnZ5SGlwa0hEejRQTXQKdGw3UmI1b1FaR3ZXVDJyYkVPcnhleTdCQmk3TEhHaEl1OEV4UXAvaFJHUG9CQUVUUDdYbHlDZ2hXUGtQdEV0RQpkVS9tWHhMb04wTnN6SHVmLzJzaTdwbUg4WXFHWjZRQjB0Z3IyMnV0NjBtYksrQUpGc0VFZjRhU3BCVXNwZXBKCjI4MDBzUUhzcVBFNkw2a1lrZloyR1JSWTFWOXZVcllFT0RLWnBXek1oTjNVQTluQUtIOVBCNnh2UDJPZHlNTmgKaEtnbVVVTU5JRnR3cjhwWmxKbjYwY2YwVXJXcmM1Q3ZxUUx1YUdZbHpEZ1VRR1Y0SkVWanFtOUY2bE1mRVBVdwplTjcwTVZlMXBjTGVMcTJyR0NWV1UzZ2FraC9IdkpxbFIvc2E1NDZIZ3dLQmdRRHlmMXZreVg0dzVzYm9pNkRKCmNsNWRNVUx0TU1ScEIxT2FNRlZPSmpJOWdaSjhtQ2RSanFYZFlvNWFTMktJcXhpZTh0R0c5K1NvaHhEQVdsNHQKbFNVdERzRTQ0ZlNtSUxxQzV6SWF3TlJRbm5rdjBYOEx3bVl1MFFkN1lBakpNbExUV3lEUnNqRDlYUnE0bnNSKwptSlZ3cnQ4NWlTcFM1VUZ5cnlFelBiRmowd0tCZ1FEd1d6cmFlTjBFY2NmMWlJWW1Rc1l5K3lNRUFsSE5SNXlpCmdQWHVBaFN5YnYySlJlUmhkVWIzOWhMci9Mdkt3MFplWGlMV1htWVVHcGJ5elB5WEltMHMrUEwzTFdsNjVHVEYKbCtjZlY1d2ZBZERrazZyQWRFUEVFMnB4Tjg1Q2h5YVBZUG9ZcjBvaG1WOTdWUWNZYzVGcVkrajF0TTZSMVJEdAovZldCU2E4aU93S0JnUUNwYTFkdFdXVERqNGdxVWRyc3d1MndtRWtVNDd4bFVJd1ZMbTE2NHU2NHovemk5WDZLCjJXbUNhV2ZoSjhmWWlnanlpOXpkT2ZYVDFFRmMwZ1g0UExvelo1cVJQalFwbUxZVjNLYkIwRFRGZW1KYWlUZ0UKcERXMXdhNURnUTNDVzFsSWR1TlAvZm1DR2ZrZ1FUUXc2ak9GL1hiUmdNWkVFZzJPclZJNXRZRm9wd0tCZ0VSOQppcWpFdGg1VkdlakNqWStMaVpUdmNVdnNLVWs0dGM2c3R1ZXFtaUU2ZFc3UGhzT3F1cDFmOW9aZWoxaTVDbTFMCm45dThMSlJmKzFHV3pnZDNIT3NxeVhsYjdHbkRlVi9BNkhCSzg4YjJLb05uL01rNG1ETGdZWDEvckh2U3JVOUEKRUNSR2x2WTZFVFpBeFhQWFFzR3hWS25uYXRHdGlGUjVBS05senMwUEFvR0FhNStYK0RVcUdoOWFFNUlEM3dydgpqa2p4UTJLTEZKQ05TcThmOUdTdXZwdmdYc3RIaDZ3S29NNnZNd0lTaGpnWHVVUkg4VWI0dWhSc1dueE1pbGRGCjdFRStRYVdVOWpuQ20ySFFZQXJmWHJBV3c2REJ1ZGlTa0JxZ0tjNkhqREh1bjVmWGxZVW84VWVzTk1RT3JnN2IKYnlkUVo1LzRWLzFvU1dQRVRrN2pTcjA9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDVENDQWZHZ0F3SUJBZ0lVRlNudEVuK1R2NkhNMnhKUmVFQ0pwSmNDN2lVd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZERVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQjRYRFRJME1ERXdPREU1TlRReE5Gb1hEVE0wTURFdwpOVEU1TlRReE5Gb3dGREVTTUJBR0ExVUVBd3dKYkc5allXeG9iM04wTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGCkFBT0NBUThBTUlJQkNnS0NBUUVBNDYzUksvVDlFMmxCRW5iS1JPbk1xTnRqVlBNb1VhMjJKVmZWUjlyMXI1ejcKRTRWM01ZWjNmbkZLblRSQWJNSWNJQlpWRUhJUDNrbGNjSzYvdDU0Zm14VTJWajNHUHRTMEdNWDZTaHJLd2wwSAp3Zk5pd3lTR1ExK0lCMksxbjkyZHU5bzF6ZFYzaFFDcllzQXlvQTExN2p4KzYrWlIrN3d0MFYzZ0gzNmk4RUNZCldYL2phQnpiYi9UQi9TSFZKRUg1Z3hXYlNQd2tNd3EyK3Zyemt1aEpsQS8wTmhUUndjNE1Rb0xocW9EY2dYRUcKOFNmVUo0UG1ZeUJib1JtRnlaYk1rVkxYc2NzMDBlZjc5RlRTdkZMR1lFUVJZVjZxd2IvMGFBZ2h2c1ZTV0xabgpkRUxLN3pjdzZodWtKNDFBZHRjMVY2c3loSkZ0b0ViWTEzTU9MMkVIb1FJREFRQUJvMU13VVRBZEJnTlZIUTRFCkZnUVVmcnkvS0R0YW13TWxSUXNGUGJCaHpkdjJVNWN3SHdZRFZSMGpCQmd3Rm9BVWZyeS9LRHRhbXdNbFJRc0YKUGJCaHpkdjJVNWN3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBeVlzdApWdmV3S1JScHVZUldjNFhHNlduWXBoVWR5WkxNb0lscTBzeVoxYWo2WWJxb0s5Tk1IQVlFbkN2U292NnpJWk9hCnRyaHVVY2Y5R0Z6NWUwaUoyeklsRGMzMTJJd3N2NDF4aUMvYnMxNmtFbjhZZi9TdWpFWGFzajd2bUEzSHJGV2YKd1pUSC95Rkw1YXpvL2YrbEExUTI4WXdxRnBIbWxlMHkwTzUzVXRoNHAwdG13bG51K0NyTzlmSHAza1RsYjdmRAo2bXFmazlOcnQ4dE9DNGFIWURvcXRZVWdaaHg1OHhzSE1PVGV0S2VSbHA4SE1GOW9ST3RyaXo0blltNkloVHdvCjVrMUExM1MzQmpheGtaQ3lQWENnWHNzdVhhZ05MYXNycjVRcStWZ2RiL25EaFZlaFY4K1o0SjBZbnp5OU1ac0UKSDFOMU5mTXRzQStQRXF0UFhBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
210
- certPEM , err := base64 .StdEncoding .DecodeString (encodedCertData )
211
- g .Expect (err ).NotTo (HaveOccurred ())
210
+ testCertPath := "../../test/setup/certificate"
212
211
213
212
tests := []struct {
214
213
name string
215
214
cluster * infrav1.AzureCluster
216
215
secret * corev1.Secret
217
216
identity * infrav1.AzureClusterIdentity
218
217
ActiveDirectoryAuthorityHost string
218
+ cacheExpect func (* mock_azure.MockCredentialCache )
219
219
}{
220
220
{
221
221
name : "workload identity" ,
@@ -235,6 +235,14 @@ func TestGetTokenCredential(t *testing.T) {
235
235
TenantID : fakeTenantID ,
236
236
},
237
237
},
238
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
239
+ cache .EXPECT ().GetOrStoreWorkloadIdentity (gomock .Cond (func (opts * azidentity.WorkloadIdentityCredentialOptions ) bool {
240
+ // ignore tracing provider
241
+ return opts .TenantID == fakeTenantID &&
242
+ opts .ClientID == fakeClientID &&
243
+ opts .TokenFilePath == GetProjectedTokenPath ()
244
+ }))
245
+ },
238
246
},
239
247
{
240
248
name : "manual service principal" ,
@@ -251,6 +259,7 @@ func TestGetTokenCredential(t *testing.T) {
251
259
Spec : infrav1.AzureClusterIdentitySpec {
252
260
Type : infrav1 .ManualServicePrincipal ,
253
261
TenantID : fakeTenantID ,
262
+ ClientID : fakeClientID ,
254
263
ClientSecret : corev1.SecretReference {
255
264
Name : "test-identity-secret" ,
256
265
},
@@ -265,6 +274,20 @@ func TestGetTokenCredential(t *testing.T) {
265
274
},
266
275
},
267
276
ActiveDirectoryAuthorityHost : "https://login.microsoftonline.com" ,
277
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
278
+ cache .EXPECT ().GetOrStoreClientSecret (fakeTenantID , fakeClientID , "fooSecret" , gomock .Cond (func (opts * azidentity.ClientSecretCredentialOptions ) bool {
279
+ // ignore tracing provider
280
+ return reflect .DeepEqual (opts .ClientOptions .Cloud , cloud.Configuration {
281
+ ActiveDirectoryAuthorityHost : "https://login.microsoftonline.com" ,
282
+ Services : map [cloud.ServiceName ]cloud.ServiceConfiguration {
283
+ cloud .ResourceManager : {
284
+ Audience : "" ,
285
+ Endpoint : "" ,
286
+ },
287
+ },
288
+ })
289
+ }))
290
+ },
268
291
},
269
292
{
270
293
name : "service principal" ,
@@ -281,6 +304,7 @@ func TestGetTokenCredential(t *testing.T) {
281
304
Spec : infrav1.AzureClusterIdentitySpec {
282
305
Type : infrav1 .ServicePrincipal ,
283
306
TenantID : fakeTenantID ,
307
+ ClientID : fakeClientID ,
284
308
ClientSecret : corev1.SecretReference {
285
309
Name : "test-identity-secret" ,
286
310
},
@@ -295,6 +319,20 @@ func TestGetTokenCredential(t *testing.T) {
295
319
},
296
320
},
297
321
ActiveDirectoryAuthorityHost : "https://login.microsoftonline.com" ,
322
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
323
+ cache .EXPECT ().GetOrStoreClientSecret (fakeTenantID , fakeClientID , "fooSecret" , gomock .Cond (func (opts * azidentity.ClientSecretCredentialOptions ) bool {
324
+ // ignore tracing provider
325
+ return reflect .DeepEqual (opts .ClientOptions .Cloud , cloud.Configuration {
326
+ ActiveDirectoryAuthorityHost : "https://login.microsoftonline.com" ,
327
+ Services : map [cloud.ServiceName ]cloud.ServiceConfiguration {
328
+ cloud .ResourceManager : {
329
+ Audience : "" ,
330
+ Endpoint : "" ,
331
+ },
332
+ },
333
+ })
334
+ }))
335
+ },
298
336
},
299
337
{
300
338
name : "service principal certificate" ,
@@ -311,17 +349,23 @@ func TestGetTokenCredential(t *testing.T) {
311
349
Spec : infrav1.AzureClusterIdentitySpec {
312
350
Type : infrav1 .ServicePrincipalCertificate ,
313
351
TenantID : fakeTenantID ,
314
- CertPath : "../../test/setup/certificate" ,
352
+ ClientID : fakeClientID ,
353
+ ClientSecret : corev1.SecretReference {
354
+ Name : "test-identity-secret" ,
355
+ },
315
356
},
316
357
},
317
358
secret : & corev1.Secret {
318
359
ObjectMeta : metav1.ObjectMeta {
319
360
Name : "test-identity-secret" ,
320
361
},
321
362
Data : map [string ][]byte {
322
- "clientSecret" : certPEM ,
363
+ "clientSecret" : [] byte ( "fooSecret" ) ,
323
364
},
324
365
},
366
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
367
+ cache .EXPECT ().GetOrStoreClientCert (fakeTenantID , fakeClientID , []byte ("fooSecret" ), gomock .Nil (), gomock .Any ())
368
+ },
325
369
},
326
370
{
327
371
name : "service principal certificate with certificate filepath" ,
@@ -338,9 +382,17 @@ func TestGetTokenCredential(t *testing.T) {
338
382
Spec : infrav1.AzureClusterIdentitySpec {
339
383
Type : infrav1 .ServicePrincipalCertificate ,
340
384
TenantID : fakeTenantID ,
341
- CertPath : "../../test/setup/certificate" ,
385
+ ClientID : fakeClientID ,
386
+ CertPath : testCertPath ,
342
387
},
343
388
},
389
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
390
+ expectedCert , err := os .ReadFile (testCertPath )
391
+ if err != nil {
392
+ panic (err )
393
+ }
394
+ cache .EXPECT ().GetOrStoreClientCert (fakeTenantID , fakeClientID , expectedCert , gomock .Nil (), gomock .Any ())
395
+ },
344
396
},
345
397
{
346
398
name : "user-assigned identity" ,
@@ -357,8 +409,15 @@ func TestGetTokenCredential(t *testing.T) {
357
409
Spec : infrav1.AzureClusterIdentitySpec {
358
410
Type : infrav1 .UserAssignedMSI ,
359
411
TenantID : fakeTenantID ,
412
+ ClientID : fakeClientID ,
360
413
},
361
414
},
415
+ cacheExpect : func (cache * mock_azure.MockCredentialCache ) {
416
+ cache .EXPECT ().GetOrStoreManagedIdentity (gomock .Cond (func (opts * azidentity.ManagedIdentityCredentialOptions ) bool {
417
+ // ignore tracing provider
418
+ return opts .ID == azidentity .ClientID (fakeClientID )
419
+ }))
420
+ },
362
421
},
363
422
}
364
423
@@ -377,11 +436,15 @@ func TestGetTokenCredential(t *testing.T) {
377
436
initObjects = append (initObjects , tt .secret )
378
437
}
379
438
fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithRuntimeObjects (initObjects ... ).Build ()
380
- provider , err := NewAzureCredentialsProvider (context .Background (), fakeClient , tt .cluster .Spec .IdentityRef , "" )
439
+
440
+ mockCtrl := gomock .NewController (t )
441
+ cache := mock_azure .NewMockCredentialCache (mockCtrl )
442
+ tt .cacheExpect (cache )
443
+
444
+ provider , err := NewAzureCredentialsProvider (context .Background (), cache , fakeClient , tt .cluster .Spec .IdentityRef , "" )
381
445
g .Expect (err ).NotTo (HaveOccurred ())
382
- cred , err : = provider .GetTokenCredential (context .Background (), "" , tt .ActiveDirectoryAuthorityHost , "" )
446
+ _ , err = provider .GetTokenCredential (context .Background (), "" , tt .ActiveDirectoryAuthorityHost , "" )
383
447
g .Expect (err ).NotTo (HaveOccurred ())
384
- g .Expect (cred ).NotTo (BeNil ())
385
448
})
386
449
}
387
450
}
0 commit comments