From 28083abdcf229aa502f19f45d186793bc9e65381 Mon Sep 17 00:00:00 2001
From: Jan-Christoph Kuester
Date: Sun, 24 May 2020 13:41:40 +0200
Subject: [PATCH] Handle aws_iam_policy attachments
---
README.md | 2 +-
go.mod | 2 +-
go.sum | 2 +
pkg/resource/list.go | 42 +++++++++++-
pkg/resource/select.go | 51 ---------------
test/iam_policy_test.go | 72 ++++++++++++++++++++
test/test-fixtures/iam-policy/main.tf | 76 ++++++++++++++++++++++
test/test-fixtures/iam-policy/outputs.tf | 7 ++
test/test-fixtures/iam-policy/variables.tf | 11 ++++
9 files changed, 209 insertions(+), 56 deletions(-)
create mode 100644 test/iam_policy_test.go
create mode 100644 test/test-fixtures/iam-policy/main.tf
create mode 100644 test/test-fixtures/iam-policy/outputs.tf
create mode 100644 test/test-fixtures/iam-policy/variables.tf
diff --git a/README.md b/README.md
index b98fc8331..d1a8d9ed9 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
AWSweeper
A tool for cleaning your AWS account
diff --git a/go.mod b/go.mod
index f558b1f10..5bbd0b389 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
github.com/golang/mock v1.4.0
github.com/gruntwork-io/terratest v0.24.2
github.com/hashicorp/terraform v0.12.24
- github.com/jckuester/awsls v0.0.0-20200523195606-04f54b8ca1c6
+ github.com/jckuester/awsls v0.0.0-20200524112109-93c2a4665746
github.com/jckuester/terradozer v0.0.0-20200523195146-e66de6fa55f3
github.com/onsi/gomega v1.9.0
github.com/pkg/errors v0.9.1
diff --git a/go.sum b/go.sum
index 814314fc1..194edf3b9 100644
--- a/go.sum
+++ b/go.sum
@@ -353,6 +353,8 @@ github.com/jckuester/awsls v0.0.0-20200523105025-fe25c60a9fba h1:fbk5OV5nnwtkElu
github.com/jckuester/awsls v0.0.0-20200523105025-fe25c60a9fba/go.mod h1:6dqF/j6Ar6b10DmHSV0CRYgKP2jwN8VUsHoFT3szFfA=
github.com/jckuester/awsls v0.0.0-20200523195606-04f54b8ca1c6 h1:Rbcyj5lTyRRE4QgkJVncOgLbn6ehT6Yp5SdjCprr6FA=
github.com/jckuester/awsls v0.0.0-20200523195606-04f54b8ca1c6/go.mod h1:hbj1nD8zXLBoZffzkV7WXUmMGarGPKkFeke90U9eehs=
+github.com/jckuester/awsls v0.0.0-20200524112109-93c2a4665746 h1:CCO3Lc/ofOzEwH5WIZpndhoixKwNQRNVPKczVT4IS9w=
+github.com/jckuester/awsls v0.0.0-20200524112109-93c2a4665746/go.mod h1:hbj1nD8zXLBoZffzkV7WXUmMGarGPKkFeke90U9eehs=
github.com/jckuester/terradozer v0.0.0-20200505071321-36ef87ab4394 h1:7LmuH4Cm81Qsi0trqbnOmZ75xemFDhmzin0OoNL7aM4=
github.com/jckuester/terradozer v0.0.0-20200505071321-36ef87ab4394/go.mod h1:KYrRcPbIiXgcRp7hG9fOBdAyvDnUx2aA9cjTqvKa4cI=
github.com/jckuester/terradozer v0.0.0-20200522202131-ed33ac929141 h1:BowqT+JEJsqjPRWcTH7EOEEJuJlhKoh80MKZouM3pkE=
diff --git a/pkg/resource/list.go b/pkg/resource/list.go
index 6af722989..b5459b3d5 100644
--- a/pkg/resource/list.go
+++ b/pkg/resource/list.go
@@ -57,14 +57,19 @@ func List(filter *Filter, client *AWS, awsClient *awsls.Client,
switch rType {
case "aws_iam_user":
- policyAttachments := getAttachedUserPolicies(filteredRes, client, provider)
- print(policyAttachments, outputType)
+ attachedPolicies := getAttachedUserPolicies(filteredRes, client, provider)
+ print(attachedPolicies, outputType)
inlinePolicies := getInlineUserPolicies(filteredRes, client, provider)
print(inlinePolicies, outputType)
- filteredRes = append(filteredRes, policyAttachments...)
+ filteredRes = append(filteredRes, attachedPolicies...)
filteredRes = append(filteredRes, inlinePolicies...)
+ case "aws_iam_policy":
+ policyAttachments := getPolicyAttachments(filteredRes, provider)
+ print(policyAttachments, outputType)
+
+ filteredRes = append(filteredRes, policyAttachments...)
}
for _, r := range filteredRes {
@@ -142,7 +147,38 @@ func getInlineUserPolicies(users []awsls.Resource, client *AWS,
result = append(result, r)
}
+ }
+
+ return result
+}
+
+func getPolicyAttachments(policies []awsls.Resource, provider *provider.TerraformProvider) []awsls.Resource {
+ var result []awsls.Resource
+
+ for _, policy := range policies {
+ arn, err := awslsRes.GetAttribute("arn", &policy)
+ if err != nil {
+ fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
+ continue
+ }
+
+ r := awsls.Resource{
+ Type: "aws_iam_policy_attachment",
+ // Note: ID is only set for pretty printing (could be also left empty)
+ ID: policy.ID,
+ }
+
+ r.Resource = terradozerRes.New(r.Type, r.ID, map[string]cty.Value{
+ "policy_arn": cty.StringVal(arn),
+ }, provider)
+
+ err = r.UpdateState()
+ if err != nil {
+ fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
+ continue
+ }
+ result = append(result, r)
}
return result
diff --git a/pkg/resource/select.go b/pkg/resource/select.go
index 418362b71..ee1d392db 100644
--- a/pkg/resource/select.go
+++ b/pkg/resource/select.go
@@ -7,7 +7,6 @@ import (
"github.com/apex/log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/efs"
- "github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/kms"
awsls "github.com/jckuester/awsls/aws"
"github.com/zclconf/go-cty/cty"
@@ -35,8 +34,6 @@ func (f Filter) Apply(resType string, res []awsls.Resource, raw interface{}, aws
switch resType {
case EfsFileSystem:
return f.efsFileSystemFilter(res, raw, aws)
- case "aws_iam_policy":
- return f.iamPolicyFilter(res, raw, aws)
case KmsKey:
return f.kmsKeysFilter(res, aws)
case KmsAlias:
@@ -118,54 +115,6 @@ func (f Filter) efsFileSystemFilter(res []awsls.Resource, raw interface{}, c *AW
return result
}
-func (f Filter) iamPolicyFilter(res []awsls.Resource, raw interface{}, c *AWS) []awsls.Resource {
- var result []awsls.Resource
-
- for _, r := range res {
- if f.Match(r) {
- es, err := c.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyInput{
- PolicyArn: &r.ID,
- })
- if err != nil {
- log.Fatal(err.Error())
- }
-
- var roles []string
- var users []string
- var groups []string
-
- for _, u := range es.PolicyUsers {
- users = append(users, *u.UserName)
- }
- for _, g := range es.PolicyGroups {
- groups = append(groups, *g.GroupName)
- }
- for _, r := range es.PolicyRoles {
- roles = append(roles, *r.RoleName)
- }
-
- result = append(result, awsls.Resource{
- Type: "aws_iam_policy_attachment",
- ID: "none",
- /*
- Attrs: map[string]string{
- "policy_arn": r.ID,
- "name": *raw.([]*iam.Policy)[i].PolicyName,
- "users": strings.Join(users, "."),
- "roles": strings.Join(roles, "."),
- "groups": strings.Join(groups, "."),
- },
-
- */
- })
- result = append(result, r)
- }
- }
- // policy attachments are not resources
- // what happens here, is that policy is detached from groups, users and roles
- return result
-}
-
func (f Filter) kmsKeysFilter(res []awsls.Resource, c *AWS) []awsls.Resource {
var result []awsls.Resource
diff --git a/test/iam_policy_test.go b/test/iam_policy_test.go
new file mode 100644
index 000000000..056c263ea
--- /dev/null
+++ b/test/iam_policy_test.go
@@ -0,0 +1,72 @@
+package test
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/aws/aws-sdk-go/aws/awserr"
+ "github.com/aws/aws-sdk-go/service/iam"
+ "github.com/gruntwork-io/terratest/modules/terraform"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAcc_IamPolicy_DeleteByID(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping acceptance test.")
+ }
+
+ env := InitEnv(t)
+
+ terraformDir := "./test-fixtures/iam-policy"
+
+ terraformOptions := getTerraformOptions(terraformDir, env)
+
+ defer terraform.Destroy(t, terraformOptions)
+
+ terraform.InitAndApply(t, terraformOptions)
+
+ arn := terraform.Output(t, terraformOptions, "arn")
+ assertIamPolicyExists(t, env, arn)
+
+ id := terraform.Output(t, terraformOptions, "id")
+ writeConfigID(t, terraformDir, "aws_iam_policy", id)
+
+ defer os.Remove(terraformDir + "/config.yml")
+
+ logBuffer, err := runBinary(t, terraformDir, "YES\n")
+ require.NoError(t, err)
+
+ assertIamPolicyDeleted(t, env, arn)
+
+ fmt.Println(logBuffer)
+}
+
+func assertIamPolicyExists(t *testing.T, env EnvVars, arn string) {
+ assert.True(t, iamPolicyExists(t, env, arn))
+}
+
+func assertIamPolicyDeleted(t *testing.T, env EnvVars, arn string) {
+ assert.False(t, iamPolicyExists(t, env, arn))
+}
+
+func iamPolicyExists(t *testing.T, env EnvVars, arn string) bool {
+ opts := &iam.GetPolicyInput{
+ PolicyArn: &arn,
+ }
+
+ _, err := env.AWSClient.IAMAPI.GetPolicy(opts)
+ if err != nil {
+ ec2err, ok := err.(awserr.Error)
+ if !ok {
+ t.Fatal()
+ }
+ if ec2err.Code() == "NoSuchEntity" {
+ return false
+ }
+ t.Fatal(err)
+ }
+
+ return true
+}
diff --git a/test/test-fixtures/iam-policy/main.tf b/test/test-fixtures/iam-policy/main.tf
new file mode 100644
index 000000000..50fb584ca
--- /dev/null
+++ b/test/test-fixtures/iam-policy/main.tf
@@ -0,0 +1,76 @@
+provider "aws" {
+ version = "~> 2.0"
+
+ profile = var.profile
+ region = var.region
+}
+
+terraform {
+ # The configuration for this backend will be filled in by Terragrunt
+ backend "s3" {
+ }
+}
+
+resource "aws_iam_user" "test" {
+ name = "awsweeper-test-acc"
+
+ tags = {
+ awsweeper = "test-acc"
+ }
+}
+
+resource "aws_iam_role" "test" {
+ name = "awsweeper-test-acc"
+
+ assume_role_policy = <