Skip to content

Commit

Permalink
Add aws_default_vpc support
Browse files Browse the repository at this point in the history
  • Loading branch information
Elie committed Dec 15, 2020
1 parent 4bf700f commit f8e97b3
Show file tree
Hide file tree
Showing 16 changed files with 343,915 additions and 1 deletion.
3 changes: 2 additions & 1 deletion doc/cmd/scan/supported_resources/aws.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,6 @@ As AWS documentation recommends, the below policy is granting only the permissio

## VPC

- [x] aws_default_vpc
- [x] aws_security_group
- [x] aws_security_group_rule
- [x] aws_security_group_rule
1 change: 1 addition & 0 deletions pkg/driftctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (d DriftCTL) Run() *analyser.Analysis {
middlewares.NewVPCSecurityGroupRuleSanitizer(),
middlewares.NewIamPolicyAttachmentSanitizer(),
middlewares.AwsInstanceEIP{},
middlewares.NewAwsDefaultVPC(),
)

logrus.Debug("Ready to run middlewares")
Expand Down
1 change: 1 addition & 0 deletions pkg/iac/deserializers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ func Deserializers() []deserializer.CTYDeserializer {
awsdeserializer.NewIamRolePolicyDeserializer(),
awsdeserializer.NewIamRolePolicyAttachmentDeserializer(),
awsdeserializer.NewVPCSecurityGroupRuleDeserializer(),
awsdeserializer.NewDefaultVPCDeserializer(),
}
}
53 changes: 53 additions & 0 deletions pkg/middlewares/aws_default_vpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package middlewares

import (
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
)

// Default VPC should not be shown as unmanaged as they are present by default
// This middleware ignores default VPC from unmanaged resources of they are not managed IaC
type AwsDefaultVPC struct{}

func NewAwsDefaultVPC() AwsDefaultVPC {
return AwsDefaultVPC{}
}

func (m AwsDefaultVPC) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {

newRemoteResources := make([]resource.Resource, 0)

for _, remoteResource := range *remoteResources {
existInState := false

// Ignore all resources other than default VPC
if remoteResource.TerraformType() != aws.AwsDefaultVpcResourceType {
newRemoteResources = append(newRemoteResources, remoteResource)
continue
}

for _, stateResource := range *resourcesFromState {
if resource.IsSameResource(remoteResource, stateResource) {
existInState = true
break
}
}

if existInState {
newRemoteResources = append(newRemoteResources, remoteResource)
}

if !existInState {
logrus.WithFields(logrus.Fields{
"id": remoteResource.TerraformId(),
"type": remoteResource.TerraformType(),
}).Debug("Ignoring default VPC as it is not managed by IaC")
}

}

*remoteResources = newRemoteResources

return nil
}
51 changes: 51 additions & 0 deletions pkg/middlewares/default_vpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package middlewares

import (
"testing"

"github.com/cloudskiff/driftctl/pkg/resource/aws"

"github.com/cloudskiff/driftctl/pkg/resource"
)

func TestAwsDefaultVPCShouldBeIgnored(t *testing.T) {
middleware := NewAwsDefaultVPC()
remoteResources := []resource.Resource{
&aws.AwsDefaultVpc{
Id: "foobar",
},
}
stateResources := []resource.Resource{}
err := middleware.Execute(&remoteResources, &stateResources)

if err != nil {
t.Error(err)
}

if len(remoteResources) != 0 {
t.Error("Default VPC was not ignored")
}
}

func TestAwsDefaultVPCShouldNotBeIgnoredWhenManaged(t *testing.T) {
middleware := NewAwsDefaultVPC()
remoteResources := []resource.Resource{
&aws.AwsDefaultVpc{
Id: "foobar",
},
}
stateResources := []resource.Resource{
&aws.AwsDefaultVpc{
Id: "foobar",
},
}
err := middleware.Execute(&remoteResources, &stateResources)

if err != nil {
t.Error(err)
}

if len(remoteResources) != 1 {
t.Error("Default VPC was ignored")
}
}
76 changes: 76 additions & 0 deletions pkg/remote/aws/default_vpc_supplier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package aws

import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/cloudskiff/driftctl/pkg"
"github.com/cloudskiff/driftctl/pkg/remote/deserializer"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"
"github.com/zclconf/go-cty/cty"

"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"

"github.com/sirupsen/logrus"
)

type DefaultVPCSupplier struct {
reader terraform.ResourceReader
deserializer deserializer.CTYDeserializer
client ec2iface.EC2API
runner *terraform.ParallelResourceReader
}

func NewDefaultVPCSupplier(runner *pkg.ParallelRunner, client ec2iface.EC2API) *DefaultVPCSupplier {
return &DefaultVPCSupplier{
terraform.Provider(terraform.AWS),
awsdeserializer.NewDefaultVPCDeserializer(),
client,
terraform.NewParallelResourceReader(runner),
}
}

