From 3053a35c98b381ceee236e74b834296062360ff1 Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Mon, 10 Jun 2024 13:09:22 +0100 Subject: [PATCH 1/2] dependencies: updating to `v0.20240610.1112704` of `github.com/hashicorp/go-azure-sdk` --- go.mod | 4 +- go.sum | 8 ++-- .../hashicorp/go-azure-sdk/sdk/auth/auth.go | 7 +-- .../sdk/auth/azure_cli_authorizer.go | 47 ++++++++++++++++++- .../hashicorp/go-azure-sdk/sdk/auth/config.go | 3 ++ .../sdk/environments/interfaces.go | 20 ++++++++ .../sdk/internal/azurecli/azcli.go | 26 ++++++++++ vendor/modules.txt | 4 +- 8 files changed, 106 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 7f6ae1d10ed0..0753482eeeeb 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ require ( github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.4.0 github.com/hashicorp/go-azure-helpers v0.69.0 - github.com/hashicorp/go-azure-sdk/resource-manager v0.20240604.1114748 - github.com/hashicorp/go-azure-sdk/sdk v0.20240604.1114748 + github.com/hashicorp/go-azure-sdk/resource-manager v0.20240610.1112704 + github.com/hashicorp/go-azure-sdk/sdk v0.20240610.1112704 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.3 diff --git a/go.sum b/go.sum index 5d0355269f22..e8ba5afc8449 100644 --- a/go.sum +++ b/go.sum @@ -95,10 +95,10 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-azure-helpers v0.69.0 h1:JwUWXyDgyr6OafU4CgSvrbEP1wcMjfz4gxRQciDQkBQ= github.com/hashicorp/go-azure-helpers v0.69.0/go.mod h1:BmbF4JDYXK5sEmFeU5hcn8Br21uElcqLfdQxjatwQKw= -github.com/hashicorp/go-azure-sdk/resource-manager v0.20240604.1114748 h1:sJEw1sYmLpBFUY+4UpE88GimbuAcvmo4ZvTPYenEdp4= -github.com/hashicorp/go-azure-sdk/resource-manager v0.20240604.1114748/go.mod h1:1kTyma4K4ZtSWbtCNQfv8H2NZMsIyF+6S8GRbchmUCI= -github.com/hashicorp/go-azure-sdk/sdk v0.20240604.1114748 h1:DJi4uLd/aUmAcXbTuQXeI6HukIG2ydrnq9aDM2o6D5A= -github.com/hashicorp/go-azure-sdk/sdk v0.20240604.1114748/go.mod h1:Ts5vRL3KPw8iLit+4WSi1hOWlRCx++wJrCkMGj69xBY= +github.com/hashicorp/go-azure-sdk/resource-manager v0.20240610.1112704 h1:APaOXyzHnmXF8SSVck0XJxFe+Y7OUHlGPt3dJ4YnU48= +github.com/hashicorp/go-azure-sdk/resource-manager v0.20240610.1112704/go.mod h1:iRfW3HSkKTYgoqUg9oOOvd3dRDwzNUUbvtLjWUwrWT0= +github.com/hashicorp/go-azure-sdk/sdk v0.20240610.1112704 h1:UDcE9AU+O5sAJobSdjAW0a0K87tiEEtAs3o9axJtpGQ= +github.com/hashicorp/go-azure-sdk/sdk v0.20240610.1112704/go.mod h1:Ts5vRL3KPw8iLit+4WSi1hOWlRCx++wJrCkMGj69xBY= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/auth.go b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/auth.go index 722e76171f87..ee9bbfc08b47 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/auth.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/auth.go @@ -126,9 +126,10 @@ func NewAuthorizerFromCredentials(ctx context.Context, c Credentials, api enviro if c.EnableAuthenticatingUsingAzureCLI { opts := AzureCliAuthorizerOptions{ - Api: api, - TenantId: c.TenantID, - AuxTenantIds: c.AuxiliaryTenantIDs, + Api: api, + TenantId: c.TenantID, + AuxTenantIds: c.AuxiliaryTenantIDs, + SubscriptionIdHint: c.AzureCliSubscriptionIDHint, } a, err := NewAzureCliAuthorizer(ctx, opts) if err != nil { diff --git a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/azure_cli_authorizer.go b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/azure_cli_authorizer.go index ba1853eca60e..b73dbc1057f6 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/azure_cli_authorizer.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/azure_cli_authorizer.go @@ -27,11 +27,15 @@ type AzureCliAuthorizerOptions struct { // used for Resource Manager when auxiliary tenants are needed. // e.g. https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/authenticate-multi-tenant AuxTenantIds []string + + // SubscriptionIdHint is the subscription to target when selecting an account with which to obtain an access token + // Used to hint to Azure CLI which of its signed-in accounts it should select, based on apparent access to the subscription. + SubscriptionIdHint string } // NewAzureCliAuthorizer returns an Authorizer which authenticates using the Azure CLI. func NewAzureCliAuthorizer(ctx context.Context, options AzureCliAuthorizerOptions) (Authorizer, error) { - conf, err := newAzureCliConfig(options.Api, options.TenantId, options.AuxTenantIds) + conf, err := newAzureCliConfig(options.Api, options.TenantId, options.AuxTenantIds, options.SubscriptionIdHint) if err != nil { return nil, err } @@ -48,6 +52,9 @@ type AzureCliAuthorizer struct { // DefaultSubscriptionID is the default subscription, when detected DefaultSubscriptionID string + // SubscriptionIDHint is a user-provided subscription ID used to hint to Azure CLI which account to select + SubscriptionIDHint string + conf *azureCliConfig } @@ -87,6 +94,15 @@ func (a *AzureCliAuthorizer) Token(_ context.Context, _ *http.Request) (*oauth2. tenantIdRequired = false } + // Prefer to specify subscription ID if provided, this hints to Azure CLI which account to use in the event + // that multiple accounts are signed in, and each account has access to a subset of all subscriptions. + if a.SubscriptionIDHint != "" { + azArgs = append(azArgs, "--subscription", a.conf.SubscriptionIDHint) + + // Cannot specify both `--subscription` and `--tenant` + tenantIdRequired = false + } + if tenantIdRequired { azArgs = append(azArgs, "--tenant", a.conf.TenantID) } @@ -164,10 +180,13 @@ type azureCliConfig struct { // DefaultSubscriptionID is the optional default subscription ID DefaultSubscriptionID string + + // SubscriptionIDHint is the subscription being targeted when obtaining a token, used to hint to Azure CLI which account to use + SubscriptionIDHint string } // newAzureCliConfig validates the supplied tenant ID and returns a new azureCliConfig. -func newAzureCliConfig(api environments.Api, tenantId string, auxiliaryTenantIds []string) (*azureCliConfig, error) { +func newAzureCliConfig(api environments.Api, tenantId string, auxiliaryTenantIds []string, subscriptionIdHint string) (*azureCliConfig, error) { // check az-cli version, ensure that MSAL is supported if err := azurecli.CheckAzVersion(); err != nil { return nil, err @@ -199,11 +218,34 @@ func newAzureCliConfig(api environments.Api, tenantId string, auxiliaryTenantIds subscriptionId = *defaultSubscriptionId } + // validate subscriptionIdHint, if applicable (currently only for Resource Manager) + if environments.ApiIsKnownPublished(api, "AzureResourceManager") { + if subscriptionIdHint != "" { + if availableSubscriptionIds, err := azurecli.ListAvailableSubscriptionIDs(); err != nil { + return nil, err + } else if availableSubscriptionIds == nil { + return nil, fmt.Errorf("no available subscription IDs returned by Azure CLI") + } else { + found := false + for _, subId := range *availableSubscriptionIds { + if strings.EqualFold(subId, subscriptionIdHint) { + found = true + break + } + } + if !found { + return nil, fmt.Errorf("the provided subscription ID %q is not known by Azure CLI", subscriptionIdHint) + } + } + } + } + return &azureCliConfig{ Api: api, TenantID: tenantId, AuxiliaryTenantIDs: auxiliaryTenantIds, DefaultSubscriptionID: subscriptionId, + SubscriptionIDHint: strings.ToLower(subscriptionIdHint), }, nil } @@ -213,6 +255,7 @@ func (c *azureCliConfig) TokenSource(ctx context.Context) (Authorizer, error) { return NewCachedAuthorizer(&AzureCliAuthorizer{ TenantID: c.TenantID, DefaultSubscriptionID: c.DefaultSubscriptionID, + SubscriptionIDHint: c.SubscriptionIDHint, conf: c, }) } diff --git a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/config.go b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/config.go index 7be93f4fcb35..eff4328be339 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/config.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/sdk/auth/config.go @@ -21,6 +21,9 @@ type Credentials struct { // EnableAuthenticatingUsingAzureCLI specifies whether Azure CLI authentication should be checked. EnableAuthenticatingUsingAzureCLI bool + // AzureCliSubscriptionIDHint is the subscription to target when selecting an account with which to obtain an access token + // Used to hint to Azure CLI which of its signed-in accounts it should select, based on apparent access to the subscription. + AzureCliSubscriptionIDHint string // EnableAuthenticatingUsingClientCertificate specifies whether Client Certificate authentication should be checked. EnableAuthenticatingUsingClientCertificate bool diff --git a/vendor/github.com/hashicorp/go-azure-sdk/sdk/environments/interfaces.go b/vendor/github.com/hashicorp/go-azure-sdk/sdk/environments/interfaces.go index 599759eef9a2..58357438aa3d 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/sdk/environments/interfaces.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/sdk/environments/interfaces.go @@ -3,6 +3,10 @@ package environments +import ( + "strings" +) + type Api interface { // AppId is a GUID that identifies the application/API in the cloud environment AppId() (*string, bool) @@ -26,3 +30,19 @@ type Api interface { // WithResourceIdentifier overrides the default resource ID for the API and is useful for APIs that offer multiple authorization scopes WithResourceIdentifier(string) Api } + +// ApiIsKnownPublished determines whether the provided Api represents the specified known API as published in PublishedApis +func ApiIsKnownPublished(api Api, apiName string) bool { + appId, ok := api.AppId() + if !ok || appId == nil { + return false + } + knownApiAppId, ok := PublishedApis[apiName] + if !ok { + return false + } + if !strings.EqualFold(*appId, knownApiAppId) { + return false + } + return true +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/sdk/internal/azurecli/azcli.go b/vendor/github.com/hashicorp/go-azure-sdk/sdk/internal/azurecli/azcli.go index bb225d181873..dce9d619b9e6 100644 --- a/vendor/github.com/hashicorp/go-azure-sdk/sdk/internal/azurecli/azcli.go +++ b/vendor/github.com/hashicorp/go-azure-sdk/sdk/internal/azurecli/azcli.go @@ -103,6 +103,23 @@ func GetDefaultSubscriptionID() (*string, error) { return account.Id, nil } +// ListAvailableSubscriptionIDs lists the available subscriptions +func ListAvailableSubscriptionIDs() (*[]string, error) { + accounts, err := listAzAccounts() + if err != nil { + return nil, fmt.Errorf("obtaining subscription ID: %s", err) + } + subscriptionIds := make([]string, 0) + if accounts != nil { + for _, account := range *accounts { + if account.Id != nil { + subscriptionIds = append(subscriptionIds, *account.Id) + } + } + } + return &subscriptionIds, nil +} + // GetAccountName returns the name of the authenticated principal func GetAccountName() (*string, error) { account, err := getAzAccount() @@ -136,6 +153,15 @@ func getAzAccount() (*azAccount, error) { return &account, nil } +// listAzAccounts returns the output of `az account list` +func listAzAccounts() (*[]azAccount, error) { + var account []azAccount + if err := JSONUnmarshalAzCmd(true, &account, "account", "list"); err != nil { + return nil, fmt.Errorf("obtaining account details: %s", err) + } + return &account, nil +} + // getAzVersion tries to determine the version of Azure CLI in the path. func getAzVersion() (*string, error) { var cliVersion azVersion diff --git a/vendor/modules.txt b/vendor/modules.txt index 8d9b11c4238a..c5c544f127ac 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -152,7 +152,7 @@ github.com/hashicorp/go-azure-helpers/resourcemanager/tags github.com/hashicorp/go-azure-helpers/resourcemanager/zones github.com/hashicorp/go-azure-helpers/sender github.com/hashicorp/go-azure-helpers/storage -# github.com/hashicorp/go-azure-sdk/resource-manager v0.20240604.1114748 +# github.com/hashicorp/go-azure-sdk/resource-manager v0.20240610.1112704 ## explicit; go 1.21 github.com/hashicorp/go-azure-sdk/resource-manager/aad/2021-05-01/domainservices github.com/hashicorp/go-azure-sdk/resource-manager/aadb2c/2021-04-01-preview @@ -1116,7 +1116,7 @@ github.com/hashicorp/go-azure-sdk/resource-manager/workloads/2023-04-01/saplands github.com/hashicorp/go-azure-sdk/resource-manager/workloads/2023-04-01/saprecommendations github.com/hashicorp/go-azure-sdk/resource-manager/workloads/2023-04-01/sapsupportedsku github.com/hashicorp/go-azure-sdk/resource-manager/workloads/2023-04-01/sapvirtualinstances -# github.com/hashicorp/go-azure-sdk/sdk v0.20240604.1114748 +# github.com/hashicorp/go-azure-sdk/sdk v0.20240610.1112704 ## explicit; go 1.21 github.com/hashicorp/go-azure-sdk/sdk/auth github.com/hashicorp/go-azure-sdk/sdk/auth/autorest From 6998891d1f3b899345220d0b2a9f5e943a7cc9ab Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Tue, 4 Jun 2024 00:53:18 +0100 Subject: [PATCH 2/2] provider: support subscription ID hinting when using Azure CLI authentication --- internal/provider/provider.go | 2 ++ internal/provider/provider_test.go | 43 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index f6ee270fc714..29ae7812af11 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -428,6 +428,8 @@ func providerConfigure(p *schema.Provider) schema.ConfigureContextFunc { CustomManagedIdentityEndpoint: d.Get("msi_endpoint").(string), + AzureCliSubscriptionIDHint: d.Get("subscription_id").(string), + EnableAuthenticatingUsingClientCertificate: true, EnableAuthenticatingUsingClientSecret: true, EnableAuthenticatingUsingAzureCLI: enableAzureCli, diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 21e83b39bd56..83ae293d17e3 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -160,6 +160,49 @@ func TestAccProvider_cliAuth(t *testing.T) { } } +func TestAccProvider_cliAuthWithSubscriptionIdHint(t *testing.T) { + if os.Getenv("TF_ACC") == "" { + t.Skip("TF_ACC not set") + } + if os.Getenv("ARM_SUBSCRIPTION_ID") == "" { + t.Skip("ARM_SUBSCRIPTION_ID not set") + } + + logging.SetOutput(t) + + provider := TestAzureProvider() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + // Support only Azure CLI authentication + provider.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { + envName := d.Get("environment").(string) + env, err := environments.FromName(envName) + if err != nil { + t.Fatalf("configuring environment %q: %v", envName, err) + } + + authConfig := &auth.Credentials{ + Environment: *env, + EnableAuthenticatingUsingAzureCLI: true, + AzureCliSubscriptionIDHint: d.Get("subscription_id").(string), + } + + return buildClient(ctx, provider, d, authConfig) + } + + d := provider.Configure(ctx, terraform.NewResourceConfigRaw(nil)) + if d != nil && d.HasError() { + t.Fatalf("err: %+v", d) + } + + if errs := testCheckProvider(provider); len(errs) > 0 { + for _, err := range errs { + t.Error(err) + } + } +} + func TestAccProvider_clientCertificateAuth(t *testing.T) { if os.Getenv("TF_ACC") == "" { t.Skip("TF_ACC not set")