diff --git a/CHANGELOG.md b/CHANGELOG.md index 6659e22f43b..2f4f37c76ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ We use *breaking* word for marking changes that are not backward compatible (rel ## Unreleased +### Added + +- [#1118](https://github.com/improbable-eng/thanos/pull/1118) swift: Added support for cross-domain authentication by introducing `userDomainID`, `userDomainName`, `projectDomainID`, `projectDomainName`. Mark `tenantID`, `tenantName` as deprecated and encourage usage of `projectID`, `projectName`. + ## [v0.4.0](https://github.com/improbable-eng/thanos/releases/tag/v0.4.0) - 2019.05.3 :warning: **IMPORTANT** :warning: This is the last release that supports gossip. From Thanos v0.5.0, gossip will be completely removed. diff --git a/docs/storage.md b/docs/storage.md index 8cd58a3dc7a..f74dc842d79 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -260,14 +260,20 @@ type: SWIFT config: auth_url: "" username: "" + user_domain_name: "" + user_domain_id: "" user_id: "" password: "" domain_id: "" domain_name: "" - tenant_id: "" - tenant_name: "" + project_id: "" + project_name: "" + project_domain_id: "" + project_domain_name: "" region_name: "" container_name: "" + tenant_id: "" + tenant_name: "" ``` ## Other minio supported S3 object storages diff --git a/pkg/objstore/swift/swift.go b/pkg/objstore/swift/swift.go index 4a16464d3b4..4021909e37c 100644 --- a/pkg/objstore/swift/swift.go +++ b/pkg/objstore/swift/swift.go @@ -11,32 +11,43 @@ import ( "testing" "time" - "github.com/improbable-eng/thanos/pkg/objstore" - "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers" "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" "github.com/gophercloud/gophercloud/pagination" + "github.com/improbable-eng/thanos/pkg/objstore" "github.com/pkg/errors" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" ) // DirDelim is the delimiter used to model a directory structure in an object store bucket. const DirDelim = "/" type SwiftConfig struct { - AuthUrl string `yaml:"auth_url"` - Username string `yaml:"username"` - UserId string `yaml:"user_id"` - Password string `yaml:"password"` - DomainId string `yaml:"domain_id"` - DomainName string `yaml:"domain_name"` - TenantID string `yaml:"tenant_id"` - TenantName string `yaml:"tenant_name"` - RegionName string `yaml:"region_name"` - ContainerName string `yaml:"container_name"` + AuthUrl string `yaml:"auth_url"` + Username string `yaml:"username"` + UserDomainName string `yaml:"user_domain_name"` + UserDomainID string `yaml:"user_domain_id"` + UserId string `yaml:"user_id"` + Password string `yaml:"password"` + DomainId string `yaml:"domain_id"` + DomainName string `yaml:"domain_name"` + ProjectID string `yaml:"project_id"` + ProjectName string `yaml:"project_name"` + ProjectDomainID string `yaml:"project_domain_id"` + ProjectDomainName string `yaml:"project_domain_name"` + RegionName string `yaml:"region_name"` + ContainerName string `yaml:"container_name"` + + // Deprecated: Please use `project_id` instead. + // The term `tenant` is used in the deprecated OpenStack Identity v2. + TenantID string `yaml:"tenant_id"` + // Deprecated: Please use `project_name` instead. + // The term `tenant` is used in the deprecated OpenStack Identity v2. + TenantName string `yaml:"tenant_name"` } type Container struct { @@ -58,13 +69,57 @@ func NewContainer(logger log.Logger, conf []byte) (*Container, error) { Password: sc.Password, DomainID: sc.DomainId, DomainName: sc.DomainName, - TenantID: sc.TenantID, - TenantName: sc.TenantName, + TenantID: sc.ProjectID, + TenantName: sc.ProjectName, // Allow Gophercloud to re-authenticate automatically. AllowReauth: true, } + // The term `tenant` is used in the deprecated OpenStack Identity v2. + // In Identity v3 the term `project` is used instead. + switch { + case sc.TenantName != "": + level.Warn(logger).Log("msg", "usage of tenant_name is deprecated. use project_name instead") + authOpts.TenantName = sc.TenantName + case sc.TenantID != "": + level.Warn(logger).Log("msg", "usage of tenant_id is deprecated. use project_id instead") + authOpts.TenantID = sc.TenantID + case sc.ProjectName != "" || sc.ProjectID != "": + level.Info(logger).Log("msg", "using project_id or project_name") + } + + // Support for cross-domain scoping (user in different domain than project). + // If a userDomainName or userDomainID is given, the user is scoped to this domain. + switch { + case sc.UserDomainName != "": + authOpts.DomainName = sc.UserDomainName + case sc.UserDomainID != "": + authOpts.DomainID = sc.UserDomainID + } + + // A token can be scoped to a domain or project. + // The project can be in another domain than the user, which is indicated by setting either projectDomainName or projectDomainID. + switch { + case sc.ProjectDomainName != "": + authOpts.Scope = &gophercloud.AuthScope{ + DomainName: sc.ProjectDomainName, + } + case sc.ProjectDomainID != "": + authOpts.Scope = &gophercloud.AuthScope{ + DomainID: sc.ProjectDomainID, + } + } + if authOpts.Scope != nil { + level.Info(logger).Log("msg", "scoping to domain, project") + switch { + case sc.ProjectName != "": + authOpts.Scope.ProjectName = sc.ProjectName + case sc.ProjectID != "": + authOpts.Scope.ProjectID = sc.ProjectID + } + } + provider, err := openstack.AuthenticatedClient(authOpts) if err != nil { return nil, err @@ -180,13 +235,19 @@ func (c *Container) deleteContainer(name string) error { func configFromEnv() SwiftConfig { c := SwiftConfig{ - AuthUrl: os.Getenv("OS_AUTH_URL"), - Username: os.Getenv("OS_USERNAME"), - Password: os.Getenv("OS_PASSWORD"), - TenantID: os.Getenv("OS_TENANT_ID"), - TenantName: os.Getenv("OS_TENANT_NAME"), - RegionName: os.Getenv("OS_REGION_NAME"), - ContainerName: os.Getenv("OS_CONTAINER_NAME"), + AuthUrl: os.Getenv("OS_AUTH_URL"), + Username: os.Getenv("OS_USERNAME"), + Password: os.Getenv("OS_PASSWORD"), + RegionName: os.Getenv("OS_REGION_NAME"), + ContainerName: os.Getenv("OS_CONTAINER_NAME"), + ProjectID: os.Getenv("OS_PROJECT_ID"), + ProjectName: os.Getenv("OS_PROJECT_NAME"), + UserDomainID: os.Getenv("OS_USER_DOMAIN_ID"), + UserDomainName: os.Getenv("OS_USER_DOMAIN_NAME"), + ProjectDomainID: os.Getenv("OS_PROJET_DOMAIN_ID"), + ProjectDomainName: os.Getenv("OS_PROJECT_DOMAIN_NAME"), + TenantID: os.Getenv("OS_TENANT_ID"), + TenantName: os.Getenv("OS_TENANT_NAME"), } return c