Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle inline and attached policies for iam_user resource #100

Merged
merged 3 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions command/wipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ package command
import (
"encoding/json"
"fmt"
"os"
"sort"
"strings"

"github.com/aws/aws-sdk-go/service/iam"
"github.com/fatih/color"
"github.com/zclconf/go-cty/cty"

"github.com/apex/log"
"github.com/cloudetc/awsweeper/resource"
awsls "github.com/jckuester/awsls/aws"
Expand Down Expand Up @@ -52,6 +57,18 @@ func List(filter *resource.Filter, client *resource.AWS, awsClient *awsls.Client
filteredRes := filter.Apply(rType, resourcesWithStates, nil, client)
print(filteredRes, outputType)

switch rType {
case "aws_iam_user":
policyAttachments := getAttachedUserPolicies(filteredRes, client, provider)
print(policyAttachments, outputType)

inlinePolicies := getInlineUserPolicies(filteredRes, client, provider)
print(inlinePolicies, outputType)

filteredRes = append(filteredRes, policyAttachments...)
filteredRes = append(filteredRes, inlinePolicies...)
}

for _, r := range filteredRes {
destroyableRes = append(destroyableRes, r.Resource)
}
Expand All @@ -61,6 +78,78 @@ func List(filter *resource.Filter, client *resource.AWS, awsClient *awsls.Client
return destroyableRes
}

func getAttachedUserPolicies(users []awsls.Resource, client *resource.AWS,
provider *provider.TerraformProvider) []awsls.Resource {
var result []awsls.Resource

for _, user := range users {
attachedPolicies, err := client.ListAttachedUserPolicies(&iam.ListAttachedUserPoliciesInput{
UserName: &user.ID,
})
if err != nil {
fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
continue
}

for _, attachedPolicy := range attachedPolicies.AttachedPolicies {
r := awsls.Resource{
Type: "aws_iam_user_policy_attachment",
ID: *attachedPolicy.PolicyArn,
}

r.Resource = terradozerRes.New(r.Type, r.ID, map[string]cty.Value{
"user": cty.StringVal(user.ID),
"policy_arn": cty.StringVal(*attachedPolicy.PolicyArn),
}, provider)

err = r.UpdateState()
if err != nil {
fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
continue
}

result = append(result, r)
}
}

return result
}

func getInlineUserPolicies(users []awsls.Resource, client *resource.AWS,
provider *provider.TerraformProvider) []awsls.Resource {
var result []awsls.Resource

for _, user := range users {
inlinePolicies, err := client.ListUserPolicies(&iam.ListUserPoliciesInput{
UserName: &user.ID,
})
if err != nil {
fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
continue
}

for _, inlinePolicy := range inlinePolicies.PolicyNames {
r := awsls.Resource{
Type: "aws_iam_user_policy",
ID: user.ID + ":" + *inlinePolicy,
}

r.Resource = terradozerRes.New(r.Type, r.ID, nil, provider)

err = r.UpdateState()
if err != nil {
fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err))
continue
}

result = append(result, r)
}

}

return result
}