func (s DefaultVPCSupplier) Resources() ([]resource.Resource, error) {
input := ec2.DescribeVpcsInput{}
var defaultVPCs []*ec2.Vpc
err := s.client.DescribeVpcsPages(&input,
func(resp *ec2.DescribeVpcsOutput, lastPage bool) bool {
for _, vpc := range resp.Vpcs {
if vpc.IsDefault != nil && *vpc.IsDefault {
defaultVPCs = append(defaultVPCs, vpc)
}
}
return !lastPage
},
)

if err != nil {
logrus.Error(err)
return nil, err
}

for _, item := range defaultVPCs {
res := *item
s.runner.Run(func() (cty.Value, error) {
return s.readDefaultVPC(res)
})
}
ctyValues, err := s.runner.Wait()
if err != nil {
return nil, err
}
return s.deserializer.Deserialize(ctyValues)
}

func (s DefaultVPCSupplier) readDefaultVPC(vpc ec2.Vpc) (cty.Value, error) {
val, err := s.reader.ReadResource(terraform.ReadResourceArgs{
ID: *vpc.VpcId,
Ty: aws.AwsDefaultVpcResourceType,
})
if err != nil {
logrus.Error(err)
return cty.NilVal, err
}
return *val, nil
}
98 changes: 98 additions & 0 deletions pkg/remote/aws/defaut_vpc_supplier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package aws

import (
"context"
"testing"

awsdeserializer "github.com/cloudskiff/driftctl/pkg/resource/aws/deserializer"

"github.com/aws/aws-sdk-go/service/ec2"

"github.com/aws/aws-sdk-go/aws"

"github.com/cloudskiff/driftctl/test/goldenfile"
mocks2 "github.com/cloudskiff/driftctl/test/mocks"
"github.com/stretchr/testify/mock"

"github.com/cloudskiff/driftctl/mocks"

"github.com/cloudskiff/driftctl/pkg"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/terraform"
"github.com/cloudskiff/driftctl/test"
)

