Middleware to explode inline policy
parent
c77d6018fe
commit
54a7bb211d
|
@ -46,6 +46,7 @@ func (d DriftCTL) Run() *analyser.Analysis {
|
|||
middlewares.NewAwsDefaultRouteTable(),
|
||||
middlewares.NewAwsDefaultRoute(),
|
||||
middlewares.NewAwsNatGatewayEipAssoc(),
|
||||
middlewares.NewAwsBucketPolicyExpander(),
|
||||
)
|
||||
|
||||
logrus.Debug("Ready to run middlewares")
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Explodes policy found in aws_s3_bucket.policy from state resources to dedicated resources
|
||||
type AwsBucketPolicyExpander struct{}
|
||||
|
||||
func NewAwsBucketPolicyExpander() AwsBucketPolicyExpander {
|
||||
return AwsBucketPolicyExpander{}
|
||||
}
|
||||
|
||||
func (m AwsBucketPolicyExpander) Execute(_, resourcesFromState *[]resource.Resource) error {
|
||||
newList := make([]resource.Resource, 0)
|
||||
for _, res := range *resourcesFromState {
|
||||
// Ignore all resources other than s3_bucket
|
||||
if res.TerraformType() != aws.AwsS3BucketResourceType {
|
||||
newList = append(newList, res)
|
||||
continue
|
||||
}
|
||||
|
||||
bucket, _ := res.(*aws.AwsS3Bucket)
|
||||
newList = append(newList, res)
|
||||
|
||||
if hasPolicyAttached(bucket, resourcesFromState) {
|
||||
bucket.Policy = nil
|
||||
continue
|
||||
}
|
||||
|
||||
err := m.handlePolicy(bucket, &newList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*resourcesFromState = newList
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AwsBucketPolicyExpander) handlePolicy(bucket *aws.AwsS3Bucket, results *[]resource.Resource) error {
|
||||
if bucket.Policy == nil || *bucket.Policy == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
newPolicy := &aws.AwsS3BucketPolicy{
|
||||
Id: bucket.Id,
|
||||
Bucket: bucket.Bucket,
|
||||
Policy: bucket.Policy,
|
||||
}
|
||||
normalizedRes, err := newPolicy.NormalizeForState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*results = append(*results, normalizedRes)
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"id": newPolicy.TerraformId(),
|
||||
}).Debug("Created new policy from bucket")
|
||||
|
||||
bucket.Policy = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return true if the bucket has a aws_bucket_policy resource attached to itself.
|
||||
// It is mandatory since it's possible to have a aws_bucket with an inline policy
|
||||
// AND a aws_bucket_policy resource at the same time. At the end, on the AWS console,
|
||||
// the aws_bucket_policy will be used.
|
||||
func hasPolicyAttached(bucket *aws.AwsS3Bucket, resourcesFromState *[]resource.Resource) bool {
|
||||
for _, res := range *resourcesFromState {
|
||||
if res.TerraformType() == aws.AwsS3BucketPolicyResourceType &&
|
||||
res.TerraformId() == bucket.Id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
awssdk "github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
func TestAwsBucketPolicyExpander_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcesFromState []resource.Resource
|
||||
expected []resource.Resource
|
||||
}{
|
||||
{
|
||||
"Inline policy, no aws_s3_bucket_policy attached",
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINEBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsS3BucketPolicy{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINEBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"No inline policy, aws_s3_bucket_policy attached",
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsS3BucketPolicy{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsS3BucketPolicy{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Inline policy and aws_s3_bucket_policy",
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINEBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
&aws.AwsS3BucketPolicy{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsS3Bucket{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsS3BucketPolicy{
|
||||
Id: "foo",
|
||||
Bucket: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYBUCKETPOLICY\",\"Statement\":[{\"Action\":\"s3:*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"8.8.8.8/32\"}},\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"arn:aws:s3:::bucket-test-policy-like-sqs/*\",\"Sid\":\"IPAllow\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := NewAwsBucketPolicyExpander()
|
||||
err := m.Execute(&[]resource.Resource{}, &tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
changelog, err := diff.Diff(tt.expected, tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(changelog) > 0 {
|
||||
for _, change := range changelog {
|
||||
t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue