providers/ibm/iam.go (326 lines of code) (raw):

// Copyright 2019 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 ibm import ( "fmt" "os" "strconv" "github.com/GoogleCloudPlatform/terraformer/terraformutils" bluemix "github.com/IBM-Cloud/bluemix-go" "github.com/IBM-Cloud/bluemix-go/api/iampap/iampapv1" "github.com/IBM-Cloud/bluemix-go/api/iamuum/iamuumv2" "github.com/IBM-Cloud/bluemix-go/api/usermanagement/usermanagementv2" "github.com/IBM-Cloud/bluemix-go/session" "github.com/IBM/go-sdk-core/core" "github.com/IBM/platform-services-go-sdk/iamidentityv1" "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" ) type IAMGenerator struct { IBMService } func (g IAMGenerator) loadUserPolicies(policyID string, user string) terraformutils.Resource { resources := terraformutils.NewSimpleResource( fmt.Sprintf("%s/%s", user, policyID), normalizeResourceName("iam_user_policy", true), "ibm_iam_user_policy", "ibm", []string{}) return resources } func (g IAMGenerator) loadAccessGroups() func(grpID, grpName string) terraformutils.Resource { names := make(map[string]struct{}) random := false return func(grpID, grpName string) terraformutils.Resource { names, random = getRandom(names, grpName, random) resources := terraformutils.NewSimpleResource( grpID, normalizeResourceName(grpName, random), "ibm_iam_access_group", "ibm", []string{}) return resources } } func (g IAMGenerator) loadServiceIDs() func(serviceID, grpName string) terraformutils.Resource { names := make(map[string]struct{}) random := false return func(grpID, grpName string) terraformutils.Resource { names, random = getRandom(names, grpName, random) resources := terraformutils.NewSimpleResource( grpID, normalizeResourceName(grpName, random), "ibm_iam_service_id", "ibm", []string{}) return resources } } func (g IAMGenerator) loadAuthPolicies(policyID string) terraformutils.Resource { resource := terraformutils.NewResource( policyID, normalizeResourceName("iam_authorization_policy", true), "ibm_iam_authorization_policy", "ibm", map[string]string{}, []string{}, map[string]interface{}{}) // Conflict parameters resource.IgnoreKeys = append(resource.IgnoreKeys, "^subject_attributes$", "^resource_attributes$", "^source_resource_instance_id$", "^target_resource_instance_id$", "^transaction_id$", ) return resource } func (g IAMGenerator) loadCustomRoles() func(roleID, roleName string) terraformutils.Resource { names := make(map[string]struct{}) random := false return func(roleID, roleName string) terraformutils.Resource { names, random = getRandom(names, roleName, random) resources := terraformutils.NewSimpleResource( roleID, normalizeResourceName(roleName, random), "ibm_iam_custom_role", "ibm", []string{}) return resources } } func (g IAMGenerator) loadServicePolicies(serviceID, policyID string, dependsOn []string) terraformutils.Resource { resources := terraformutils.NewResource( fmt.Sprintf("%s/%s", serviceID, policyID), normalizeResourceName("iam_service_policy", true), "ibm_iam_service_policy", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) return resources } func (g IAMGenerator) loadAccessGroupMembers() func(grpID string, dependsOn []string, grpName string) terraformutils.Resource { names := make(map[string]struct{}) random := false return func(grpID string, dependsOn []string, grpName string) terraformutils.Resource { names, random = getRandom(names, grpName, random) resources := terraformutils.NewResource( fmt.Sprintf("%s/%s", grpID, grpID), normalizeResourceName(grpName, random), "ibm_iam_access_group_members", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) return resources } } func (g IAMGenerator) loadAccessGroupPolicies(grpID, policyID string, dependsOn []string) terraformutils.Resource { resources := terraformutils.NewResource( fmt.Sprintf("%s/%s", grpID, policyID), normalizeResourceName("iam_access_group_policy", true), "ibm_iam_access_group_policy", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) return resources } func (g IAMGenerator) loadAccessGroupDynamicPolicies() func(grpID, ruleID, name string, dependsOn []string) terraformutils.Resource { names := make(map[string]struct{}) random := false return func(grpID, ruleID, name string, dependsOn []string) terraformutils.Resource { names, random = getRandom(names, name, random) resources := terraformutils.NewResource( fmt.Sprintf("%s/%s", grpID, ruleID), normalizeResourceName(name, random), "ibm_iam_access_group_dynamic_rule", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) return resources } } func (g *IAMGenerator) InitResources() error { bmxConfig := &bluemix.Config{ BluemixAPIKey: os.Getenv("IC_API_KEY"), } sess, err := session.New(bmxConfig) if err != nil { return err } userManagementAPI, err := usermanagementv2.New(sess) if err != nil { return err } err = authenticateAPIKey(sess) if err != nil { return err } generation := envFallBack([]string{"Generation"}, "2") gen, err := strconv.Atoi(generation) if err != nil { return err } userInfo, err := fetchUserDetails(sess, gen) if err != nil { return err } accountID := userInfo.userAccount users, err := userManagementAPI.UserInvite().GetUsers(userInfo.userAccount) if err != nil { return err } iampap, err := iampapv1.New(sess) if err != nil { return err } for _, u := range users.Resources { // User policies policies, err := iampap.V1Policy().List(iampapv1.SearchParams{ AccountID: accountID, IAMID: u.IamID, Type: iampapv1.AccessPolicyType, }) if err != nil { return err } for _, p := range policies { g.Resources = append(g.Resources, g.loadUserPolicies(p.ID, u.Email)) } } iamuumClient, err := iamuumv2.New(sess) if err != nil { return err } agrps, err := iamuumClient.AccessGroup().List(accountID) if err != nil { return err } fnObjt := g.loadAccessGroups() agmfnObj := g.loadAccessGroupMembers() for _, group := range agrps { g.Resources = append(g.Resources, fnObjt(group.ID, group.Name)) resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName var dependsOn []string dependsOn = append(dependsOn, "ibm_iam_access_group."+resourceName) g.Resources = append(g.Resources, agmfnObj(group.ID, dependsOn, group.Name)) policies, err := iampap.V1Policy().List(iampapv1.SearchParams{ AccountID: accountID, AccessGroupID: group.ID, Type: iampapv1.AccessPolicyType, }) if err != nil { return fmt.Errorf("error retrieving access group policy: %s", err) } for _, p := range policies { g.Resources = append(g.Resources, g.loadAccessGroupPolicies(group.ID, p.ID, dependsOn)) } dynamicPolicies, err := iamuumClient.DynamicRule().List(group.ID) if err != nil { return err } dpfnObj := g.loadAccessGroupDynamicPolicies() for _, d := range dynamicPolicies { g.Resources = append(g.Resources, dpfnObj(group.ID, d.RuleID, d.Name, dependsOn)) } } // service id and service policy apiKey := os.Getenv("IC_API_KEY") if apiKey == "" { return fmt.Errorf("no API key set") } iamIDurl := "https://iam.cloud.ibm.com" iamOptions := &iamidentityv1.IamIdentityV1Options{ URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamIDurl), Authenticator: &core.IamAuthenticator{ ApiKey: apiKey, }, } iamPolicyOptions := &iampolicymanagementv1.IamPolicyManagementV1Options{ URL: envFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamIDurl), Authenticator: &core.IamAuthenticator{ ApiKey: apiKey, }, } iamIDClient, err := iamidentityv1.NewIamIdentityV1(iamOptions) if err != nil { return err } iamPolicyClient, err := iampolicymanagementv1.NewIamPolicyManagementV1(iamPolicyOptions) if err != nil { return err } start := "" allrecs := []iamidentityv1.ServiceID{} var pg int64 = 100 for { listServiceIDOptions := iamidentityv1.ListServiceIdsOptions{ AccountID: &accountID, Pagesize: &pg, } if start != "" { listServiceIDOptions.Pagetoken = &start } serviceIDs, resp, err := iamIDClient.ListServiceIds(&listServiceIDOptions) if err != nil { return fmt.Errorf("[ERROR] Error listing Service Ids %s %s", err, resp) } start = GetNextIAM(serviceIDs.Next) allrecs = append(allrecs, serviceIDs.Serviceids...) if start == "" { break } } servicefnObjt := g.loadServiceIDs() // loop through all service IDs and fetch policies correspponds to each service ID for _, service := range allrecs { g.Resources = append(g.Resources, servicefnObjt(*service.ID, *service.Name)) resourceName := g.Resources[len(g.Resources)-1:][0].ResourceName var dependsOn []string dependsOn = append(dependsOn, "ibm_iam_service_id."+resourceName) listServicePolicyOptions := iampolicymanagementv1.ListPoliciesOptions{ AccountID: core.StringPtr(accountID), IamID: core.StringPtr(*service.IamID), Type: core.StringPtr("access"), } policyList, _, err := iamPolicyClient.ListPolicies(&listServicePolicyOptions) policies := policyList.Policies if err != nil { return fmt.Errorf("error retrieving service policy: %s", err) } for _, p := range policies { g.Resources = append(g.Resources, g.loadServicePolicies(*service.ID, *p.ID, dependsOn)) } } // Authorization policy listAuthPolicyOptions := iampolicymanagementv1.ListPoliciesOptions{ AccountID: core.StringPtr(accountID), Type: core.StringPtr("authorization"), } authPolicyList, _, err := iamPolicyClient.ListPolicies(&listAuthPolicyOptions) authPolicies := authPolicyList.Policies if err != nil { return fmt.Errorf("error retrieving authorization policy: %s", err) } for _, ap := range authPolicies { g.Resources = append(g.Resources, g.loadAuthPolicies(*ap.ID)) } // Custom role listCustomRoleOptions := iampolicymanagementv1.ListRolesOptions{ AccountID: core.StringPtr(accountID), } rolesList, _, err := iamPolicyClient.ListRoles(&listCustomRoleOptions) customRoles := rolesList.CustomRoles if err != nil { return fmt.Errorf("error retrieving custom roles: %s", err) } rolefnObjt := g.loadCustomRoles() for _, r := range customRoles { g.Resources = append(g.Resources, rolefnObjt(*r.ID, *r.Name)) } return nil }