Skip to content

Commit

Permalink
Allow root user to access remote state S3 bucket
Browse files Browse the repository at this point in the history
After creating the remote state S3 bucket, we need to grant access to
the root user. Without this, the root user cannot use the remote state
bucket. This is documented by AWS here:
https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_iam-s3.html.

Fixes gruntwork-io#770.
  • Loading branch information
bwhaley committed Dec 18, 2019
1 parent 26627f1 commit 273141a
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions remote/remote_state_s3.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package remote

import (
"encoding/json"
"fmt"
"reflect"
"strconv"
Expand All @@ -9,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/gruntwork-io/terragrunt/aws_helper"
"github.com/gruntwork-io/terragrunt/dynamodb"
"github.com/gruntwork-io/terragrunt/errors"
Expand Down Expand Up @@ -356,6 +358,10 @@ func CreateS3BucketWithVersioningSSEncryptionAndAccessLogging(s3Client *s3.S3, c
return err
}

if err := EnableRootAccesstoS3Bucket(s3Client, &config.remoteStateConfigS3, terragruntOptions); err != nil {
return err
}

if err := EnablePublicAccessBlockingForS3Bucket(s3Client, &config.remoteStateConfigS3, terragruntOptions); err != nil {
return err
}
Expand Down Expand Up @@ -458,6 +464,62 @@ func isBucketAlreadyOwnedByYourError(err error) bool {
return isAwsErr && (awsErr.Code() == "BucketAlreadyOwnedByYou" || awsErr.Code() == "OperationAborted")
}

// Get the AWS account ID of the current session configuration
func getAWSAccountID(config *aws_helper.AwsSessionConfig, terragruntOptions *options.TerragruntOptions) (string, error) {
session, err := aws_helper.CreateAwsSession(config, terragruntOptions)
if err != nil {
return "", err
}

identity, err := sts.New(session).GetCallerIdentity(nil)
if err != nil {
return "", errors.WithStackTrace(err)
}

return *identity.Account, nil
}

// Create the S3 bucket specified in the given config
func EnableRootAccesstoS3Bucket(s3Client *s3.S3, config *RemoteStateConfigS3, terragruntOptions *options.TerragruntOptions) error {
accountID, err := getAWSAccountID(config.GetAwsSessionConfig(), terragruntOptions)
if err != nil {
return errors.WithStackTrace(err)
}

rootS3Policy := map[string]interface{}{
"Version": "2012-10-17",
"Statement": []map[string]interface{}{
{
"Sid": "RootAccess",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::" + config.Bucket,
"Principal": map[string][]string{
"AWS": []string{
"arn:aws:iam::" + accountID + ":root",
},
},
},
},
}

policy, err := json.Marshal(rootS3Policy)
if err != nil {
return errors.WithStackTrace(err)
}

_, err = s3Client.PutBucketPolicy(&s3.PutBucketPolicyInput{
Bucket: aws.String(config.Bucket),
Policy: aws.String(string(policy)),
})
if err != nil {
return errors.WithStackTrace(err)
}

terragruntOptions.Logger.Printf("Enabled root access to bucket %s", config.Bucket)
return nil
}

// Enable versioning for the S3 bucket specified in the given config
func EnableVersioningForS3Bucket(s3Client *s3.S3, config *RemoteStateConfigS3, terragruntOptions *options.TerragruntOptions) error {
terragruntOptions.Logger.Printf("Enabling versioning on S3 bucket %s", config.Bucket)
Expand Down

0 comments on commit 273141a

Please sign in to comment.