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

feat(aws assumerolewithwebidentity): fixed s3 access for ruler to use… #4738

Closed
wants to merge 1 commit 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* [ENHANCEMENT] Blocks storage: Add `-blocks-storage.azure.http.*`, `-alertmanager-storage.azure.http.*`, and `-ruler-storage.azure.http.*` to configure the Azure storage client. #4581
* [ENHANCEMENT] Optimise memberlist receive path when used as a backing store for rings with a large number of members. #4601
* [ENHANCEMENT] Add length and limit to labelNameTooLongError and labelValueTooLongError #4595
* [ENHANCEMENT] Use IRSA Variables for ruler & alertmanager AWS S3 access PR3740
* [BUGFIX] AlertManager: remove stale template files. #4495
* [BUGFIX] Distributor: fix bug in query-exemplar where some results would get dropped. #4583
* [BUGFIX] Update Thanos dependency: compactor tracing support, azure blocks storage memory fix. #4585
Expand Down
57 changes: 56 additions & 1 deletion pkg/chunk/aws/s3_storage_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (
"fmt"
"hash/fnv"
"io"
"io/ioutil"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"

Expand All @@ -20,6 +23,7 @@ import (
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/minio/minio-go/v7/pkg/signer"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -66,13 +70,15 @@ type S3Config struct {

BucketNames string
Endpoint string `yaml:"endpoint"`
STSEndpoint string `yaml:"sts_endpoint"`
Region string `yaml:"region"`
AccessKeyID string `yaml:"access_key_id"`
SecretAccessKey flagext.Secret `yaml:"secret_access_key"`
Insecure bool `yaml:"insecure"`
SSEEncryption bool `yaml:"sse_encryption"`
HTTPConfig HTTPConfig `yaml:"http_config"`
SignatureVersion string `yaml:"signature_version"`
SessionToken string `yaml:"session_token"`
SSEConfig cortex_s3.SSEConfig `yaml:"sse"`

Inject InjectRequestMiddleware `yaml:"-"`
Expand All @@ -97,10 +103,12 @@ func (cfg *S3Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
f.BoolVar(&cfg.S3ForcePathStyle, prefix+"s3.force-path-style", false, "Set this to `true` to force the request to use path-style addressing.")
f.StringVar(&cfg.BucketNames, prefix+"s3.buckets", "", "Comma separated list of bucket names to evenly distribute chunks over. Overrides any buckets specified in s3.url flag")

f.StringVar(&cfg.STSEndpoint, prefix+"sts.endpoint", "", "STS Endpoint to connect to for AssumeRoleWithWebIdentity")
f.StringVar(&cfg.Endpoint, prefix+"s3.endpoint", "", "S3 Endpoint to connect to.")
f.StringVar(&cfg.Region, prefix+"s3.region", "", "AWS region to use.")
f.StringVar(&cfg.AccessKeyID, prefix+"s3.access-key-id", "", "AWS Access Key ID")
f.Var(&cfg.SecretAccessKey, prefix+"s3.secret-access-key", "AWS Secret Access Key")
f.StringVar(&cfg.SessionToken, prefix+"s3.session-token", "", "AWS Session Name to be used for AssumeRoleWithWebIdentity Session")
f.BoolVar(&cfg.Insecure, prefix+"s3.insecure", false, "Disable https on s3 connection.")

// TODO Remove in Cortex 1.10.0
Expand Down Expand Up @@ -231,8 +239,55 @@ func buildS3Config(cfg S3Config) (*aws.Config, []string, error) {
return nil, nil, errors.New("must supply both an Access Key ID and Secret Access Key or neither")
}

role := os.Getenv("AWS_ROLE_ARN")
webIdentityTokenFile := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")
if cfg.AccessKeyID == "" && cfg.SecretAccessKey.Value == "" &&
role != "" && webIdentityTokenFile != "" {

s3Config = s3Config.WithEndpoint(cfg.STSEndpoint)
webIdentityReadToken, err := ioutil.ReadFile(webIdentityTokenFile)
if err != nil {
return nil, nil, err
}
token := string(webIdentityReadToken)

sess, err := session.NewSession(s3Config)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create new s3 session")
}

awsSTS := sts.New(sess)
if err != nil {
return nil, nil, err
}

sessName := cfg.SessionToken
if sessName == "" {
sessName = strconv.FormatInt(time.Now().UnixNano(), 10)
cfg.SessionToken = sessName
}

req, sessCred := awsSTS.AssumeRoleWithWebIdentityRequest(
&sts.AssumeRoleWithWebIdentityInput{
RoleSessionName: &sessName,
WebIdentityToken: &token,
RoleArn: &role,
},
)

err = req.Send()
if err != nil {
return nil, nil, err
}

cfg.AccessKeyID = aws.StringValue(sessCred.Credentials.AccessKeyId)
cfg.SecretAccessKey = flagext.Secret{Value: *sessCred.Credentials.SecretAccessKey}
cfg.SessionToken = aws.StringValue(sessCred.Credentials.SessionToken)
s3Config = s3Config.WithEndpoint(cfg.Endpoint)
}

if cfg.AccessKeyID != "" && cfg.SecretAccessKey.Value != "" {
creds := credentials.NewStaticCredentials(cfg.AccessKeyID, cfg.SecretAccessKey.Value, "")
creds := credentials.NewStaticCredentials(cfg.AccessKeyID, cfg.SecretAccessKey.Value, cfg.SessionToken)
s3Config = s3Config.WithCredentials(creds)
}

Expand Down