github.com/Azure/aad-pod-identity@v1.8.17/test/image/identityvalidator/keyvault.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 8 "github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault" 9 "github.com/Azure/azure-sdk-for-go/services/keyvault/auth" 10 "github.com/Azure/go-autorest/autorest" 11 "github.com/Azure/go-autorest/autorest/adal" 12 "k8s.io/klog/v2" 13 ) 14 15 const ( 16 keyvaultResource = "https://vault.azure.net" 17 ) 18 19 type keyvaultTester struct { 20 client keyvault.BaseClient 21 subscriptionID string 22 identityClientID string 23 identityResourceID string 24 keyvaultName string 25 secretName string 26 secretVersion string 27 secretValue string 28 } 29 30 // assertWithIdentityClientID obtains the secret value from a keyvault using 31 // aad-pod-identity and check if is the same as the expected secret values. 32 func (kvt *keyvaultTester) assertWithIdentityClientID() error { 33 if kvt.identityClientID == "" { 34 return nil 35 } 36 37 // When new authorizer is created, azure-sdk-for-go tries to create data plane authorizer using MSI. It checks the AZURE_CLIENT_ID to get the client id 38 // for the user assigned identity. If client id not found, then NewServicePrincipalTokenFromMSI is invoked instead of using the actual 39 // user assigned identity. Setting this env var ensures we validate GetSecret using the desired user assigned identity. 40 if err := os.Setenv("AZURE_CLIENT_ID", kvt.identityClientID); err != nil { 41 return fmt.Errorf("failed to set AZURE_CLIENT_ID environment variable, error: %+v", err) 42 } 43 defer os.Unsetenv("AZURE_CLIENT_ID") 44 45 authorizer, err := auth.NewAuthorizerFromEnvironment() 46 if err != nil { 47 return fmt.Errorf("failed to generate a new authorizer from environment, error: %+v", err) 48 } 49 50 klog.Infof("added authorizer with clientID: %s", kvt.identityClientID) 51 52 secret, err := kvt.getSecret(authorizer) 53 if err != nil { 54 return err 55 } 56 57 if err := kvt.assertSecret(secret); err != nil { 58 return err 59 } 60 61 klog.Info("successfully verified user-assigned identity on pod with identity client ID") 62 return nil 63 } 64 65 // assertWithIdentityResourceID obtains the secret value from a keyvault using 66 // aad-pod-identity and check if is the same as the expected secret values. 67 func (kvt *keyvaultTester) assertWithIdentityResourceID() error { 68 if kvt.identityResourceID == "" { 69 return nil 70 } 71 72 token, err := kvt.getADALTokenWithIdentityResourceID() 73 if err != nil { 74 return fmt.Errorf("failed to get ADAL token with identity resource ID, error: %+v", err) 75 } 76 77 klog.Infof("added authorizer with resource ID: %s", kvt.identityResourceID) 78 79 secret, err := kvt.getSecret(autorest.NewBearerAuthorizer(token)) 80 if err != nil { 81 return err 82 } 83 84 if err := kvt.assertSecret(secret); err != nil { 85 return err 86 } 87 88 klog.Info("successfully verified user-assigned identity on pod with identity resource ID") 89 return nil 90 } 91 92 // assertSecret checks if kvt.secretValue == actualSecret. 93 func (kvt *keyvaultTester) assertSecret(actualSecret string) error { 94 if kvt.secretValue != actualSecret { 95 return fmt.Errorf("expected %s to be equal to %s", actualSecret, kvt.secretValue) 96 } 97 98 return nil 99 } 100 101 // getSecret returns the secret value with a specific autorest authorizer. 102 func (kvt *keyvaultTester) getSecret(authorizer autorest.Authorizer) (string, error) { 103 kvt.client.Authorizer = authorizer 104 105 ctx, cancel := context.WithTimeout(context.Background(), contextTimeout) 106 defer cancel() 107 108 secret, err := kvt.client.GetSecret(ctx, kvt.getKeyvaultURL(), kvt.secretName, kvt.secretVersion) 109 if err != nil { 110 return "", fmt.Errorf("failed to get secret, error: %+v", err) 111 } 112 113 return *secret.Value, nil 114 } 115 116 // getKeyvaultURL returns the FQDN of the Azure Key Vault. 117 func (kvt *keyvaultTester) getKeyvaultURL() string { 118 return fmt.Sprintf("https://%s.vault.azure.net", kvt.keyvaultName) 119 } 120 121 // getADALTokenWithIdentityResourceID returns an ADAL token 122 // using the resource ID of a user-assigned identity. 123 func (kvt *keyvaultTester) getADALTokenWithIdentityResourceID() (*adal.Token, error) { 124 managedIdentityOptions := &adal.ManagedIdentityOptions{IdentityResourceID: kvt.identityResourceID} 125 spt, err := adal.NewServicePrincipalTokenFromManagedIdentity(keyvaultResource, managedIdentityOptions) 126 if err != nil { 127 return nil, err 128 } 129 err = spt.Refresh() 130 if err != nil { 131 return nil, err 132 } 133 token := spt.Token() 134 return &token, nil 135 }