diff --git a/go.mod b/go.mod index 2e1db7b7018a..16661f7cb02c 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( cloud.google.com/go/storage v1.10.0 github.com/Azure/azure-storage-blob-go v0.14.0 github.com/Azure/go-autorest/autorest v0.11.24 - github.com/Azure/go-autorest/autorest/adal v0.9.18 + github.com/Azure/go-autorest/autorest/adal v0.9.21 github.com/NYTimes/gziphandler v1.1.1 github.com/SAP/go-hdb v0.14.1 github.com/Sectorbob/mlab-ns2 v0.0.0-20171030222938-d3aa0c295a8a @@ -178,7 +178,7 @@ require ( go.opentelemetry.io/otel/trace v0.20.0 go.uber.org/atomic v1.9.0 go.uber.org/goleak v1.1.12 - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d + golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa golang.org/x/net v0.0.0-20220607020251-c690dde0001d golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a diff --git a/go.sum b/go.sum index 8e0ceabca806..87287b589318 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,9 @@ github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyC github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.21 h1:jjQnVFXPfekaqb8vIsv2G1lxshoW+oGv4MDlhRtnYZk= +github.com/Azure/go-autorest/autorest/adal v0.9.21/go.mod h1:zua7mBUaCc5YnSLKYgGJR/w5ePdMDA6H56upLsHzA9U= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4= @@ -1766,8 +1767,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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= diff --git a/physical/azure/azure.go b/physical/azure/azure.go index eb158a993d8a..8ec79af9de5f 100644 --- a/physical/azure/azure.go +++ b/physical/azure/azure.go @@ -44,7 +44,7 @@ var _ physical.Backend = (*AzureBackend)(nil) // from the environment, via HCL or by using managed identities. func NewAzureBackend(conf map[string]string, logger log.Logger) (physical.Backend, error) { name := os.Getenv("AZURE_BLOB_CONTAINER") - useMSI := false + keyAuth := true if name == "" { name = conf["container"] @@ -66,7 +66,7 @@ func NewAzureBackend(conf map[string]string, logger log.Logger) (physical.Backen accountKey = conf["accountKey"] if accountKey == "" { logger.Info("accountKey not set, using managed identity auth") - useMSI = true + keyAuth = false } } @@ -111,10 +111,26 @@ func NewAzureBackend(conf map[string]string, logger log.Logger) (physical.Backen } var credential azblob.Credential - if useMSI { - authToken, err := getAuthTokenFromIMDS(environment.ResourceIdentifiers.Storage) + if keyAuth { + credential, err = azblob.NewSharedKeyCredential(accountName, accountKey) if err != nil { - return nil, fmt.Errorf("failed to obtain auth token from IMDS %q: %w", environmentName, err) + return nil, fmt.Errorf("failed to create Azure client: %w", err) + } + } else { + var authToken *adal.ServicePrincipalToken + jwtBytes, err := ioutil.ReadFile(os.Getenv("AZURE_FEDERATED_TOKEN_FILE")) + + if err == nil { + logger.Debug("found Azure federated token file - attempting OIDC auth") + authToken, err = getAuthTokenViaAzWorkloadIdentity(string(jwtBytes), environment.ResourceIdentifiers.Storage) + if err != nil { + return nil, fmt.Errorf("failed to obtain auth token via Azure Workload Identity %q: %w", environmentName, err) + } + } else { + authToken, err = getAuthTokenFromIMDS(environment.ResourceIdentifiers.Storage) + if err != nil { + return nil, fmt.Errorf("failed to obtain auth token from IMDS %q: %w", environmentName, err) + } } credential = azblob.NewTokenCredential(authToken.OAuthToken(), func(c azblob.TokenCredential) time.Duration { @@ -136,11 +152,6 @@ func NewAzureBackend(conf map[string]string, logger log.Logger) (physical.Backen // tokens are valid for 23h59m (86399s) by default, refresh after ~21h return time.Duration(int(float64(expIn)*0.9)) * time.Second }) - } else { - credential, err = azblob.NewSharedKeyCredential(accountName, accountKey) - if err != nil { - return nil, fmt.Errorf("failed to create Azure client: %w", err) - } } p := azblob.NewPipeline(credential, azblob.PipelineOptions{}) @@ -325,3 +336,30 @@ func getAuthTokenFromIMDS(resource string) (*adal.ServicePrincipalToken, error) return spt, nil } + +func getAuthTokenViaAzWorkloadIdentity(jwt string, resource string) (*adal.ServicePrincipalToken, error) { + azClientId := os.Getenv("AZURE_CLIENT_ID") + azTenantId := os.Getenv("AZURE_TENANT_ID") + azAuthorityHost := os.Getenv("AZURE_AUTHORITY_HOST") + + oauthConfig, err := adal.NewOAuthConfig(azAuthorityHost, azTenantId) + if err != nil { + return nil, err + } + + spt, err := adal.NewServicePrincipalTokenFromFederatedToken(*oauthConfig, azClientId, jwt, resource) + if err != nil { + return nil, err + } + + if err := spt.Refresh(); err != nil { + return nil, err + } + + token := spt.Token() + if token.IsZero() { + return nil, errors.New("could not get oauth token") + } + + return spt, nil +}