Skip to content

Commit

Permalink
Handle aws_iam_policy attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
jckuester committed May 24, 2020
1 parent e090a5d commit 28083ab
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 56 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img alt="AWSweeper" src="https://github.com/cloudetc/awsweeper/blob/master/img/logo.png" height="120" />
<img alt="AWSweeper" src="https://github.com/cloudetc/awsweeper/blob/master/img/logo.png" height="150" />
<h3 align="center">AWSweeper</h3>
<p align="center">A tool for cleaning your AWS account</p>
</p>
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
42 changes: 39 additions & 3 deletions pkg/resource/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
51 changes: 0 additions & 51 deletions pkg/resource/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down
72 changes: 72 additions & 0 deletions test/iam_policy_test.go
Original file line number Diff line number Diff line change
@@ -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
}
76 changes: 76 additions & 0 deletions test/test-fixtures/iam-policy/main.tf
Original file line number Diff line number Diff line change
@@ -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 = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF

tags = {
awsweeper = "test-acc"
}
}

resource "aws_iam_group" "test" {
name = "awsweeper-test-acc"
}

resource "aws_iam_policy" "test" {
name = "awsweeper-test-acc"
description = "A test policy"

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}

resource "aws_iam_policy_attachment" "test" {
name = "awsweeper-test-acc"
users = [aws_iam_user.test.name]
roles = [aws_iam_role.test.name]
groups = [aws_iam_group.test.name]
policy_arn = aws_iam_policy.test.arn
}
7 changes: 7 additions & 0 deletions test/test-fixtures/iam-policy/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
output "id" {
value = aws_iam_policy.test.id
}

output "arn" {
value = aws_iam_policy.test.arn
}
11 changes: 11 additions & 0 deletions test/test-fixtures/iam-policy/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "profile" {
description = "The named profile for the AWS account that will be deployed to"
}

variable "region" {
description = "The AWS region to deploy to"
}

variable "name" {
description = "The name of test"
}

0 comments on commit 28083ab

Please sign in to comment.