providers/aws/iam.go (374 lines of code) (raw):

// Copyright 2018 The Terraformer Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aws import ( "context" "fmt" "log" "strings" "github.com/GoogleCloudPlatform/terraformer/terraformutils" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/iam/types" ) var IamAllowEmptyValues = []string{"tags."} var IamAdditionalFields = map[string]interface{}{} type IamGenerator struct { AWSService } func (g *IamGenerator) InitResources() error { config, e := g.generateConfig() if e != nil { return e } svc := iam.NewFromConfig(config) g.Resources = []terraformutils.Resource{} err := g.getUsers(svc) if err != nil { log.Println(err) } err = g.getGroups(svc) if err != nil { log.Println(err) } err = g.getPolicies(svc) if err != nil { log.Println(err) } err = g.getRoles(svc) if err != nil { log.Println(err) } err = g.getInstanceProfiles(svc) if err != nil { log.Println(err) } return nil } func (g *IamGenerator) getRoles(svc *iam.Client) error { p := iam.NewListRolesPaginator(svc, &iam.ListRolesInput{}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, role := range page.Roles { roleName := StringValue(role.RoleName) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( roleName, roleName, "aws_iam_role", "aws", IamAllowEmptyValues)) rolePoliciesPage := iam.NewListRolePoliciesPaginator(svc, &iam.ListRolePoliciesInput{RoleName: role.RoleName}) for rolePoliciesPage.HasMorePages() { rolePoliciesNextPage, err := rolePoliciesPage.NextPage(context.TODO()) if err != nil { log.Println(err) continue } for _, policyName := range rolePoliciesNextPage.PolicyNames { g.Resources = append(g.Resources, terraformutils.NewSimpleResource( roleName+":"+policyName, roleName+"_"+policyName, "aws_iam_role_policy", "aws", IamAllowEmptyValues)) } } roleAttachedPoliciesPage := iam.NewListAttachedRolePoliciesPaginator(svc, &iam.ListAttachedRolePoliciesInput{ RoleName: &roleName, }) for roleAttachedPoliciesPage.HasMorePages() { roleAttachedPoliciesNextPage, err := roleAttachedPoliciesPage.NextPage(context.TODO()) if err != nil { log.Println(err) continue } for _, attachedPolicy := range roleAttachedPoliciesNextPage.AttachedPolicies { g.Resources = append(g.Resources, terraformutils.NewResource( roleName+"/"+*attachedPolicy.PolicyArn, roleName+"_"+*attachedPolicy.PolicyName, "aws_iam_role_policy_attachment", "aws", map[string]string{ "role": roleName, "policy_arn": *attachedPolicy.PolicyArn, }, IamAllowEmptyValues, map[string]interface{}{})) } } } } return nil } func (g *IamGenerator) getUsers(svc *iam.Client) error { p := iam.NewListUsersPaginator(svc, &iam.ListUsersInput{}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, user := range page.Users { resourceName := StringValue(user.UserName) g.Resources = append(g.Resources, terraformutils.NewResource( resourceName, StringValue(user.UserId), "aws_iam_user", "aws", map[string]string{ "force_destroy": "false", }, IamAllowEmptyValues, map[string]interface{}{})) err := g.getUserPolices(svc, user.UserName) if err != nil { log.Println(err) } err = g.getUserPolicyAttachment(svc, user.UserName) if err != nil { log.Println(err) } err = g.getUserGroup(svc, user.UserName) if err != nil { log.Println(err) } err = g.getUserAccessKey(svc, user.UserName, StringValue(user.UserId)) if err != nil { log.Println(err) } } } return nil } func (g *IamGenerator) getUserGroup(svc *iam.Client, userName *string) error { p := iam.NewListGroupsForUserPaginator(svc, &iam.ListGroupsForUserInput{UserName: userName}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, group := range page.Groups { userGroupMembership := *userName + "/" + *group.GroupName g.Resources = append(g.Resources, terraformutils.NewResource( userGroupMembership, userGroupMembership, "aws_iam_user_group_membership", "aws", map[string]string{ "user": *userName, "groups.#": "1", "groups.0": *group.GroupName, }, IamAllowEmptyValues, IamAdditionalFields, )) } } return nil } func (g *IamGenerator) getUserPolices(svc *iam.Client, userName *string) error { p := iam.NewListUserPoliciesPaginator(svc, &iam.ListUserPoliciesInput{UserName: userName}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, policy := range page.PolicyNames { resourceName := StringValue(userName) + "_" + policy resourceName = strings.ReplaceAll(resourceName, "@", "") policyID := StringValue(userName) + ":" + policy g.Resources = append(g.Resources, terraformutils.NewSimpleResource( policyID, resourceName, "aws_iam_user_policy", "aws", IamAllowEmptyValues)) } } return nil } func (g *IamGenerator) getUserPolicyAttachment(svc *iam.Client, userName *string) error { p := iam.NewListAttachedUserPoliciesPaginator(svc, &iam.ListAttachedUserPoliciesInput{ UserName: userName, }) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, attachedPolicy := range page.AttachedPolicies { g.Resources = append(g.Resources, terraformutils.NewResource( *userName+"/"+*attachedPolicy.PolicyArn, *userName+"_"+*attachedPolicy.PolicyName, "aws_iam_user_policy_attachment", "aws", map[string]string{ "user": *userName, "policy_arn": *attachedPolicy.PolicyArn, }, IamAllowEmptyValues, map[string]interface{}{})) } } return nil } func (g *IamGenerator) getPolicies(svc *iam.Client) error { p := iam.NewListPoliciesPaginator(svc, &iam.ListPoliciesInput{Scope: types.PolicyScopeTypeLocal}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, policy := range page.Policies { resourceName := StringValue(policy.PolicyName) policyARN := StringValue(policy.Arn) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( policyARN, resourceName, "aws_iam_policy", "aws", IamAllowEmptyValues)) } } return nil } func (g *IamGenerator) getGroups(svc *iam.Client) error { p := iam.NewListGroupsPaginator(svc, &iam.ListGroupsInput{}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, group := range page.Groups { resourceName := StringValue(group.GroupName) g.Resources = append(g.Resources, terraformutils.NewSimpleResource( resourceName, resourceName, "aws_iam_group", "aws", IamAllowEmptyValues)) g.getGroupPolicies(svc, group) g.getAttachedGroupPolicies(svc, group) } } return nil } func (g *IamGenerator) getGroupPolicies(svc *iam.Client, group types.Group) { groupPoliciesPage := iam.NewListGroupPoliciesPaginator(svc, &iam.ListGroupPoliciesInput{GroupName: group.GroupName}) for groupPoliciesPage.HasMorePages() { groupPoliciesNextPage, err := groupPoliciesPage.NextPage(context.TODO()) if err != nil { log.Println(err) continue } for _, policy := range groupPoliciesNextPage.PolicyNames { id := *group.GroupName + ":" + policy groupPolicyName := *group.GroupName + "_" + policy g.Resources = append(g.Resources, terraformutils.NewResource( id, groupPolicyName, "aws_iam_group_policy", "aws", map[string]string{}, IamAllowEmptyValues, IamAdditionalFields)) } } } func (g *IamGenerator) getAttachedGroupPolicies(svc *iam.Client, group types.Group) { groupAttachedPoliciesPage := iam.NewListAttachedGroupPoliciesPaginator(svc, &iam.ListAttachedGroupPoliciesInput{GroupName: group.GroupName}) for groupAttachedPoliciesPage.HasMorePages() { groupAttachedPoliciesNextPage, err := groupAttachedPoliciesPage.NextPage(context.TODO()) if err != nil { log.Println(err) continue } for _, attachedPolicy := range groupAttachedPoliciesNextPage.AttachedPolicies { if !strings.Contains(*attachedPolicy.PolicyArn, "arn:aws:iam::aws") { continue // map only AWS managed policies since others should be managed by } id := *group.GroupName + "/" + *attachedPolicy.PolicyArn g.Resources = append(g.Resources, terraformutils.NewResource( id, *group.GroupName+"_"+*attachedPolicy.PolicyName, "aws_iam_group_policy_attachment", "aws", map[string]string{ "group": *group.GroupName, "policy_arn": *attachedPolicy.PolicyArn, }, IamAllowEmptyValues, IamAdditionalFields)) } } } func (g *IamGenerator) getInstanceProfiles(svc *iam.Client) error { p := iam.NewListInstanceProfilesPaginator(svc, &iam.ListInstanceProfilesInput{}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, instanceProfile := range page.InstanceProfiles { resourceName := *instanceProfile.InstanceProfileName g.Resources = append(g.Resources, terraformutils.NewResource( resourceName, resourceName, "aws_iam_instance_profile", "aws", map[string]string{ "name": resourceName, }, IamAllowEmptyValues, IamAdditionalFields)) } } return nil } func (g *IamGenerator) getUserAccessKey(svc *iam.Client, userName *string, userID string) error { p := iam.NewListAccessKeysPaginator(svc, &iam.ListAccessKeysInput{UserName: userName}) for p.HasMorePages() { page, err := p.NextPage(context.TODO()) if err != nil { return err } for _, key := range page.AccessKeyMetadata { accessKeyID := StringValue(key.AccessKeyId) g.Resources = append(g.Resources, terraformutils.NewResource( accessKeyID, accessKeyID, "aws_iam_access_key", "aws", map[string]string{ "user": *userName, }, IamAllowEmptyValues, map[string]interface{}{ "depends_on": []string{"aws_iam_user.tfer--" + userID}, })) } } return nil } // PostGenerateHook for add policy json as heredoc func (g *IamGenerator) PostConvertHook() error { for i, resource := range g.Resources { switch { case resource.InstanceInfo.Type == "aws_iam_policy" || resource.InstanceInfo.Type == "aws_iam_user_policy" || resource.InstanceInfo.Type == "aws_iam_group_policy" || resource.InstanceInfo.Type == "aws_iam_role_policy": policy := g.escapeAwsInterpolation(resource.Item["policy"].(string)) resource.Item["policy"] = fmt.Sprintf(`<<POLICY %s POLICY`, policy) case resource.InstanceInfo.Type == "aws_iam_role": policy := g.escapeAwsInterpolation(resource.Item["assume_role_policy"].(string)) g.Resources[i].Item["assume_role_policy"] = fmt.Sprintf(`<<POLICY %s POLICY`, policy) case resource.InstanceInfo.Type == "aws_iam_instance_profile": delete(resource.Item, "roles") } } return nil }