func print(res []awsls.Resource, outputType string) {
if len(res) == 0 {
return
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ 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-20200516153042-96ea638daeb5
github.com/jckuester/terradozer v0.0.0-20200505071321-36ef87ab4394
github.com/jckuester/awsls v0.0.0-20200523195606-04f54b8ca1c6
github.com/jckuester/terradozer v0.0.0-20200523195146-e66de6fa55f3
github.com/onsi/gomega v1.9.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.5.1
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ github.com/aws/aws-sdk-go v1.30.5 h1:i+sSesaMrSxiUt3NJddOApe2mXK+VNBgfcmRTvNFrXM
github.com/aws/aws-sdk-go v1.30.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go-v2 v0.20.0 h1:/yefUjgMrda9PNFwWctBU63nL10CJMdBwkAmaQ4w4Hs=
github.com/aws/aws-sdk-go-v2 v0.20.0/go.mod h1:2LhT7UgHOXK3UXONKI5OMgIyoQL6zTAw/jwIeX6yqzw=
github.com/aws/aws-sdk-go-v2 v0.22.0 h1:mlixfS5HVzn7Sf3KVhjAIM2H3bB7uoTbLCtKHvteUfE=
github.com/aws/aws-sdk-go-v2 v0.22.0/go.mod h1:2LhT7UgHOXK3UXONKI5OMgIyoQL6zTAw/jwIeX6yqzw=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
Expand Down Expand Up @@ -347,8 +349,16 @@ github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jckuester/awsls v0.0.0-20200516153042-96ea638daeb5 h1:V8YuMycWi094/mWHmVIqbcFVH7L5o8LrgJgAi56yIA8=
github.com/jckuester/awsls v0.0.0-20200516153042-96ea638daeb5/go.mod h1:6dqF/j6Ar6b10DmHSV0CRYgKP2jwN8VUsHoFT3szFfA=
github.com/jckuester/awsls v0.0.0-20200523105025-fe25c60a9fba h1:fbk5OV5nnwtkElugQcUTur/B0M4NceHTp4Mr0qAbJvA=
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/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=
github.com/jckuester/terradozer v0.0.0-20200522202131-ed33ac929141/go.mod h1:fc32wbKuGQHf17dmggX1O51swhUUEr344xb173I6mSA=
github.com/jckuester/terradozer v0.0.0-20200523195146-e66de6fa55f3 h1:uba9ja+voKyereVEuM7YI6kDQO0W1890W+Y5MBWutI8=
github.com/jckuester/terradozer v0.0.0-20200523195146-e66de6fa55f3/go.mod h1:KYrRcPbIiXgcRp7hG9fOBdAyvDnUx2aA9cjTqvKa4cI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
Expand Down
47 changes: 1 addition & 46 deletions resource/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ func (f Filter) Apply(resType string, res []awsls.Resource, raw interface{}, aws
switch resType {
case EfsFileSystem:
return f.efsFileSystemFilter(res, raw, aws)
case IamUser:
return f.iamUserFilter(res, aws)
case IamPolicy:
case "aws_iam_policy":
return f.iamPolicyFilter(res, raw, aws)
case KmsKey:
return f.kmsKeysFilter(res, aws)
Expand Down Expand Up @@ -120,49 +118,6 @@ func (f Filter) efsFileSystemFilter(res []awsls.Resource, raw interface{}, c *AW
return result
}

func (f Filter) iamUserFilter(res []awsls.Resource, c *AWS) []awsls.Resource {
var result []awsls.Resource

for _, r := range res {
if f.Match(r) {
// list inline policies, delete with "aws_iam_user_policy" delete routine
ups, err := c.ListUserPolicies(&iam.ListUserPoliciesInput{
UserName: &r.ID,
})
if err == nil {
for _, up := range ups.PolicyNames {
result = append(result, awsls.Resource{
Type: "aws_iam_user_policy",
ID: r.ID + ":" + *up,
})
}
}

// Lists all managed policies that are attached to user (inline and others)
upols, err := c.ListAttachedUserPolicies(&iam.ListAttachedUserPoliciesInput{
UserName: &r.ID,
})
if err == nil {
for _, upol := range upols.AttachedPolicies {
result = append(result, awsls.Resource{
Type: "aws_iam_user_policy_attachment",
ID: *upol.PolicyArn,
/*
Attrs: map[string]string{
"user": r.ID,
"policy_arn": *upol.PolicyArn,
},
*/
})
}
}

result = append(result, r)
}
}
return result
}

func (f Filter) iamPolicyFilter(res []awsls.Resource, raw interface{}, c *AWS) []awsls.Resource {
var result []awsls.Resource

Expand Down
28 changes: 2 additions & 26 deletions resource/supported.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ const (
EbsSnapshot = "aws_ebs_snapshot"
EcsCluster = "aws_ecs_cluster"
EfsFileSystem = "aws_efs_file_system"
IamPolicy = "aws_iam_policy"
IamUser = "aws_iam_user"
Instance = "aws_instance"
KmsAlias = "aws_kms_alias"
KmsKey = "aws_kms_key"
Expand All @@ -60,8 +58,6 @@ var (
// Note: to import a cluster, the name is used as ID
EcsCluster: "ClusterArn",
EfsFileSystem: "FileSystemId",
IamPolicy: "Arn",
IamUser: "UserName",
Instance: "InstanceId",
KmsAlias: "AliasName",
KmsKey: "KeyId",
Expand Down Expand Up @@ -93,9 +89,9 @@ var (
"aws_network_acl": 9840,
"aws_vpc": 9830,
"aws_db_instance": 9825,
IamPolicy: 9820,
"aws_iam_policy": 9820,
"aws_iam_group": 9810,
IamUser: 9800,
"aws_iam_user": 9800,
"aws_iam_role": 9790,
"aws_iam_instance_profile": 9780,
"aws_s3_bucket": 9750,
Expand Down Expand Up @@ -195,10 +191,6 @@ func (a *AWS) RawResources(resType string) (interface{}, error) {
return a.ecsClusters()
case EfsFileSystem:
return a.efsFileSystems()
case IamPolicy:
return a.iamPolicies()
case IamUser:
return a.iamUsers()
case Instance:
return a.instances()
case KmsAlias:
Expand Down Expand Up @@ -280,22 +272,6 @@ func (a *AWS) efsFileSystems() (interface{}, error) {
return output.FileSystems, nil
}

func (a *AWS) iamPolicies() (interface{}, error) {
output, err := a.ListPolicies(&iam.ListPoliciesInput{})
if err != nil {
return nil, err
}
return output.Policies, nil
}

func (a *AWS) iamUsers() (interface{}, error) {
output, err := a.ListUsers(&iam.ListUsersInput{})
if err != nil {
return nil, err
}
return output.Users, nil
}

func (a *AWS) KmsAliases() (interface{}, error) {
output, err := a.KMSAPI.ListAliases(&kms.ListAliasesInput{})
if err != nil {
Expand Down
101 changes: 101 additions & 0 deletions test/iam_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package test

import (
"fmt"
"os"
"testing"

"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"

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

func TestAcc_IamUser_DeleteByID(t *testing.T) {
if testing.Short() {
t.Skip("Skipping acceptance test.")
}

env := InitEnv(t)

terraformDir := "./test-fixtures/iam-user"

terraformOptions := getTerraformOptions(terraformDir, env)

defer terraform.Destroy(t, terraformOptions)

terraform.InitAndApply(t, terraformOptions)

id := terraform.Output(t, terraformOptions, "id")
assertIamUserExists(t, env, id)

writeConfigID(t, terraformDir, "aws_iam_user", id)
defer os.Remove(terraformDir + "/config.yml")

logBuffer, err := runBinary(t, terraformDir, "YES\n")
require.NoError(t, err)

assertIamUserDeleted(t, env, id)

fmt.Println(logBuffer)
}

func TestAcc_IamUser_DeleteByTag(t *testing.T) {
if testing.Short() {
t.Skip("Skipping acceptance test.")
}

env := InitEnv(t)

terraformDir := "./test-fixtures/iam-user"

terraformOptions := getTerraformOptions(terraformDir, env)

defer terraform.Destroy(t, terraformOptions)

terraform.InitAndApply(t, terraformOptions)

id := terraform.Output(t, terraformOptions, "id")
assertIamUserExists(t, env, id)

writeConfigTag(t, terraformDir, "aws_iam_user")
defer os.Remove(terraformDir + "/config.yml")

logBuffer, err := runBinary(t, terraformDir, "YES\n")
require.NoError(t, err)

assertIamUserDeleted(t, env, id)

fmt.Println(logBuffer)
}

func assertIamUserExists(t *testing.T, env EnvVars, id string) {
assert.True(t, iamUserExists(t, env, id))
}

func assertIamUserDeleted(t *testing.T, env EnvVars, id string) {
assert.False(t, iamUserExists(t, env, id))
}

func iamUserExists(t *testing.T, env EnvVars, id string) bool {
opts := &iam.GetUserInput{
UserName: &id,
}

_, err := env.AWSClient.GetUser(opts)
if err != nil {
ec2err, ok := err.(awserr.Error)
if !ok {
t.Fatal()
}
if ec2err.Code() == "NoSuchEntity" {
return false
}
t.Fatal()
}

return true
}
18 changes: 0 additions & 18 deletions test/test-fixtures/dependent-resources/main.tf

This file was deleted.

Loading