feat: implement aws_iam_role_defaults middleware

main
sundowndev 2021-03-29 18:29:30 +02:00
parent 2ca48d4e65
commit f2ff032b85
5 changed files with 222 additions and 27 deletions

View File

@ -53,7 +53,8 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
middlewares.NewAwsSqsQueuePolicyExpander(d.resourceFactory),
middlewares.NewAwsDefaultSqsQueuePolicy(),
middlewares.NewAwsSNSTopicPolicyExpander(d.resourceFactory),
middlewares.NewAwsDefaultIamRolePolicy(),
middlewares.NewAwsIamRolePolicyDefaults(),
middlewares.NewAwsIamRoleDefaults(),
)
logrus.Debug("Ready to run middlewares")

View File

@ -0,0 +1,55 @@
package middlewares
import (
"github.com/sirupsen/logrus"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
)
// When scanning a brand new AWS account, some users may see irrelevant results about default AWS role policies.
// We ignore these resources by default when strict mode is disabled.
type AwsIamRoleDefaults struct{}
var ignoredIamRoleIds = []string{
"AWSServiceRoleForSSO",
"OrganizationAccountAccessRole",
}
func NewAwsIamRoleDefaults() AwsIamRoleDefaults {
return AwsIamRoleDefaults{}
}
func (m AwsIamRoleDefaults) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
for _, remoteResource := range *remoteResources {
// Ignore all resources other than role policy
if remoteResource.TerraformType() != aws.AwsIamRoleResourceType {
continue
}
existInState := false
for _, stateResource := range *resourcesFromState {
if resource.IsSameResource(remoteResource, stateResource) {
existInState = true
break
}
}
if existInState {
continue
}
for _, id := range ignoredIamRoleIds {
if remoteResource.TerraformId() == id {
*resourcesFromState = append(*resourcesFromState, remoteResource)
logrus.WithFields(logrus.Fields{
"id": remoteResource.TerraformId(),
"type": remoteResource.TerraformType(),
}).Debug("Ignoring default iam role as it is not managed by IaC")
}
}
}
return nil
}

View File

@ -0,0 +1,118 @@
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 TestAwsIamRoleDefaults_Execute(t *testing.T) {
tests := []struct {
name string
remoteResources []resource.Resource
resourcesFromState []resource.Resource
expected []resource.Resource
}{
{
"ignore default iam roles when they're managed by IaC",
[]resource.Resource{
&aws.AwsIamRole{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
[]resource.Resource{
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
[]resource.Resource{
&aws.AwsIamRole{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
},
{
"iam roles when they're managed by IaC",
[]resource.Resource{
&aws.AwsIamRole{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRole{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
[]resource.Resource{
&aws.AwsIamRole{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRole{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
[]resource.Resource{
&aws.AwsIamRole{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRole{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
GatewayId: awssdk.String("local"),
},
},
},
}
differ, err := diff.NewDiffer(diff.SliceOrdering(true))
if err != nil {
t.Fatal(err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewAwsIamRoleDefaults()
err := m.Execute(&tt.remoteResources, &tt.resourcesFromState)
if err != nil {
t.Fatal(err)
}
changelog, err := differ.Diff(tt.expected, tt.remoteResources)
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))
}
}
})
}
}

View File

@ -1,32 +1,32 @@
package middlewares
import (
"github.com/sirupsen/logrus"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/sirupsen/logrus"
)
// Default subnet should not be shown as unmanaged as they are present by default
// This middleware ignores default subnet from unmanaged resources if they are not managed by IaC
type AwsDefaultIamRolePolicy struct{}
// When scanning a brand new AWS account, some users may see irrelevant results about default AWS role policies.
// We ignore these resources by default when strict mode is disabled.
type AwsIamRolePolicyDefaults struct{}
func NewAwsDefaultIamRolePolicy() AwsDefaultIamRolePolicy {
return AwsDefaultIamRolePolicy{}
var ignoredIamRolePolicyIds = []string{
"OrganizationAccountAccessRole:AdministratorAccess",
}
func (m AwsDefaultIamRolePolicy) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
newRemoteResources := make([]resource.Resource, 0)
func NewAwsIamRolePolicyDefaults() AwsIamRolePolicyDefaults {
return AwsIamRolePolicyDefaults{}
}
func (m AwsIamRolePolicyDefaults) Execute(remoteResources, resourcesFromState *[]resource.Resource) error {
for _, remoteResource := range *remoteResources {
existInState := false
// Ignore all resources other than default Subnet
// Ignore all resources other than role policy
if remoteResource.TerraformType() != aws.AwsIamRolePolicyResourceType {
newRemoteResources = append(newRemoteResources, remoteResource)
continue
}
existInState := false
for _, stateResource := range *resourcesFromState {
if resource.IsSameResource(remoteResource, stateResource) {
existInState = true
@ -35,17 +35,20 @@ func (m AwsDefaultIamRolePolicy) Execute(remoteResources, resourcesFromState *[]
}
if existInState {
newRemoteResources = append(newRemoteResources, remoteResource)
} else {
logrus.WithFields(logrus.Fields{
"id": remoteResource.TerraformId(),
"type": remoteResource.TerraformType(),
}).Debug("Ignoring default IAM policies as it is not managed by IaC")
continue
}
}
for _, id := range ignoredIamRolePolicyIds {
if remoteResource.TerraformId() == id {
*resourcesFromState = append(*resourcesFromState, remoteResource)
*remoteResources = newRemoteResources
logrus.WithFields(logrus.Fields{
"id": remoteResource.TerraformId(),
"type": remoteResource.TerraformType(),
}).Debug("Ignoring default iam role policy as it is not managed by IaC")
}
}
}
return nil
}

View File

@ -11,7 +11,7 @@ import (
"github.com/r3labs/diff/v2"
)
func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
func TestAwsIamRolePolicyDefaults_Execute(t *testing.T) {
tests := []struct {
name string
remoteResources []resource.Resource
@ -19,7 +19,7 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
expected []resource.Resource
}{
{
"default iam role policies when they're not ignored when managed by IaC",
"ignore default iam role policies when they're managed by IaC",
[]resource.Resource{
&aws.AwsIamRolePolicy{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
@ -38,6 +38,9 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
},
},
[]resource.Resource{
&aws.AwsIamRolePolicy{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
@ -46,11 +49,14 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
},
},
{
"default iam role policies when they're not ignored when managed by IaC",
"iam role policies when they're managed by IaC",
[]resource.Resource{
&aws.AwsIamRolePolicy{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRolePolicy{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
@ -61,6 +67,9 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
&aws.AwsIamRolePolicy{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRolePolicy{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
@ -71,6 +80,9 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
&aws.AwsIamRolePolicy{
Id: "OrganizationAccountAccessRole:AdministratorAccess",
},
&aws.AwsIamRolePolicy{
Id: "driftctl_assume_role:driftctl_policy.10",
},
&aws.AwsRoute{
Id: "dummy-route",
RouteTableId: awssdk.String("default-route-table"),
@ -79,14 +91,20 @@ func TestAwsDefaultIamRolePolicy_Execute(t *testing.T) {
},
},
}
differ, err := diff.NewDiffer(diff.SliceOrdering(true))
if err != nil {
t.Fatal(err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewAwsDefaultIamRolePolicy()
m := NewAwsIamRolePolicyDefaults()
err := m.Execute(&tt.remoteResources, &tt.resourcesFromState)
if err != nil {
t.Fatal(err)
}
changelog, err := diff.Diff(tt.expected, tt.remoteResources)
changelog, err := differ.Diff(tt.expected, tt.remoteResources)
if err != nil {
t.Fatal(err)
}