Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
We use *breaking :warning:* to mark changes that are not backward compatible (relates only to v0.y.z releases.)

## Unreleased
- [#263](https://github.com/thanos-io/objstore/pull/263) Azure: Support for Azure Active directory Override
- [#165](https://github.com/thanos-io/objstore/pull/165) GCS: Upgrade cloud.google.com/go/storage version to `v1.50.0`.
- [#38](https://github.com/thanos-io/objstore/pull/38) GCS: Upgrade cloud.google.com/go/storage version to `v1.43.0`.
- [#145](https://github.com/thanos-io/objstore/pull/145) Include content length in the response of Get and GetRange.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ If `user_assigned_id` is used, authentication is done via user-assigned managed

If `storage_connection_string` is set, the values of `storage_account` and `endpoint` values will not be used. Use this method over `storage_account_key` if you need to authenticate via a SAS token.

If `use_workload_identity` is set, `az_tenant_id` and `client_id` may be configured together or supplied through the standard Azure environment variables; `client_secret` must not be set. Set `active_directory_endpoint` to the Microsoft Entra authority host when using a sovereign cloud, for example `https://login.microsoftonline.us/` for Azure Government.

The generic `max_retries` will be used as value for the `pipeline_config`'s `max_tries` and `reader_config`'s `max_retry_requests`. For more control, `max_retries` could be ignored (0) and one could set specific retry values.

##### OpenStack Swift
Expand Down
13 changes: 12 additions & 1 deletion providers/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type Config struct {
ReaderConfig ReaderConfig `yaml:"reader_config"`
PipelineConfig PipelineConfig `yaml:"pipeline_config"`
HTTPConfig exthttp.HTTPConfig `yaml:"http_config"`
ActiveDirectoryEndpoint string `yaml:"active_directory_endpoint"`
UseWorkloadIdentity bool `yaml:"use_workload_identity"`

// Deprecated: Is automatically set by the Azure SDK.
MSIResource string `yaml:"msi_resource"`
Expand Down Expand Up @@ -92,10 +94,19 @@ func (conf *Config) validate() error {
errMsg = append(errMsg, "user_assigned_id cannot be set when using client_id authentication")
}

if (conf.AzTenantID != "" || conf.ClientSecret != "" || conf.ClientID != "") && (conf.AzTenantID == "" || conf.ClientSecret == "" || conf.ClientID == "") {
if !conf.UseWorkloadIdentity && (conf.AzTenantID != "" || conf.ClientSecret != "" || conf.ClientID != "") && (conf.AzTenantID == "" || conf.ClientSecret == "" || conf.ClientID == "") {
errMsg = append(errMsg, "az_tenant_id, client_id, and client_secret must be set together")
}

if conf.UseWorkloadIdentity {
if (conf.AzTenantID == "") != (conf.ClientID == "") {
errMsg = append(errMsg, "az_tenant_id and client_id must be set together when using workload identity authentication")
}
if conf.ClientSecret != "" {
errMsg = append(errMsg, "client_secret cannot be set when using workload identity authentication")
}
}

if conf.StorageAccountKey != "" && conf.StorageConnectionString != "" {
errMsg = append(errMsg, "storage_account_key and storage_connection_string cannot both be set")
}
Expand Down
42 changes: 42 additions & 0 deletions providers/azure/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package azure

import (
"strings"
"testing"
"time"

Expand Down Expand Up @@ -165,6 +166,47 @@ container: "MyContainer"`),
wantFailParse: false,
wantFailValidate: true,
},
{
name: "ClientSecret without TenantID or ClientID",
config: []byte(`storage_account: "myAccount"
client_secret: "1234-56578678-655"
container: "MyContainer"`),
wantFailParse: false,
wantFailValidate: true,
},
{
name: "Valid workload identity",
config: []byte(`storage_account: "myAccount"
az_tenant_id: "1234-56578678-655"
client_id: "1234-56578678-655"
use_workload_identity: true
active_directory_endpoint: "https://login.microsoftonline.us/"
container: "MyContainer"`),
wantFailParse: false,
wantFailValidate: false,
},
{
name: "Workload identity with client secret",
config: []byte(`storage_account: "myAccount"
az_tenant_id: "1234-56578678-655"
client_id: "1234-56578678-655"
client_secret: "1234-56578678-655"
use_workload_identity: true
container: "MyContainer"`),
wantFailParse: false,
wantFailValidate: true,
},
}

func TestGetTokenCredential_CustomActiveDirectoryEndpoint(t *testing.T) {
_, err := getTokenCredential(Config{
AzTenantID: "tenant",
ClientID: "client",
ClientSecret: "secret",
ActiveDirectoryEndpoint: "http://login.example.com",
})
testutil.NotOk(t, err)
testutil.Assert(t, strings.Contains(err.Error(), "https"), "expected HTTPS validation error, got %v", err)
}

func TestConfig_validate(t *testing.T) {
Expand Down
22 changes: 20 additions & 2 deletions providers/azure/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
Expand Down Expand Up @@ -86,12 +87,29 @@ func getContainerClient(conf Config, wrapRoundtripper func(http.RoundTripper) ht
}

func getTokenCredential(conf Config) (azcore.TokenCredential, error) {
clientOptions := azcore.ClientOptions{}
if conf.ActiveDirectoryEndpoint != "" {
clientOptions.Cloud = cloud.Configuration{ActiveDirectoryAuthorityHost: conf.ActiveDirectoryEndpoint}
}

if conf.UseWorkloadIdentity {
return azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{
ClientOptions: clientOptions,
TenantID: conf.AzTenantID,
ClientID: conf.ClientID,
})
}

if conf.ClientSecret != "" && conf.AzTenantID != "" && conf.ClientID != "" {
return azidentity.NewClientSecretCredential(conf.AzTenantID, conf.ClientID, conf.ClientSecret, &azidentity.ClientSecretCredentialOptions{})
return azidentity.NewClientSecretCredential(conf.AzTenantID, conf.ClientID, conf.ClientSecret, &azidentity.ClientSecretCredentialOptions{
ClientOptions: clientOptions,
})
}

if conf.UserAssignedID == "" {
return azidentity.NewDefaultAzureCredential(nil)
return azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{
ClientOptions: clientOptions,
})
}

msiOpt := &azidentity.ManagedIdentityCredentialOptions{}
Expand Down
Loading