func TestDefaultVPCSupplier_Resources(t *testing.T) {
cases := []struct {
test string
dirName string
mocks func(client *mocks.FakeEC2)
err error
}{
{
test: "no default VPC",
dirName: "default_vpc_empty",
mocks: func(client *mocks.FakeEC2) {
client.On("DescribeVpcsPages",
&ec2.DescribeVpcsInput{},
mock.MatchedBy(func(callback func(res *ec2.DescribeVpcsOutput, lastPage bool) bool) bool {
callback(&ec2.DescribeVpcsOutput{}, true)
return true
})).Return(nil)
},
err: nil,
},
{
test: "single default VPC",
dirName: "default_vpc",
mocks: func(client *mocks.FakeEC2) {
client.On("DescribeVpcsPages",
&ec2.DescribeVpcsInput{},
mock.MatchedBy(func(callback func(res *ec2.DescribeVpcsOutput, lastPage bool) bool) bool {
callback(&ec2.DescribeVpcsOutput{
Vpcs: []*ec2.Vpc{
{
VpcId: aws.String("vpc-a8c5d4c1"),
IsDefault: aws.Bool(true),
},
},
}, false)
return true
})).Return(nil)
},
err: nil,
},
}
for _, c := range cases {
shouldUpdate := c.dirName == *goldenfile.Update
if shouldUpdate {
provider, err := NewTerraFormProvider()
if err != nil {
t.Fatal(err)
}

terraform.AddProvider(terraform.AWS, provider)
resource.AddSupplier(NewDefaultVPCSupplier(provider.Runner(), ec2.New(provider.session)))
}

t.Run(c.test, func(tt *testing.T) {
fakeEC2 := mocks.FakeEC2{}
c.mocks(&fakeEC2)
provider := mocks2.NewMockedGoldenTFProvider(c.dirName, terraform.Provider(terraform.AWS), shouldUpdate)
deserializer := awsdeserializer.NewDefaultVPCDeserializer()
s := &DefaultVPCSupplier{
provider,
deserializer,
&fakeEC2,
terraform.NewParallelResourceReader(pkg.NewParallelRunner(context.TODO(), 10)),
}
got, err := s.Resources()
if c.err != err {
tt.Errorf("Expected error %+v got %+v", c.err, err)
}

mock.AssertExpectationsForObjects(tt)
test.CtyTestDiff(got, c.dirName, provider, deserializer, shouldUpdate, tt)
})
}
}
1 change: 1 addition & 0 deletions pkg/remote/aws/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func Init() error {
resource.AddSupplier(NewIamRolePolicySupplier(provider.Runner().SubRunner(), iam.New(provider.session)))
resource.AddSupplier(NewIamRolePolicyAttachmentSupplier(provider.Runner().SubRunner(), iam.New(provider.session)))
resource.AddSupplier(NewVPCSecurityGroupRuleSupplier(provider.Runner().SubRunner(), ec2.New(provider.session)))
resource.AddSupplier(NewDefaultVPCSupplier(provider.Runner().SubRunner(), ec2.New(provider.session)))

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiYXJuIjoic3RyaW5nIiwiYXNzaWduX2dlbmVyYXRlZF9pcHY2X2NpZHJfYmxvY2siOiJib29sIiwiY2lkcl9ibG9jayI6InN0cmluZyIsImRlZmF1bHRfbmV0d29ya19hY2xfaWQiOiJzdHJpbmciLCJkZWZhdWx0X3JvdXRlX3RhYmxlX2lkIjoic3RyaW5nIiwiZGVmYXVsdF9zZWN1cml0eV9ncm91cF9pZCI6InN0cmluZyIsImRoY3Bfb3B0aW9uc19pZCI6InN0cmluZyIsImVuYWJsZV9jbGFzc2ljbGluayI6ImJvb2wiLCJlbmFibGVfY2xhc3NpY2xpbmtfZG5zX3N1cHBvcnQiOiJib29sIiwiZW5hYmxlX2Ruc19ob3N0bmFtZXMiOiJib29sIiwiZW5hYmxlX2Ruc19zdXBwb3J0IjoiYm9vbCIsImlkIjoic3RyaW5nIiwiaW5zdGFuY2VfdGVuYW5jeSI6InN0cmluZyIsImlwdjZfYXNzb2NpYXRpb25faWQiOiJzdHJpbmciLCJpcHY2X2NpZHJfYmxvY2siOiJzdHJpbmciLCJtYWluX3JvdXRlX3RhYmxlX2lkIjoic3RyaW5nIiwib3duZXJfaWQiOiJzdHJpbmciLCJ0YWdzIjpbIm1hcCIsInN0cmluZyJdfV0=",
"Val": "eyJhcm4iOiJhcm46YXdzOmVjMjpldS13ZXN0LTM6OTI5MzI3MDY1MzMzOnZwYy92cGMtYThjNWQ0YzEiLCJhc3NpZ25fZ2VuZXJhdGVkX2lwdjZfY2lkcl9ibG9jayI6ZmFsc2UsImNpZHJfYmxvY2siOiIxNzIuMzEuMC4wLzE2IiwiZGVmYXVsdF9uZXR3b3JrX2FjbF9pZCI6ImFjbC0zZDQzNTk1NCIsImRlZmF1bHRfcm91dGVfdGFibGVfaWQiOiJydGItYjBiYTViZDgiLCJkZWZhdWx0X3NlY3VyaXR5X2dyb3VwX2lkIjoic2ctYTc0ODE1YzgiLCJkaGNwX29wdGlvbnNfaWQiOiJkb3B0LTliZWNmMmYyIiwiZW5hYmxlX2NsYXNzaWNsaW5rIjpudWxsLCJlbmFibGVfY2xhc3NpY2xpbmtfZG5zX3N1cHBvcnQiOm51bGwsImVuYWJsZV9kbnNfaG9zdG5hbWVzIjp0cnVlLCJlbmFibGVfZG5zX3N1cHBvcnQiOnRydWUsImlkIjoidnBjLWE4YzVkNGMxIiwiaW5zdGFuY2VfdGVuYW5jeSI6ImRlZmF1bHQiLCJpcHY2X2Fzc29jaWF0aW9uX2lkIjoiIiwiaXB2Nl9jaWRyX2Jsb2NrIjoiIiwibWFpbl9yb3V0ZV90YWJsZV9pZCI6InJ0Yi1iMGJhNWJkOCIsIm93bmVyX2lkIjoiOTI5MzI3MDY1MzMzIiwidGFncyI6e319",
"Err": null
}
22 changes: 22 additions & 0 deletions pkg/remote/aws/test/default_vpc/results.golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"arn": "arn:aws:ec2:eu-west-3:929327065333:vpc/vpc-a8c5d4c1",
"assign_generated_ipv6_cidr_block": false,
"cidr_block": "172.31.0.0/16",
"default_network_acl_id": "acl-3d435954",
"default_route_table_id": "rtb-b0ba5bd8",
"default_security_group_id": "sg-a74815c8",
"dhcp_options_id": "dopt-9becf2f2",
"enable_classiclink": null,
"enable_classiclink_dns_support": null,
"enable_dns_hostnames": true,
"enable_dns_support": true,
"id": "vpc-a8c5d4c1",
"instance_tenancy": "default",
"ipv6_association_id": "",
"ipv6_cidr_block": "",
"main_route_table_id": "rtb-b0ba5bd8",
"owner_id": "929327065333",
"tags": {}
}
]
Loading

0 comments on commit f8e97b3

Please sign in to comment.