From f22a1cab60d10dbda79950132ae67b868c0d9c09 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 18 Sep 2024 14:42:05 -0700 Subject: [PATCH] WIP: Support OIDC in Azure Pipelines This change teaches `azd` how to login using a service connection for an OIDC like experience when running in Azure Pipelines using service connections and then updates our pipelines to use this authentication strategy. Contributes To #4341 --- cli/azd/.vscode/cspell.yaml | 6 + cli/azd/cmd/auth_login.go | 43 ++++++-- .../testdata/TestUsage-azd-auth-login.snap | 24 ++-- cli/azd/pkg/auth/manager.go | 104 ++++++++++++++++-- .../test/functional/deployment_stacks_test.go | 2 - cli/azd/test/functional/login_test.go | 41 ------- cli/azd/test/recording/recording.go | 4 +- eng/pipelines/templates/jobs/build-cli.yml | 9 +- eng/pipelines/templates/steps/azd-login.yml | 10 +- go.mod | 16 +-- go.sum | 16 +++ 11 files changed, 186 insertions(+), 89 deletions(-) diff --git a/cli/azd/.vscode/cspell.yaml b/cli/azd/.vscode/cspell.yaml index 9364122e8f6..a38d2d4807a 100644 --- a/cli/azd/.vscode/cspell.yaml +++ b/cli/azd/.vscode/cspell.yaml @@ -26,6 +26,9 @@ dictionaryDefinitions: dictionaries: - azdProjectDictionary overrides: + - filename: cmd/auth_login.go + words: + - ACCESSTOKEN - filename: internal/tracing/fields/domains.go words: - azmk @@ -110,6 +113,9 @@ overrides: - filename: test/functional/testdata/samples/funcapp/getting_started.md words: - funcignore + - filename: test/recording/recording.go + words: + - oidctoken - filename: internal/vsrpc/handler.go words: - arity diff --git a/cli/azd/cmd/auth_login.go b/cli/azd/cmd/auth_login.go index c50c6e5988d..0a90ae33fe1 100644 --- a/cli/azd/cmd/auth_login.go +++ b/cli/azd/cmd/auth_login.go @@ -46,18 +46,20 @@ func newAuthLoginFlags(cmd *cobra.Command, global *internal.GlobalCommandOptions } type loginFlags struct { - onlyCheckStatus bool - browser bool - managedIdentity bool - useDeviceCode boolPtr - tenantID string - clientID string - clientSecret stringPtr - clientCertificate string - federatedTokenProvider string - scopes []string - redirectPort int - global *internal.GlobalCommandOptions + onlyCheckStatus bool + browser bool + managedIdentity bool + useDeviceCode boolPtr + tenantID string + clientID string + clientSecret stringPtr + clientCertificate string + serviceConnectionID string + systemAccessTokenEnvVar string + federatedTokenProvider string + scopes []string + redirectPort int + global *internal.GlobalCommandOptions } // stringPtr implements a pflag.Value and allows us to distinguish between a flag value being explicitly set to the empty @@ -139,6 +141,16 @@ func (lf *loginFlags) Bind(local *pflag.FlagSet, global *internal.GlobalCommandO cClientCertificateFlagName, "", "The path to the client certificate for the service principal to authenticate with.") + local.StringVar( + &lf.serviceConnectionID, + "service-connection-id", + "", + "The service connection id to authenticate with.") + local.StringVar( + &lf.systemAccessTokenEnvVar, + "system-access-token-environment-variable-name", + "SYSTEM_ACCESSTOKEN", + "The name of the environment variable that contains the system access token to authenticate with.") local.StringVar( &lf.federatedTokenProvider, cFederatedCredentialProviderFlagName, @@ -407,6 +419,7 @@ func (la *loginAction) login(ctx context.Context) error { if countTrue( la.flags.clientSecret.ptr != nil, la.flags.clientCertificate != "", + la.flags.serviceConnectionID != "", la.flags.federatedTokenProvider != "", ) != 1 { return fmt.Errorf( @@ -457,6 +470,12 @@ func (la *loginAction) login(ctx context.Context) error { ); err != nil { return fmt.Errorf("logging in: %w", err) } + case la.flags.serviceConnectionID != "": + if _, err := la.authManager.LoginWithServiceConnection( + ctx, la.flags.tenantID, la.flags.clientID, la.flags.serviceConnectionID, la.flags.systemAccessTokenEnvVar, + ); err != nil { + return fmt.Errorf("logging in: %w", err) + } } return nil diff --git a/cli/azd/cmd/testdata/TestUsage-azd-auth-login.snap b/cli/azd/cmd/testdata/TestUsage-azd-auth-login.snap index c9e531eda87..aae80ccc8ba 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-auth-login.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-auth-login.snap @@ -5,17 +5,19 @@ Usage azd auth login [flags] Flags - --check-status : Checks the log-in status instead of logging in. - --client-certificate string : The path to the client certificate for the service principal to authenticate with. - --client-id string : The client id for the service principal to authenticate with. - --client-secret string : The client secret for the service principal to authenticate with. Set to the empty string to read the value from the console. - --docs : Opens the documentation for azd auth login in your web browser. - --federated-credential-provider string : The provider to use to acquire a federated token to authenticate with. - -h, --help : Gets help for login. - --managed-identity : Use a managed identity to authenticate. - --redirect-port int : Choose the port to be used as part of the redirect URI during interactive login. - --tenant-id string : The tenant id or domain name to authenticate with. - --use-device-code : When true, log in by using a device code instead of a browser. + --check-status : Checks the log-in status instead of logging in. + --client-certificate string : The path to the client certificate for the service principal to authenticate with. + --client-id string : The client id for the service principal to authenticate with. + --client-secret string : The client secret for the service principal to authenticate with. Set to the empty string to read the value from the console. + --docs : Opens the documentation for azd auth login in your web browser. + --federated-credential-provider string : The provider to use to acquire a federated token to authenticate with. + -h, --help : Gets help for login. + --managed-identity : Use a managed identity to authenticate. + --redirect-port int : Choose the port to be used as part of the redirect URI during interactive login. + --service-connection-id string : The service connection id to authenticate with. + --system-access-token-environment-variable-name string : The name of the environment variable that contains the system access token to authenticate with. + --tenant-id string : The tenant id or domain name to authenticate with. + --use-device-code : When true, log in by using a device code instead of a browser. Global Flags -C, --cwd string : Sets the current working directory. diff --git a/cli/azd/pkg/auth/manager.go b/cli/azd/pkg/auth/manager.go index 77c574e75d1..81625f76f97 100644 --- a/cli/azd/pkg/auth/manager.go +++ b/cli/azd/pkg/auth/manager.go @@ -312,11 +312,6 @@ func (m *Manager) CredentialForCurrentUser( } return m.newCredentialFromManagedIdentity(clientID) } else if currentUser.TenantID != nil && currentUser.ClientID != nil { - ps, err := m.loadSecret(*currentUser.TenantID, *currentUser.ClientID) - if err != nil { - return nil, fmt.Errorf("loading secret: %w: %w", err, ErrNoCurrentUser) - } - // by default we used the stored tenant (i.e. the one provided with the tenant id parameter when a user ran // `azd auth login`), but we allow an override using the options bag, when // TenantID is non-empty and PreferFallbackTenant is not true. @@ -326,6 +321,16 @@ func (m *Manager) CredentialForCurrentUser( tenantID = options.TenantID } + if currentUser.ServiceConnectionID != nil && currentUser.SystemAccessTokenName != nil { + return m.newCredentialFromServiceConnection( + tenantID, *currentUser.ClientID, *currentUser.ServiceConnectionID, *currentUser.SystemAccessTokenName) + } + + ps, err := m.loadSecret(*currentUser.TenantID, *currentUser.ClientID) + if err != nil { + return nil, fmt.Errorf("loading secret: %w: %w", err, ErrNoCurrentUser) + } + if ps.ClientSecret != nil { return m.newCredentialFromClientSecret(tenantID, *currentUser.ClientID, *ps.ClientSecret) } else if ps.ClientCertificate != nil { @@ -481,6 +486,36 @@ func (m *Manager) newCredentialFromClientSecret( return cred, nil } +func (m *Manager) newCredentialFromServiceConnection( + tenantID string, + clientID string, + serviceConnectionID string, + systemAccessTokenEnvVar string, +) (azcore.TokenCredential, error) { + options := &azidentity.AzurePipelinesCredentialOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: m.httpClient, + // TODO: Inject client options instead? this can be done if we're OK + // using the default user agent string. + Cloud: m.cloud.Configuration, + }, + } + + systemAccessToken := os.Getenv(systemAccessTokenEnvVar) + if systemAccessToken == "" { + // nolint:lll + return nil, fmt.Errorf("system access token not found, ensure the System.AccessToken value is mapped to an environment variable named %s", systemAccessTokenEnvVar) + } + + cred, err := azidentity.NewAzurePipelinesCredential( + tenantID, clientID, serviceConnectionID, systemAccessToken, options) + if err != nil { + return nil, fmt.Errorf("creating credential: %w: %w", err, ErrNoCurrentUser) + } + + return cred, nil +} + func (m *Manager) newCredentialFromClientCertificate( tenantID string, clientID string, @@ -688,6 +723,37 @@ func (m *Manager) LoginWithDeviceCode( } +func (m *Manager) LoginWithServiceConnection( + ctx context.Context, tenantID string, clientID string, serviceConnectionID string, systemAccessTokenEnvVar string, +) (azcore.TokenCredential, error) { + systemAccessToken := os.Getenv(systemAccessTokenEnvVar) + + if systemAccessToken == "" { + // nolint:lll + return nil, fmt.Errorf("system access token not found, ensure the System.AccessToken value is mapped to an environment variable named %s", systemAccessTokenEnvVar) + } + + options := &azidentity.AzurePipelinesCredentialOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: m.httpClient, + // TODO: Inject client options instead? this can be done if we're OK + // using the default user agent string. + Cloud: m.cloud.Configuration, + }, + } + + cred, err := azidentity.NewAzurePipelinesCredential(tenantID, clientID, serviceConnectionID, systemAccessToken, options) + if err != nil { + return nil, fmt.Errorf("creating credential: %w", err) + } + + if err := m.saveLoginForServiceConnection(tenantID, clientID, serviceConnectionID, systemAccessTokenEnvVar); err != nil { + return nil, err + } + + return cred, nil +} + func (m *Manager) LoginWithManagedIdentity(ctx context.Context, clientID string) (azcore.TokenCredential, error) { options := &azidentity.ManagedIdentityCredentialOptions{} if clientID != "" { @@ -848,6 +914,22 @@ func (m *Manager) saveLoginForManagedIdentity(clientID string) error { return nil } +func (m *Manager) saveLoginForServiceConnection( + tenantID, clientID, serviceConnectionID, systemAccessTokenEnvVar string, +) error { + props := &userProperties{ + ClientID: &clientID, + TenantID: &tenantID, + ServiceConnectionID: &serviceConnectionID, + SystemAccessTokenName: &systemAccessTokenEnvVar, + } + if err := m.saveUserProperties(props); err != nil { + return err + } + + return nil +} + func (m *Manager) saveLoginForServicePrincipal(tenantId, clientId string, secret *persistedSecret) error { if err := m.saveSecret(tenantId, clientId, secret); err != nil { return err @@ -1033,11 +1115,13 @@ type federatedAuth struct { // either an home account id (when logging in using a public client) or a client and tenant id (when using a confidential // client). type userProperties struct { - ManagedIdentity bool `json:"managedIdentity,omitempty"` - HomeAccountID *string `json:"homeAccountId,omitempty"` - FromOneAuth bool `json:"fromOneAuth,omitempty"` - ClientID *string `json:"clientId,omitempty"` - TenantID *string `json:"tenantId,omitempty"` + ManagedIdentity bool `json:"managedIdentity,omitempty"` + HomeAccountID *string `json:"homeAccountId,omitempty"` + FromOneAuth bool `json:"fromOneAuth,omitempty"` + ClientID *string `json:"clientId,omitempty"` + TenantID *string `json:"tenantId,omitempty"` + ServiceConnectionID *string `json:"serviceConnectionId,omitempty"` + SystemAccessTokenName *string `json:"systemAccessTokenName,omitempty"` } func readUserProperties(cfg config.Config) (*userProperties, error) { diff --git a/cli/azd/test/functional/deployment_stacks_test.go b/cli/azd/test/functional/deployment_stacks_test.go index cabaf4a61de..152ac0559df 100644 --- a/cli/azd/test/functional/deployment_stacks_test.go +++ b/cli/azd/test/functional/deployment_stacks_test.go @@ -18,8 +18,6 @@ import ( ) func Test_DeploymentStacks(t *testing.T) { - t.Skip("azure/azure-dev#4341") - t.Run("Subscription_Scope_Up_Down", func(t *testing.T) { t.Parallel() ctx, cancel := newTestContext(t) diff --git a/cli/azd/test/functional/login_test.go b/cli/azd/test/functional/login_test.go index 0fbd97f46b4..56f9e6195f4 100644 --- a/cli/azd/test/functional/login_test.go +++ b/cli/azd/test/functional/login_test.go @@ -53,47 +53,6 @@ func Test_CLI_AuthLoginStatus(t *testing.T) { } } -func Test_CLI_LoginServicePrincipal(t *testing.T) { - t.Skip("azure/azure-dev#4341") - - ctx, cancel := newTestContext(t) - defer cancel() - - dir := t.TempDir() - - cli := azdcli.NewCLI(t) - // Isolate login to a separate configuration directory - cli.Env = append(cli.Env, "AZD_CONFIG_DIR="+dir) - if cfg.ClientID == "" || cfg.TenantID == "" /* || cfg.ClientSecret == "" */ { - if cfg.CI { - panic("Service principal is not configured. AZD_TEST_* variables are required to be set for live testing.") - } - - t.Skip("Skipping test because service principal is not configured. " + - "Set the relevant AZD_TEST_* variables to run this test.") - return - } - - loginState := loginStatus(t, ctx, cli) - require.Equal(t, contracts.LoginStatusUnauthenticated, loginState.Status) - - _, err := cli.RunCommand(ctx, - "auth", "login", - "--client-id", cfg.ClientID, - // "--client-secret", cfg.ClientSecret, - "--tenant-id", cfg.TenantID) - require.NoError(t, err) - - loginState = loginStatus(t, ctx, cli) - require.Equal(t, contracts.LoginStatusSuccess, loginState.Status) - - _, err = cli.RunCommand(ctx, "auth", "logout") - require.NoError(t, err) - - loginState = loginStatus(t, ctx, cli) - require.Equal(t, contracts.LoginStatusUnauthenticated, loginState.Status) -} - func loginStatus(t *testing.T, ctx context.Context, cli *azdcli.CLI) contracts.LoginResult { result, err := cli.RunCommand(ctx, "auth", "login", "--check-status", "--output", "json") require.NoError(t, err) diff --git a/cli/azd/test/recording/recording.go b/cli/azd/test/recording/recording.go index abf8423ff5b..231d6c83f89 100644 --- a/cli/azd/test/recording/recording.go +++ b/cli/azd/test/recording/recording.go @@ -306,7 +306,9 @@ func Start(t *testing.T, opts ...Options) *Session { strings.Contains(req.URL.Path, "/azure-dev")) || strings.Contains(req.URL.Host, "azure-dev.azureedge.net") || strings.Contains(req.URL.Host, "azdrelease.azureedge.net") || - strings.Contains(req.URL.Host, "default.exp-tas.com") + strings.Contains(req.URL.Host, "default.exp-tas.com") || + (strings.Contains(req.URL.Host, "dev.azure.com") && + strings.Contains(req.URL.Path, "/oidctoken")) }) proxy := &connectHandler{ diff --git a/eng/pipelines/templates/jobs/build-cli.yml b/eng/pipelines/templates/jobs/build-cli.yml index a38f4331337..c2da7134585 100644 --- a/eng/pipelines/templates/jobs/build-cli.yml +++ b/eng/pipelines/templates/jobs/build-cli.yml @@ -121,9 +121,14 @@ jobs: AZD_TEST_AZURE_SUBSCRIPTION_ID: $(SubscriptionId) AZD_TEST_AZURE_LOCATION: eastus2 AZURE_RECORD_MODE: $(AZURE_RECORD_MODE) - # AZD Live Test: Terraform authentication via `az` - ARM_USE_CLI: true + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + # AZD Live Test: Terraform authentication via OIDC. + ARM_CLIENT_ID: $(arm-client-id) + ARM_SUBSCRIPTION_ID: $(SubscriptionId) ARM_TENANT_ID: $(arm-tenant-id) + ARM_USE_OIDC: true + ARM_OIDC_REQUEST_URL: $(arm-oidc-request-url) + ARM_OIDC_REQUEST_TOKEN: $(System.AccessToken) # Code Coverage: Generate junit report to publish results GOTESTSUM_JUNITFILE: junitTestReport.xml diff --git a/eng/pipelines/templates/steps/azd-login.yml b/eng/pipelines/templates/steps/azd-login.yml index 3875acfd1ef..db4f6589328 100644 --- a/eng/pipelines/templates/steps/azd-login.yml +++ b/eng/pipelines/templates/steps/azd-login.yml @@ -1,6 +1,7 @@ parameters: SubscriptionConfiguration: $(sub-config-azure-cloud-test-resources) AzdDirectory: "" + ServiceConnectionId: "3d79cc98-46f2-428c-bdd5-861414f85602" steps: - pwsh: | @@ -14,8 +15,10 @@ steps: ${{ parameters.SubscriptionConfiguration }} '@ | ConvertFrom-Json -AsHashtable; - # Delegate auth to az CLI which supports federated auth in AzDo - & $azdCmd config set auth.useAzCliAuth true + & $azdCmd login ` + --client-id "$($subscriptionConfiguration.TestApplicationId)" ` + --tenant-id "$($subscriptionConfiguration.TenantId)" ` + --service-connection-id "${{ parameters.ServiceConnectionId }}" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } @@ -27,8 +30,11 @@ steps: Write-Host "##vso[task.setvariable variable=SubscriptionId]$($subscriptionConfiguration.SubscriptionId)" # Export service principal auth information for terraform testing + Write-Host "##vso[task.setvariable variable=arm-oidc-request-url;issecret=false]$($env:SYSTEM_OIDCREQUESTURI)?api-version=7.1&serviceConnectionId=${{ parameters.ServiceConnectionId }}" Write-Host "##vso[task.setvariable variable=arm-client-id;issecret=false]$($subscriptionConfiguration.TestApplicationId)" Write-Host "##vso[task.setvariable variable=arm-tenant-id;issecret=false]$($subscriptionConfiguration.TenantId)" condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) displayName: Azure Dev Login + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/go.mod b/go.mod index 164e3b7cb42..4068ae6d552 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.23 require ( github.com/AlecAivazis/survey/v2 v2.3.2 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appconfiguration/armappconfiguration v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appcontainers/armappcontainers/v3 v3.0.0-beta.1 @@ -67,14 +67,14 @@ require ( go.opentelemetry.io/otel/trace v1.8.0 go.uber.org/atomic v1.9.0 go.uber.org/multierr v1.8.0 - golang.org/x/sys v0.21.0 + golang.org/x/sys v0.25.0 gopkg.in/dnaeon/go-vcr.v3 v3.1.2 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/Azure/azure-pipeline-go v0.2.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -99,10 +99,10 @@ require ( go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.8.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.8.0 // indirect go.opentelemetry.io/proto/otlp v0.18.0 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/term v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index 1bfc6810097..eab41df64ab 100644 --- a/go.sum +++ b/go.sum @@ -53,10 +53,16 @@ github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZ github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o= github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0 h1:Ai3+BE11JvwQ2PxLGNKAfMNSceYXjeijReLJiCouO6o= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0/go.mod h1:gr6fiHmIii3Zw3riWMSr+P0tWTz4hfqTVcFttdi2JBo= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appconfiguration/armappconfiguration v1.0.0 h1:5reBX+9pzc5xp9VrjSUoPrE8Wl/3y7wjfHzGjXzJbNk= @@ -566,6 +572,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -646,6 +654,8 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -749,10 +759,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -764,6 +778,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=