Add aws_sqs_queue_policy
parent
ad5ad4cc76
commit
d3c542c004
|
@ -244,4 +244,4 @@ As AWS documentation recommends, the below policy is granting only the permissio
|
|||
## SQS
|
||||
|
||||
- [x] aws_sqs_queue
|
||||
- [ ] aws_sqs_queue_policy
|
||||
- [x] aws_sqs_queue_policy
|
||||
|
|
|
@ -47,6 +47,8 @@ func (d DriftCTL) Run() *analyser.Analysis {
|
|||
middlewares.NewAwsDefaultRoute(),
|
||||
middlewares.NewAwsNatGatewayEipAssoc(),
|
||||
middlewares.NewAwsBucketPolicyExpander(),
|
||||
middlewares.NewAwsSqsQueuePolicyExpander(),
|
||||
middlewares.NewAwsDefaultSqsQueuePolicy(),
|
||||
)
|
||||
|
||||
logrus.Debug("Ready to run middlewares")
|
||||
|
|
|
@ -48,5 +48,6 @@ func Deserializers() []deserializer.CTYDeserializer {
|
|||
awsdeserializer.NewNatGatewayDeserializer(),
|
||||
awsdeserializer.NewInternetGatewayDeserializer(),
|
||||
awsdeserializer.NewSqsQueueDeserializer(),
|
||||
awsdeserializer.NewSqsQueuePolicyDeserializer(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ func TestTerraformStateReader_Resources(t *testing.T) {
|
|||
{name: "NAT gateway", dirName: "aws_nat_gateway", wantErr: false},
|
||||
{name: "Internet Gateway", dirName: "internet_gateway", wantErr: false},
|
||||
{name: "SQS queue", dirName: "sqs_queue", wantErr: false},
|
||||
{name: "SQS queue policy", dirName: "sqs_queue_policy", wantErr: false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"MessageRetentionSeconds": 345600,
|
||||
"Name": "bar.fifo",
|
||||
"NamePrefix": null,
|
||||
"Policy": "",
|
||||
"Policy": null,
|
||||
"ReceiveWaitTimeSeconds": 0,
|
||||
"RedrivePolicy": "",
|
||||
"Tags": {},
|
||||
|
@ -29,7 +29,7 @@
|
|||
"MessageRetentionSeconds": 345600,
|
||||
"Name": "foo",
|
||||
"NamePrefix": null,
|
||||
"Policy": "",
|
||||
"Policy": null,
|
||||
"ReceiveWaitTimeSeconds": 0,
|
||||
"RedrivePolicy": "",
|
||||
"Tags": {},
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
{
|
||||
"Id": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo",
|
||||
"Policy": "{\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:bar.fifo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}",
|
||||
"QueueUrl": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.14.5",
|
||||
"serial": 638,
|
||||
"lineage": "cc4be827-a907-1623-961b-0fc1ce33973e",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_sqs_queue_policy",
|
||||
"name": "test",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 1,
|
||||
"attributes": {
|
||||
"id": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo",
|
||||
"policy": "{\"Version\":\"2012-10-17\",\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Sid\":\"Stmt1611769527792\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:bar.fifo\"}]}",
|
||||
"queue_url": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SQS queues from AWS have a weird behaviour when we fetch them.
|
||||
// By default they have a Policy attached with only an ID
|
||||
// "arn:aws:sqs:eu-west-3:XXXXXXXXXXXX:foobar/SQSDefaultPolicy" but on fetch
|
||||
// the SDK return an empty policy (e.g. policy = "").
|
||||
// We need to ignore those policy from unmanaged resources if they are not managed
|
||||
// by IaC.
|
||||
type AwsDefaultSqsQueuePolicy struct{}
|
||||
|
||||
func NewAwsDefaultSqsQueuePolicy() AwsDefaultSqsQueuePolicy {
|
||||
return AwsDefaultSqsQueuePolicy{}
|
||||
}
|
||||
|
||||
func (m AwsDefaultSqsQueuePolicy) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
|
||||
newRemoteResources := make([]resource.Resource, 0)
|
||||
for _, res := range *remoteResources {
|
||||
// Ignore all resources other than sqs_queue_policy
|
||||
if res.TerraformType() != aws.AwsSqsQueuePolicyResourceType {
|
||||
newRemoteResources = append(newRemoteResources, res)
|
||||
continue
|
||||
}
|
||||
|
||||
policy, _ := res.(*aws.AwsSqsQueuePolicy)
|
||||
|
||||
// Ignore all non-default queue policy
|
||||
if policy.Policy != nil && *policy.Policy != "" {
|
||||
newRemoteResources = append(newRemoteResources, policy)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if queue policy is managed by IaC
|
||||
existInState := false
|
||||
for _, stateResource := range *resourcesFromState {
|
||||
if resource.IsSameResource(res, stateResource) {
|
||||
existInState = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Include resource if it's managed in IaC
|
||||
if existInState {
|
||||
newRemoteResources = append(newRemoteResources, res)
|
||||
continue
|
||||
}
|
||||
|
||||
// Else, resource is not added to newRemoteResources slice so it will be ignored
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"id": res.TerraformId(),
|
||||
"type": res.TerraformType(),
|
||||
}).Debug("Ignoring default queue policy as it is not managed by IaC")
|
||||
}
|
||||
*remoteResources = newRemoteResources
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
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 TestAwsDefaultSqsQueuePolicy_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
remoteResources []resource.Resource
|
||||
resourcesFromState []resource.Resource
|
||||
expected []resource.Resource
|
||||
}{
|
||||
{
|
||||
"test default sqs queue policy managed by IaC",
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "default-sqs-queue-policy",
|
||||
Policy: awssdk.String(""),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "default-sqs-queue-policy",
|
||||
Policy: awssdk.String(""),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "default-sqs-queue-policy",
|
||||
Policy: awssdk.String(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"test default sqs queue policy not managed by IaC",
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "default-sqs-queue-policy",
|
||||
Policy: awssdk.String(""),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "non-default-sqs-queue-policy",
|
||||
Policy: awssdk.String("foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := NewAwsDefaultSqsQueuePolicy()
|
||||
err := m.Execute(&tt.remoteResources, &tt.resourcesFromState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changelog, err := diff.Diff(tt.remoteResources, tt.expected)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
awssdk "github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Explodes policy found in aws_sqs_queue.policy from state resources to dedicated resources
|
||||
type AwsSqsQueuePolicyExpander struct{}
|
||||
|
||||
func NewAwsSqsQueuePolicyExpander() AwsSqsQueuePolicyExpander {
|
||||
return AwsSqsQueuePolicyExpander{}
|
||||
}
|
||||
|
||||
func (m AwsSqsQueuePolicyExpander) Execute(_, resourcesFromState *[]resource.Resource) error {
|
||||
newList := make([]resource.Resource, 0)
|
||||
for _, res := range *resourcesFromState {
|
||||
// Ignore all resources other than sqs_queue
|
||||
if res.TerraformType() != aws.AwsSqsQueueResourceType {
|
||||
newList = append(newList, res)
|
||||
continue
|
||||
}
|
||||
|
||||
queue, _ := res.(*aws.AwsSqsQueue)
|
||||
newList = append(newList, res)
|
||||
|
||||
if m.hasPolicyAttached(queue, resourcesFromState) {
|
||||
queue.Policy = nil
|
||||
continue
|
||||
}
|
||||
|
||||
err := m.handlePolicy(queue, &newList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*resourcesFromState = newList
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AwsSqsQueuePolicyExpander) handlePolicy(queue *aws.AwsSqsQueue, results *[]resource.Resource) error {
|
||||
if queue.Policy == nil || *queue.Policy == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
newPolicy := &aws.AwsSqsQueuePolicy{
|
||||
Id: queue.Id,
|
||||
QueueUrl: awssdk.String(queue.Id),
|
||||
Policy: queue.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 sqs queue")
|
||||
|
||||
queue.Policy = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return true if the sqs queue has a aws_sqs_queue_policy resource attached to itself.
|
||||
// It is mandatory since it's possible to have a aws_sqs_queue with an inline policy
|
||||
// AND a aws_sqs_queue_policy resource at the same time. At the end, on the AWS console,
|
||||
// the aws_sqs_queue_policy will be used.
|
||||
func (m *AwsSqsQueuePolicyExpander) hasPolicyAttached(queue *aws.AwsSqsQueue, resourcesFromState *[]resource.Resource) bool {
|
||||
for _, res := range *resourcesFromState {
|
||||
if res.TerraformType() == aws.AwsSqsQueuePolicyResourceType &&
|
||||
res.TerraformId() == queue.Id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
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 TestAwsSqsQueuePolicyExpander_Execute(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcesFromState []resource.Resource
|
||||
expected []resource.Resource
|
||||
}{
|
||||
{
|
||||
"Inline policy, no aws_sqs_queue_policy attached",
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINESQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "foo",
|
||||
QueueUrl: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINESQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"No inline policy, aws_sqs_queue_policy attached",
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "foo",
|
||||
QueueUrl: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "foo",
|
||||
QueueUrl: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Inline policy and aws_sqs_queue_policy",
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: awssdk.String("{\"Id\":\"MYINLINESQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "foo",
|
||||
QueueUrl: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
[]resource.Resource{
|
||||
&aws.AwsSqsQueue{
|
||||
Id: "foo",
|
||||
Policy: nil,
|
||||
},
|
||||
&aws.AwsSqsQueuePolicy{
|
||||
Id: "foo",
|
||||
QueueUrl: awssdk.String("foo"),
|
||||
Policy: awssdk.String("{\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Action\":\"sqs:SendMessage\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\",\"Sid\":\"Stmt1611769527792\"}],\"Version\":\"2012-10-17\"}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := NewAwsSqsQueuePolicyExpander()
|
||||
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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/sqs"
|
||||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
|
@ -59,7 +58,7 @@ func Init(alerter *alerter.Alerter, providerLibrary *terraform.ProviderLibrary,
|
|||
supplierLibrary.AddSupplier(NewNatGatewaySupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewInternetGatewaySupplier(provider))
|
||||
supplierLibrary.AddSupplier(NewSqsQueueSupplier(provider))
|
||||
resource.AddSupplier(NewSqsQueuePolicySupplier(provider.Runner().SubRunner(), sqs.New(provider.session)))
|
||||
supplierLibrary.AddSupplier(NewSqsQueuePolicySupplier(provider))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/sqs"
|
||||
"github.com/aws/aws-sdk-go/service/sqs/sqsiface"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
type SqsQueuePolicySupplier struct {
|
||||
reader terraform.ResourceReader
|
||||
deserializer deserializer.CTYDeserializer
|
||||
client sqsiface.SQSAPI
|
||||
runner *terraform.ParallelResourceReader
|
||||
}
|
||||
|
||||
func NewSqsQueuePolicySupplier(provider *TerraformProvider) *SqsQueuePolicySupplier {
|
||||
return &SqsQueuePolicySupplier{
|
||||
provider,
|
||||
awsdeserializer.NewSqsQueuePolicyDeserializer(),
|
||||
sqs.New(provider.session),
|
||||
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
|
||||
}
|
||||
}
|
||||
|
||||
func (s SqsQueuePolicySupplier) Resources() ([]resource.Resource, error) {
|
||||
queues, err := listSqsQueues(s.client)
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceEnumerationErrorWithType(err, aws.AwsSqsQueuePolicyResourceType, aws.AwsSqsQueueResourceType)
|
||||
}
|
||||
|
||||
for _, queue := range queues {
|
||||
q := *queue
|
||||
s.runner.Run(func() (cty.Value, error) {
|
||||
return s.readSqsQueuePolicy(q)
|
||||
})
|
||||
}
|
||||
|
||||
resources, err := s.runner.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.deserializer.Deserialize(resources)
|
||||
}
|
||||
|
||||
func (s SqsQueuePolicySupplier) readSqsQueuePolicy(queue string) (cty.Value, error) {
|
||||
var Ty resource.ResourceType = aws.AwsSqsQueuePolicyResourceType
|
||||
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
|
||||
Ty: Ty,
|
||||
ID: queue,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"type": Ty,
|
||||
}).Error(err)
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return *val, nil
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
||||
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/sqs"
|
||||
|
||||
awssdk "github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
"github.com/cloudskiff/driftctl/mocks"
|
||||
"github.com/cloudskiff/driftctl/pkg/parallel"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
|
||||
"github.com/cloudskiff/driftctl/pkg/terraform"
|
||||
"github.com/cloudskiff/driftctl/test"
|
||||
"github.com/cloudskiff/driftctl/test/goldenfile"
|
||||
mocks2 "github.com/cloudskiff/driftctl/test/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestSqsQueuePolicySupplier_Resources(t *testing.T) {
|
||||
cases := []struct {
|
||||
test string
|
||||
dirName string
|
||||
mocks func(client *mocks.FakeSQS)
|
||||
err error
|
||||
}{
|
||||
{
|
||||
// sqs queue with no policy case is not possible
|
||||
// as a default SQSDefaultPolicy (e.g. policy="") will always be present in each queue
|
||||
test: "no sqs queue policies",
|
||||
dirName: "sqs_queue_policy_empty",
|
||||
mocks: func(client *mocks.FakeSQS) {
|
||||
client.On("ListQueuesPages",
|
||||
&sqs.ListQueuesInput{},
|
||||
mock.MatchedBy(func(callback func(res *sqs.ListQueuesOutput, lastPage bool) bool) bool {
|
||||
callback(&sqs.ListQueuesOutput{}, true)
|
||||
return true
|
||||
})).Return(nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "multiple sqs queue policies (default or not)",
|
||||
dirName: "sqs_queue_policy_multiple",
|
||||
mocks: func(client *mocks.FakeSQS) {
|
||||
client.On("ListQueuesPages",
|
||||
&sqs.ListQueuesInput{},
|
||||
mock.MatchedBy(func(callback func(res *sqs.ListQueuesOutput, lastPage bool) bool) bool {
|
||||
callback(&sqs.ListQueuesOutput{
|
||||
QueueUrls: []*string{
|
||||
awssdk.String("https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo"),
|
||||
awssdk.String("https://sqs.eu-west-3.amazonaws.com/047081014315/foo"),
|
||||
awssdk.String("https://sqs.eu-west-3.amazonaws.com/047081014315/baz"),
|
||||
},
|
||||
}, true)
|
||||
return true
|
||||
})).Return(nil)
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
test: "cannot list sqs queues, thus sqs queue policies",
|
||||
dirName: "sqs_queue_policy_empty",
|
||||
mocks: func(client *mocks.FakeSQS) {
|
||||
client.On(
|
||||
"ListQueuesPages",
|
||||
&sqs.ListQueuesInput{},
|
||||
mock.Anything,
|
||||
).Once().Return(awserr.NewRequestFailure(nil, 403, ""))
|
||||
},
|
||||
err: remoteerror.NewResourceEnumerationErrorWithType(awserr.NewRequestFailure(nil, 403, ""), resourceaws.AwsSqsQueuePolicyResourceType, resourceaws.AwsSqsQueueResourceType),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
shouldUpdate := c.dirName == *goldenfile.Update
|
||||
providerLibrary := terraform.NewProviderLibrary()
|
||||
supplierLibrary := resource.NewSupplierLibrary()
|
||||
|
||||
if shouldUpdate {
|
||||
provider, err := NewTerraFormProvider()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
providerLibrary.AddProvider(terraform.AWS, provider)
|
||||
supplierLibrary.AddSupplier(NewSqsQueuePolicySupplier(provider))
|
||||
}
|
||||
|
||||
t.Run(c.test, func(tt *testing.T) {
|
||||
fakeSQS := mocks.FakeSQS{}
|
||||
c.mocks(&fakeSQS)
|
||||
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, providerLibrary.Provider(terraform.AWS), shouldUpdate)
|
||||
sqsQueuePolicyDeserializer := awsdeserializer.NewSqsQueuePolicyDeserializer()
|
||||
s := &SqsQueuePolicySupplier{
|
||||
provider,
|
||||
sqsQueuePolicyDeserializer,
|
||||
&fakeSQS,
|
||||
terraform.NewParallelResourceReader(parallel.NewParallelRunner(context.TODO(), 10)),
|
||||
}
|
||||
got, err := s.Resources()
|
||||
assert.Equal(tt, c.err, err)
|
||||
|
||||
mock.AssertExpectationsForObjects(tt)
|
||||
deserializers := []deserializer.CTYDeserializer{sqsQueuePolicyDeserializer}
|
||||
test.CtyTestDiffMixed(got, c.dirName, provider, deserializers, shouldUpdate, tt)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiaWQiOiJzdHJpbmciLCJwb2xpY3kiOiJzdHJpbmciLCJxdWV1ZV91cmwiOiJzdHJpbmcifV0=",
|
||||
"Val": "eyJpZCI6Imh0dHBzOi8vc3FzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tLzA0NzA4MTAxNDMxNS9iYXIuZmlmbyIsInBvbGljeSI6IiIsInF1ZXVlX3VybCI6Imh0dHBzOi8vc3FzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tLzA0NzA4MTAxNDMxNS9iYXIuZmlmbyJ9",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiaWQiOiJzdHJpbmciLCJwb2xpY3kiOiJzdHJpbmciLCJxdWV1ZV91cmwiOiJzdHJpbmcifV0=",
|
||||
"Val": "eyJpZCI6Imh0dHBzOi8vc3FzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tLzA0NzA4MTAxNDMxNS9iYXoiLCJwb2xpY3kiOiJ7XCJWZXJzaW9uXCI6XCIyMDEyLTEwLTE3XCIsXCJJZFwiOlwiTVlTUVNQT0xJQ1lcIixcIlN0YXRlbWVudFwiOlt7XCJTaWRcIjpcIlN0bXQxNjExNzY5NTI3NzkyXCIsXCJFZmZlY3RcIjpcIkFsbG93XCIsXCJQcmluY2lwYWxcIjpcIipcIixcIkFjdGlvblwiOlwic3FzOlNlbmRNZXNzYWdlXCIsXCJSZXNvdXJjZVwiOlwiYXJuOmF3czpzcXM6ZXUtd2VzdC0zOjA0NzA4MTAxNDMxNTpiYXpcIn1dfSIsInF1ZXVlX3VybCI6Imh0dHBzOi8vc3FzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tLzA0NzA4MTAxNDMxNS9iYXoifQ==",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Typ": "WyJvYmplY3QiLHsiaWQiOiJzdHJpbmciLCJwb2xpY3kiOiJzdHJpbmciLCJxdWV1ZV91cmwiOiJzdHJpbmcifV0=",
|
||||
"Val": "eyJpZCI6Imh0dHBzOi8vc3FzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tLzA0NzA4MTAxNDMxNS9mb28iLCJwb2xpY3kiOiJ7XCJWZXJzaW9uXCI6XCIyMDEyLTEwLTE3XCIsXCJJZFwiOlwiUG9saWN5MTYxMTc2OTUzMjQyNVwiLFwiU3RhdGVtZW50XCI6W3tcIlNpZFwiOlwiU3RtdDE2MTE3Njk1Mjc3OTJcIixcIkVmZmVjdFwiOlwiQWxsb3dcIixcIlByaW5jaXBhbFwiOlwiKlwiLFwiQWN0aW9uXCI6XCJzcXM6U2VuZE1lc3NhZ2VcIixcIlJlc291cmNlXCI6XCJhcm46YXdzOnNxczpldS13ZXN0LTM6MDQ3MDgxMDE0MzE1OmZvb1wifV19IiwicXVldWVfdXJsIjoiaHR0cHM6Ly9zcXMuZXUtd2VzdC0zLmFtYXpvbmF3cy5jb20vMDQ3MDgxMDE0MzE1L2ZvbyJ9",
|
||||
"Err": null
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"Id": "Policy1611769532425",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt1611769527792",
|
||||
"Action": ["sqs:SendMessage"],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:sqs:eu-west-3:047081014315:foo",
|
||||
"Principal": "*"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
[
|
||||
{
|
||||
"id": "https://sqs.eu-west-3.amazonaws.com/047081014315/foo",
|
||||
"policy": "{\"Version\":\"2012-10-17\",\"Id\":\"Policy1611769532425\",\"Statement\":[{\"Sid\":\"Stmt1611769527792\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:foo\"}]}",
|
||||
"queue_url": "https://sqs.eu-west-3.amazonaws.com/047081014315/foo"
|
||||
},
|
||||
{
|
||||
"id": "https://sqs.eu-west-3.amazonaws.com/047081014315/baz",
|
||||
"policy": "{\"Version\":\"2012-10-17\",\"Id\":\"MYSQSPOLICY\",\"Statement\":[{\"Sid\":\"Stmt1611769527792\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"arn:aws:sqs:eu-west-3:047081014315:baz\"}]}",
|
||||
"queue_url": "https://sqs.eu-west-3.amazonaws.com/047081014315/baz"
|
||||
},
|
||||
{
|
||||
"id": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo",
|
||||
"policy": "",
|
||||
"queue_url": "https://sqs.eu-west-3.amazonaws.com/047081014315/bar.fifo"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
|||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = "3.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "foo" {
|
||||
name = "foo"
|
||||
policy = file("policy.json")
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "bar" {
|
||||
name = "bar.fifo"
|
||||
fifo_queue = true
|
||||
content_based_deduplication = true
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "baz" {
|
||||
name = "baz"
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue_policy" "sqs-policy" {
|
||||
queue_url = aws_sqs_queue.baz.id
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Id": "MYSQSPOLICY",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt1611769527792",
|
||||
"Action": ["sqs:SendMessage"],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:sqs:eu-west-3:047081014315:baz",
|
||||
"Principal": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package aws
|
||||
|
||||
import "github.com/cloudskiff/driftctl/pkg/resource"
|
||||
|
||||
func (r *AwsSqsQueue) NormalizeForState() (resource.Resource, error) {
|
||||
if r.Policy != nil && *r.Policy == "" {
|
||||
r.Policy = nil
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *AwsSqsQueue) NormalizeForProvider() (resource.Resource, error) {
|
||||
r.Policy = nil
|
||||
return r, nil
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// GENERATED, DO NOT EDIT THIS FILE
|
||||
package aws
|
||||
|
||||
const AwsSqsQueuePolicyResourceType = "aws_sqs_queue_policy"
|
||||
|
||||
type AwsSqsQueuePolicy struct {
|
||||
Id string `cty:"id" computed:"true"`
|
||||
Policy *string `cty:"policy"`
|
||||
QueueUrl *string `cty:"queue_url"`
|
||||
}
|
||||
|
||||
func (r *AwsSqsQueuePolicy) TerraformId() string {
|
||||
return r.Id
|
||||
}
|
||||
|
||||
func (r *AwsSqsQueuePolicy) TerraformType() string {
|
||||
return AwsSqsQueuePolicyResourceType
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/cloudskiff/driftctl/pkg/helpers"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
)
|
||||
|
||||
func (r AwsSqsQueuePolicy) NormalizeForState() (resource.Resource, error) {
|
||||
err := r.normalizePolicy()
|
||||
return &r, err
|
||||
}
|
||||
|
||||
func (r AwsSqsQueuePolicy) NormalizeForProvider() (resource.Resource, error) {
|
||||
err := r.normalizePolicy()
|
||||
return &r, err
|
||||
}
|
||||
|
||||
func (r *AwsSqsQueuePolicy) normalizePolicy() error {
|
||||
if r.Policy != nil {
|
||||
jsonString, err := helpers.NormalizeJsonString(*r.Policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Policy = &jsonString
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cloudskiff/driftctl/test/acceptance"
|
||||
)
|
||||
|
||||
func TestAcc_AwsSqsQueuePolicy(t *testing.T) {
|
||||
acceptance.Run(t, acceptance.AccTestCase{
|
||||
Path: "./testdata/acc/aws_sqs_queue_policy",
|
||||
Args: []string{"scan", "--filter", "Type=='aws_sqs_queue_policy'"},
|
||||
Checks: []acceptance.AccCheck{
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "us-east-1",
|
||||
},
|
||||
Check: func(result *acceptance.ScanResult, stdout string, err error) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result.AssertInfrastructureIsInSync()
|
||||
result.Equal(2, result.Summary().TotalManaged)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package deserializer
|
||||
|
||||
import (
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
)
|
||||
|
||||
type SqsQueuePolicyDeserializer struct {
|
||||
}
|
||||
|
||||
func NewSqsQueuePolicyDeserializer() *SqsQueuePolicyDeserializer {
|
||||
return &SqsQueuePolicyDeserializer{}
|
||||
}
|
||||
|
||||
func (s *SqsQueuePolicyDeserializer) HandledType() resource.ResourceType {
|
||||
return resourceaws.AwsSqsQueuePolicyResourceType
|
||||
}
|
||||
|
||||
func (s SqsQueuePolicyDeserializer) Deserialize(rawList []cty.Value) ([]resource.Resource, error) {
|
||||
resources := make([]resource.Resource, 0)
|
||||
for _, rawResource := range rawList {
|
||||
resource, err := decodeSqsQueuePolicy(&rawResource)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"type": s.HandledType(),
|
||||
}).Warnf("Error when deserializing resource %+v : %+v", rawResource, err)
|
||||
return nil, err
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func decodeSqsQueuePolicy(raw *cty.Value) (*resourceaws.AwsSqsQueuePolicy, error) {
|
||||
var decoded resourceaws.AwsSqsQueuePolicy
|
||||
if err := gocty.FromCtyValue(*raw, &decoded); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decoded, nil
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/aws" {
|
||||
version = "3.19.0"
|
||||
constraints = "3.19.0"
|
||||
hashes = [
|
||||
"h1:xur9tF49NgsovNnmwmBR8RdpN8Fcg1TD4CKQPJD6n1A=",
|
||||
"zh:185a5259153eb9ee4699d4be43b3d509386b473683392034319beee97d470c3b",
|
||||
"zh:2d9a0a01f93e8d16539d835c02b8b6e1927b7685f4076e96cb07f7dd6944bc6c",
|
||||
"zh:703f6da36b1b5f3497baa38fccaa7765fb8a2b6440344e4c97172516b49437dd",
|
||||
"zh:770855565462abadbbddd98cb357d2f1a8f30f68a358cb37cbd5c072cb15b377",
|
||||
"zh:8008db43149fe4345301f81e15e6d9ddb47aa5e7a31648f9b290af96ad86e92a",
|
||||
"zh:8cdd27d375da6dcb7687f1fed126b7c04efce1671066802ee876dbbc9c66ec79",
|
||||
"zh:be22ae185005690d1a017c1b909e0d80ab567e239b4f06ecacdba85080667c1c",
|
||||
"zh:d2d02e72dbd80f607636cd6237a6c862897caabc635c7b50c0cb243d11246723",
|
||||
"zh:d8f125b66a1eda2555c0f9bbdf12036a5f8d073499a22ca9e4812b68067fea31",
|
||||
"zh:f5a98024c64d5d2973ff15b093725a074c0cb4afde07ef32c542e69f17ac90bc",
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"Id": "Policy1611769532425",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt1611769527792",
|
||||
"Action": ["sqs:SendMessage"],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:sqs:eu-west-3:047081014315:foo",
|
||||
"Principal": "*"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = "3.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "foo" {
|
||||
name = "foo"
|
||||
policy = file("policy.json")
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "bar" {
|
||||
name = "bar.fifo"
|
||||
fifo_queue = true
|
||||
content_based_deduplication = true
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue" "baz" {
|
||||
name = "baz"
|
||||
}
|
||||
|
||||
resource "aws_sqs_queue_policy" "sqs-policy" {
|
||||
queue_url = aws_sqs_queue.baz.id
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Id": "MYSQSPOLICY",
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt1611769527792",
|
||||
"Action": ["sqs:SendMessage"],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:sqs:eu-west-3:047081014315:baz",
|
||||
"Principal": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
Loading…
Reference in New Issue