Skip to content

Commit

Permalink
Remote state errors improvement (#3032)
Browse files Browse the repository at this point in the history
* Updated S3 remote state error message to include root cause and bucket name

* Add test check for s3 bucket name

* GCS bucket name in error
  • Loading branch information
denis256 committed Apr 2, 2024
1 parent 52425e4 commit 0d1e6a8
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 25 deletions.
2 changes: 1 addition & 1 deletion remote/remote_state_gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ func CreateGCSBucket(gcsClient *storage.Client, config *ExtendedRemoteStateConfi
}

err := bucket.Create(ctx, projectID, bucketAttrs)
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error creating GCS bucket %s", config.remoteStateConfigGCS.Bucket)
}

// GCP is eventually consistent, so after creating a GCS bucket, this method can be used to wait until the information
Expand Down
48 changes: 24 additions & 24 deletions remote/remote_state_s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -910,12 +910,12 @@ func EnableRootAccesstoS3Bucket(s3Client *s3.S3, config *ExtendedRemoteStateConf

accountID, err := aws_helper.GetAWSAccountID(config.GetAwsSessionConfig(), terragruntOptions)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error getting AWS account ID %s for bucket %s", accountID, bucket)
}

partition, err := aws_helper.GetAWSPartition(config.GetAwsSessionConfig(), terragruntOptions)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error getting AWS partition %s for bucket %s", partition, bucket)
}

var policyInBucket aws_helper.Policy
Expand All @@ -931,7 +931,7 @@ func EnableRootAccesstoS3Bucket(s3Client *s3.S3, config *ExtendedRemoteStateConf
terragruntOptions.Logger.Debugf("Policy already exists for bucket %s", bucket)
policyInBucket, err = aws_helper.UnmarshalPolicy(*policyOutput.Policy)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error unmarshalling policy for bucket %s", bucket)
}
}

Expand Down Expand Up @@ -966,15 +966,15 @@ func EnableRootAccesstoS3Bucket(s3Client *s3.S3, config *ExtendedRemoteStateConf
rootS3Policy.Statement = append(rootS3Policy.Statement, policyInBucket.Statement...)
policy, err := aws_helper.MarshalPolicy(rootS3Policy)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error marshalling policy for bucket %s", bucket)
}

_, err = s3Client.PutBucketPolicy(&s3.PutBucketPolicyInput{
Bucket: aws.String(bucket),
Policy: aws.String(string(policy)),
})
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error putting policy for bucket %s", bucket)
}

terragruntOptions.Logger.Debugf("Enabled root access to bucket %s", bucket)
Expand All @@ -996,7 +996,7 @@ func checkIfBucketRootAccess(s3Client *s3.S3, config *RemoteStateConfigS3, terra
}
}
terragruntOptions.Logger.Debugf("Could not get policy for bucket %s", config.Bucket)
return false, errors.WithStackTrace(err)
return false, errors.WithStackTraceAndPrefix(err, "Error checking if bucket %s is have root access", config.Bucket)
}

// If the bucket has no policy, it is not enforced
Expand All @@ -1006,7 +1006,7 @@ func checkIfBucketRootAccess(s3Client *s3.S3, config *RemoteStateConfigS3, terra

policyInBucket, err := aws_helper.UnmarshalPolicy(*policyOutput.Policy)
if err != nil {
return false, errors.WithStackTrace(err)
return false, errors.WithStackTraceAndPrefix(err, "Error unmarshalling policy for bucket %s", config.Bucket)
}

for _, statement := range policyInBucket.Statement {
Expand Down Expand Up @@ -1042,7 +1042,7 @@ func EnableEnforcedTLSAccesstoS3Bucket(s3Client *s3.S3, bucket string, config *E
terragruntOptions.Logger.Debugf("Policy already exists for bucket %s", bucket)
policyInBucket, err = aws_helper.UnmarshalPolicy(*policyOutput.Policy)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error unmarshalling policy for bucket %s", bucket)
}
}

Expand Down Expand Up @@ -1078,15 +1078,15 @@ func EnableEnforcedTLSAccesstoS3Bucket(s3Client *s3.S3, bucket string, config *E
tlsS3Policy.Statement = append(tlsS3Policy.Statement, policyInBucket.Statement...)
policy, err := aws_helper.MarshalPolicy(tlsS3Policy)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error marshalling policy for bucket %s", bucket)
}

_, err = s3Client.PutBucketPolicy(&s3.PutBucketPolicyInput{
Bucket: aws.String(bucket),
Policy: aws.String(string(policy)),
})
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error putting policy for bucket %s", bucket)
}

terragruntOptions.Logger.Debugf("Enabled enforced TLS access for bucket %s", bucket)
Expand All @@ -1111,7 +1111,7 @@ func checkIfBucketEnforcedTLS(s3Client *s3.S3, config *RemoteStateConfigS3, terr
}
}

return false, errors.WithStackTrace(err)
return false, errors.WithStackTraceAndPrefix(err, "Error checking if bucket %s is enforced with TLS", config.Bucket)
}

if policyOutput.Policy == nil {
Expand All @@ -1120,7 +1120,7 @@ func checkIfBucketEnforcedTLS(s3Client *s3.S3, config *RemoteStateConfigS3, terr

policyInBucket, err := aws_helper.UnmarshalPolicy(*policyOutput.Policy)
if err != nil {
return false, errors.WithStackTrace(err)
return false, errors.WithStackTraceAndPrefix(err, "Error unmarshalling policy for bucket %s", config.Bucket)
}

for _, statement := range policyInBucket.Statement {
Expand All @@ -1144,7 +1144,7 @@ func EnableVersioningForS3Bucket(s3Client *s3.S3, config *RemoteStateConfigS3, t

_, err := s3Client.PutBucketVersioning(&input)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error enabling versioning on S3 bucket %s", config.Bucket)
}

terragruntOptions.Logger.Debugf("Enabled versioning on S3 bucket %s", config.Bucket)
Expand Down Expand Up @@ -1182,7 +1182,7 @@ func EnableSSEForS3BucketWide(s3Client *s3.S3, bucketName string, algorithm stri

_, err = s3Client.PutBucketEncryption(input)
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error enabling bucket-wide SSE on AWS S3 bucket %s", bucketName)
}

terragruntOptions.Logger.Debugf("Enabled bucket-wide SSE on AWS S3 bucket %s", bucketName)
Expand All @@ -1205,7 +1205,7 @@ func checkIfSSEForS3Enabled(s3Client *s3.S3, config *ExtendedRemoteStateConfigS3
output, err := s3Client.GetBucketEncryption(input)
if err != nil {
terragruntOptions.Logger.Debugf("Error checking if SSE is enabled for AWS S3 bucket %s: %s", config.remoteStateConfigS3.Bucket, err.Error())
return false, err
return false, errors.WithStackTraceAndPrefix(err, "Error checking if SSE is enabled for AWS S3 bucket %s", config.remoteStateConfigS3.Bucket)
}

if output.ServerSideEncryptionConfiguration == nil {
Expand All @@ -1227,10 +1227,10 @@ func checkIfSSEForS3Enabled(s3Client *s3.S3, config *ExtendedRemoteStateConfigS3
return false, nil
}

// Enable bucket-wide Access Logging for the AWS S3 bucket specified in the given config
// EnableAccessLoggingForS3BucketWide Enable bucket-wide Access Logging for the AWS S3 bucket specified in the given config
func EnableAccessLoggingForS3BucketWide(s3Client *s3.S3, config *RemoteStateConfigS3, terragruntOptions *options.TerragruntOptions, logsBucket string, logsBucketPrefix string) error {
if err := configureBucketAccessLoggingAcl(s3Client, aws.String(logsBucket), terragruntOptions); err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error configuring bucket access logging ACL on S3 bucket %s", config.Bucket)
}

terragruntOptions.Logger.Debugf("Putting bucket logging on S3 bucket %s with TargetBucket %s and TargetPrefix %s", config.Bucket, logsBucket, logsBucketPrefix)
Expand All @@ -1246,7 +1246,7 @@ func EnableAccessLoggingForS3BucketWide(s3Client *s3.S3, config *RemoteStateConf
}

if _, err := s3Client.PutBucketLogging(&loggingInput); err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error enabling bucket-wide Access Logging on AWS S3 bucket %s", config.Bucket)
}

terragruntOptions.Logger.Debugf("Enabled bucket-wide Access Logging on AWS S3 bucket %s", config.Bucket)
Expand All @@ -1260,7 +1260,7 @@ func checkIfAccessLoggingForS3Enabled(s3Client *s3.S3, config *RemoteStateConfig
output, err := s3Client.GetBucketLogging(input)
if err != nil {
terragruntOptions.Logger.Debugf("Error checking if Access Logging is enabled for AWS S3 bucket %s: %s", config.Bucket, err.Error())
return false, err
return false, errors.WithStackTraceAndPrefix(err, "Error checking if Access Logging is enabled for AWS S3 bucket %s", config.Bucket)
}

if output.LoggingEnabled == nil {
Expand Down Expand Up @@ -1288,7 +1288,7 @@ func EnablePublicAccessBlockingForS3Bucket(s3Client *s3.S3, bucketName string, t
)

if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error blocking all public access to S3 bucket %s", bucketName)
}

terragruntOptions.Logger.Debugf("Blocked all public access to S3 bucket %s", bucketName)
Expand All @@ -1310,7 +1310,7 @@ func checkIfS3PublicAccessBlockingEnabled(s3Client *s3.S3, config *RemoteStateCo
}
}

return false, errors.WithStackTrace(err)
return false, errors.WithStackTraceAndPrefix(err, "Error checking if S3 bucket %s is configured to block public access", config.Bucket)
}

return validatePublicAccessBlock(output)
Expand Down Expand Up @@ -1351,7 +1351,7 @@ func configureBucketAccessLoggingAcl(s3Client *s3.S3, bucket *string, terragrunt
}

if _, err := s3Client.PutBucketAcl(&aclInput); err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error granting WRITE and READ_ACP permissions to S3 Log Delivery (%s) for bucket %s", s3LogDeliveryGranteeUri, *bucket)
}

return waitUntilBucketHasAccessLoggingAcl(s3Client, bucket, terragruntOptions)
Expand All @@ -1365,7 +1365,7 @@ func waitUntilBucketHasAccessLoggingAcl(s3Client *s3.S3, bucket *string, terragr
for i := 0; i < maxRetries; i++ {
out, err := s3Client.GetBucketAcl(&s3.GetBucketAclInput{Bucket: bucket})
if err != nil {
return errors.WithStackTrace(err)
return errors.WithStackTraceAndPrefix(err, "Error getting ACL for bucket %s", *bucket)
}

hasReadAcp := false
Expand Down Expand Up @@ -1415,7 +1415,7 @@ func checkBucketAccess(s3Client *s3.S3, bucket *string, key *string) error {
if awsErr.Code() == "NoSuchBucket" || awsErr.Code() == "NoSuchKey" {
return nil
}
return err
return errors.WithStackTraceAndPrefix(err, "Error checking access to S3 bucket %s", *bucket)
}

// Create a table for locks in DynamoDB if the user has configured a lock table and the table doesn't already exist
Expand Down
1 change: 1 addition & 0 deletions test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6158,6 +6158,7 @@ func TestTerragruntPrintAwsErrors(t *testing.T) {
assert.Error(t, err)
message := fmt.Sprintf("%v", err.Error())
assert.True(t, strings.Contains(message, "AllAccessDisabled: All access to this object has been disabled") || strings.Contains(message, "BucketRegionError: incorrect region"))
assert.Contains(t, message, s3BucketName)
}

func TestTerragruntErrorWhenStateBucketIsInDifferentRegion(t *testing.T) {
Expand Down

0 comments on commit 0d1e6a8

Please sign in to comment.