mirror of
https://github.com/octoleo/restic.git
synced 2024-11-22 04:45:15 +00:00
Merge pull request #4474 from ekristen/aws-assume-role
Allow AWS Assume Role
This commit is contained in:
commit
77434c6e2b
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/.idea
|
||||
/restic
|
||||
/restic.exe
|
||||
/.vagrant
|
||||
|
18
changelog/unreleased/issue-4472
Normal file
18
changelog/unreleased/issue-4472
Normal file
@ -0,0 +1,18 @@
|
||||
Enhancement: Allow AWS Assume Role to be used for S3 backend
|
||||
|
||||
Previously only credentials discovered via the Minio discovery methods
|
||||
were used to authenticate.
|
||||
|
||||
However, there are many circumstances where the discovered credentials have
|
||||
lower permissions and need to assume a specific role. This is now possible
|
||||
using the following new environment variables.
|
||||
|
||||
- RESTIC_AWS_ASSUME_ROLE_ARN
|
||||
- RESTIC_AWS_ASSUME_ROLE_SESSION_NAME
|
||||
- RESTIC_AWS_ASSUME_ROLE_EXTERNAL_ID
|
||||
- RESTIC_AWS_ASSUME_ROLE_REGION (defaults to us-east-1)
|
||||
- RESTIC_AWS_ASSUME_ROLE_POLICY
|
||||
- RESTIC_AWS_ASSUME_ROLE_STS_ENDPOINT
|
||||
|
||||
https://github.com/restic/restic/issues/4472
|
||||
https://github.com/restic/restic/pull/4474
|
@ -628,6 +628,12 @@ environment variables. The following lists these environment variables:
|
||||
AWS_DEFAULT_REGION Amazon S3 default region
|
||||
AWS_PROFILE Amazon credentials profile (alternative to specifying key and region)
|
||||
AWS_SHARED_CREDENTIALS_FILE Location of the AWS CLI shared credentials file (default: ~/.aws/credentials)
|
||||
RESTIC_AWS_ASSUME_ROLE_ARN Amazon IAM Role ARN to assume using discovered credentials
|
||||
RESTIC_AWS_ASSUME_ROLE_SESSION_NAME Session Name to use with the role assumption
|
||||
RESTIC_AWS_ASSUME_ROLE_EXTERNAL_ID External ID to use with the role assumption
|
||||
RESTIC_AWS_ASSUME_ROLE_POLICY Inline Amazion IAM session policy
|
||||
RESTIC_AWS_ASSUME_ROLE_REGION Region to use for IAM calls for the role assumption (default: us-east-1)
|
||||
RESTIC_AWS_ASSUME_ROLE_STS_ENDPOINT URL to the STS endpoint (default is determined based on RESTIC_AWS_ASSUME_ROLE_REGION). You generally do not need to set this, advanced use only.
|
||||
|
||||
AZURE_ACCOUNT_NAME Account name for Azure
|
||||
AZURE_ACCOUNT_KEY Account key for Azure
|
||||
|
@ -51,40 +51,9 @@ func open(ctx context.Context, cfg Config, rt http.RoundTripper) (*Backend, erro
|
||||
minio.MaxRetry = int(cfg.MaxRetries)
|
||||
}
|
||||
|
||||
// Chains all credential types, in the following order:
|
||||
// - Static credentials provided by user
|
||||
// - AWS env vars (i.e. AWS_ACCESS_KEY_ID)
|
||||
// - Minio env vars (i.e. MINIO_ACCESS_KEY)
|
||||
// - AWS creds file (i.e. AWS_SHARED_CREDENTIALS_FILE or ~/.aws/credentials)
|
||||
// - Minio creds file (i.e. MINIO_SHARED_CREDENTIALS_FILE or ~/.mc/config.json)
|
||||
// - IAM profile based credentials. (performs an HTTP
|
||||
// call to a pre-defined endpoint, only valid inside
|
||||
// configured ec2 instances)
|
||||
creds := credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.EnvAWS{},
|
||||
&credentials.Static{
|
||||
Value: credentials.Value{
|
||||
AccessKeyID: cfg.KeyID,
|
||||
SecretAccessKey: cfg.Secret.Unwrap(),
|
||||
},
|
||||
},
|
||||
&credentials.EnvMinio{},
|
||||
&credentials.FileAWSCredentials{},
|
||||
&credentials.FileMinioClient{},
|
||||
&credentials.IAM{
|
||||
Client: &http.Client{
|
||||
Transport: http.DefaultTransport,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
c, err := creds.Get()
|
||||
creds, err := getCredentials(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creds.Get")
|
||||
}
|
||||
|
||||
if c.SignerType == credentials.SignatureAnonymous {
|
||||
debug.Log("using anonymous access for %#v", cfg.Endpoint)
|
||||
return nil, errors.Wrap(err, "s3.getCredentials")
|
||||
}
|
||||
|
||||
options := &minio.Options{
|
||||
@ -125,6 +94,91 @@ func open(ctx context.Context, cfg Config, rt http.RoundTripper) (*Backend, erro
|
||||
return be, nil
|
||||
}
|
||||
|
||||
// getCredentials -- runs through the various credential types and returns the first one that works.
|
||||
// additionally if the user has specified a role to assume, it will do that as well.
|
||||
func getCredentials(cfg Config) (*credentials.Credentials, error) {
|
||||
// Chains all credential types, in the following order:
|
||||
// - Static credentials provided by user
|
||||
// - AWS env vars (i.e. AWS_ACCESS_KEY_ID)
|
||||
// - Minio env vars (i.e. MINIO_ACCESS_KEY)
|
||||
// - AWS creds file (i.e. AWS_SHARED_CREDENTIALS_FILE or ~/.aws/credentials)
|
||||
// - Minio creds file (i.e. MINIO_SHARED_CREDENTIALS_FILE or ~/.mc/config.json)
|
||||
// - IAM profile based credentials. (performs an HTTP
|
||||
// call to a pre-defined endpoint, only valid inside
|
||||
// configured ec2 instances)
|
||||
creds := credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.EnvAWS{},
|
||||
&credentials.Static{
|
||||
Value: credentials.Value{
|
||||
AccessKeyID: cfg.KeyID,
|
||||
SecretAccessKey: cfg.Secret.Unwrap(),
|
||||
},
|
||||
},
|
||||
&credentials.EnvMinio{},
|
||||
&credentials.FileAWSCredentials{},
|
||||
&credentials.FileMinioClient{},
|
||||
&credentials.IAM{
|
||||
Client: &http.Client{
|
||||
Transport: http.DefaultTransport,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
c, err := creds.Get()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creds.Get")
|
||||
}
|
||||
|
||||
if c.SignerType == credentials.SignatureAnonymous {
|
||||
debug.Log("using anonymous access for %#v", cfg.Endpoint)
|
||||
}
|
||||
|
||||
roleArn := os.Getenv("RESTIC_AWS_ASSUME_ROLE_ARN")
|
||||
if roleArn != "" {
|
||||
// use the region provided by the configuration by default
|
||||
awsRegion := cfg.Region
|
||||
// allow the region to be overridden if for some reason it is required
|
||||
if os.Getenv("RESTIC_AWS_ASSUME_ROLE_REGION") != "" {
|
||||
awsRegion = os.Getenv("RESTIC_AWS_ASSUME_ROLE_REGION")
|
||||
}
|
||||
|
||||
sessionName := os.Getenv("RESTIC_AWS_ASSUME_ROLE_SESSION_NAME")
|
||||
externalID := os.Getenv("RESTIC_AWS_ASSUME_ROLE_EXTERNAL_ID")
|
||||
policy := os.Getenv("RESTIC_AWS_ASSUME_ROLE_POLICY")
|
||||
stsEndpoint := os.Getenv("RESTIC_AWS_ASSUME_ROLE_STS_ENDPOINT")
|
||||
|
||||
if stsEndpoint == "" {
|
||||
if awsRegion != "" {
|
||||
if strings.HasPrefix(awsRegion, "cn-") {
|
||||
stsEndpoint = "https://sts." + awsRegion + ".amazonaws.com.cn"
|
||||
} else {
|
||||
stsEndpoint = "https://sts." + awsRegion + ".amazonaws.com"
|
||||
}
|
||||
} else {
|
||||
stsEndpoint = "https://sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
|
||||
opts := credentials.STSAssumeRoleOptions{
|
||||
RoleARN: roleArn,
|
||||
AccessKey: c.AccessKeyID,
|
||||
SecretKey: c.SecretAccessKey,
|
||||
SessionToken: c.SessionToken,
|
||||
RoleSessionName: sessionName,
|
||||
ExternalID: externalID,
|
||||
Policy: policy,
|
||||
Location: awsRegion,
|
||||
}
|
||||
|
||||
creds, err = credentials.NewSTSAssumeRole(stsEndpoint, opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creds.AssumeRole")
|
||||
}
|
||||
}
|
||||
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
// Open opens the S3 backend at bucket and region. The bucket is created if it
|
||||
// does not exist yet.
|
||||
func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backend, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user