Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic aws credentials support #2135

Closed
wants to merge 3 commits into from
Closed
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 go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ require (
github.com/mattn/go-runewidth v0.0.6 // indirect
github.com/miekg/dns v1.1.22
github.com/minio/minio-go/v6 v6.0.45
github.com/mitchellh/go-homedir v1.1.0
github.com/mozillazg/go-cos v0.13.0
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
github.com/oklog/run v1.0.0
Expand Down
65 changes: 61 additions & 4 deletions pkg/objstore/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"net"
"net/http"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
Expand All @@ -23,11 +24,13 @@ import (
"github.com/minio/minio-go/v6"
"github.com/minio/minio-go/v6/pkg/credentials"
"github.com/minio/minio-go/v6/pkg/encrypt"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/prometheus/common/model"
"github.com/prometheus/common/version"
"github.com/thanos-io/thanos/pkg/objstore"
"github.com/thanos-io/thanos/pkg/runutil"
"gopkg.in/fsnotify.v1"
"gopkg.in/yaml.v2"
)

Expand Down Expand Up @@ -105,7 +108,7 @@ func NewBucket(logger log.Logger, conf []byte, component string) (*Bucket, error

// NewBucketWithConfig returns a new Bucket using the provided s3 config values.
func NewBucketWithConfig(logger log.Logger, config Config, component string) (*Bucket, error) {
var chain []credentials.Provider
var creds *credentials.Credentials

if err := validate(config); err != nil {
return nil, err
Expand All @@ -117,15 +120,16 @@ func NewBucketWithConfig(logger log.Logger, config Config, component string) (*B
signature = credentials.SignatureV2
}

chain = []credentials.Provider{&credentials.Static{
chain := []credentials.Provider{&credentials.Static{
Value: credentials.Value{
AccessKeyID: config.AccessKey,
SecretAccessKey: config.SecretKey,
SignerType: signature,
},
}}
creds = credentials.NewChainCredentials(chain)
} else {
chain = []credentials.Provider{
chain := []credentials.Provider{
&credentials.EnvAWS{},
&credentials.FileAWSCredentials{},
&credentials.IAM{
Expand All @@ -134,9 +138,22 @@ func NewBucketWithConfig(logger log.Logger, config Config, component string) (*B
},
},
}
creds = credentials.NewChainCredentials(chain)

// We will watch for credential changes for non-static credentials
filename := os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
Copy link
Author

@kush-patel-hs kush-patel-hs Feb 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably also get filename from config if we can. Then provide that to FileAWSCredentials. I really hate having to duplicate the FileAWSCredentials logic to determine filename here (I guess we would have to anyways if there's no filename provided in config).

if filename == "" {
homeDir, err := homedir.Dir()
if err == nil {
filename = filepath.Join(homeDir, ".aws", "credentials")
}
}
if err := startCredentialExpirer(creds, filename); err != nil {
logger.Log("msg", "failed to start credential expirer", err)
}
}

client, err := minio.NewWithCredentials(config.Endpoint, credentials.NewChainCredentials(chain), !config.Insecure, config.Region)
client, err := minio.NewWithCredentials(config.Endpoint, creds, !config.Insecure, config.Region)
if err != nil {
return nil, errors.Wrap(err, "initialize s3 client")
}
Expand Down Expand Up @@ -192,6 +209,46 @@ func (b *Bucket) Name() string {
return b.name
}

// startCredentialExpirer will start a watch of the file directory of AWS credentials and
// if it is updated it will force expire credentials so they are fetched again next get.
func startCredentialExpirer(creds *credentials.Credentials, filePath string) error {
// Will not start watch for empty filePath
if filePath == "" {
return nil
}

watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}

// Launch the watch which will expire the credentials when fired
go func() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to kill this go routine when thanos quit or dies. Is there a standard way thanos does this atm for other go routines?

defer watcher.Close()
for {
select {
case _, ok := <-watcher.Events:
if !ok {
return
}
creds.Expire()
case _, ok := <-watcher.Errors:
if !ok {
return
}
}
}
}()

// We want to watch the parent because when files are rewritten watch will die
err = watcher.Add(filepath.Dir(filePath))
if err != nil {
return err
}

return nil
}

// validate checks to see the config options are set.
func validate(conf Config) error {
if conf.Endpoint == "" {
Expand Down