providers/gcp/iam.go (112 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 gcp import ( "context" "log" "regexp" admin "cloud.google.com/go/iam/admin/apiv1" "google.golang.org/api/cloudresourcemanager/v1" "google.golang.org/api/iterator" adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" "github.com/GoogleCloudPlatform/terraformer/terraformutils" ) var IamAllowEmptyValues = []string{"tags."} var IamAdditionalFields = map[string]interface{}{} type IamGenerator struct { GCPService } func (g IamGenerator) createServiceAccountResources(serviceAccountsIterator *admin.ServiceAccountIterator) []terraformutils.Resource { resources := []terraformutils.Resource{} re := regexp.MustCompile(`^[a-z]`) for { serviceAccount, err := serviceAccountsIterator.Next() if err == iterator.Done { break } if err != nil { log.Println("error with service account:", err) continue } if !re.MatchString(serviceAccount.Email) { log.Printf("skipping %s: service account email must start with [a-z]\n", serviceAccount.Name) continue } resources = append(resources, terraformutils.NewSimpleResource( serviceAccount.Name, serviceAccount.UniqueId, "google_service_account", g.ProviderName, IamAllowEmptyValues, )) } return resources } func (g *IamGenerator) createIamCustomRoleResources(rolesResponse *adminpb.ListRolesResponse, project string) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, role := range rolesResponse.Roles { if role.Deleted { // Note: no need to log that the resource has been deleted continue } resources = append(resources, terraformutils.NewResource( role.Name, role.Name, "google_project_iam_custom_role", g.ProviderName, map[string]string{ "role_id": role.Name, "project": project, }, IamAllowEmptyValues, map[string]interface{}{ "stage": role.Stage.String(), }, )) } return resources } func (g *IamGenerator) createIamMemberResources(policy *cloudresourcemanager.Policy, project string) []terraformutils.Resource { resources := []terraformutils.Resource{} for _, b := range policy.Bindings { for _, m := range b.Members { resources = append(resources, terraformutils.NewResource( b.Role+m, b.Role+m, "google_project_iam_member", g.ProviderName, map[string]string{ "role": b.Role, "project": project, "member": m, }, IamAllowEmptyValues, IamAdditionalFields, )) } } return resources } func (g *IamGenerator) InitResources() error { ctx := context.Background() projectID := g.GetArgs()["project"].(string) client, err := admin.NewIamClient(ctx) if err != nil { return err } serviceAccountsIterator := client.ListServiceAccounts(ctx, &adminpb.ListServiceAccountsRequest{Name: "projects/" + projectID}) rolesResponse, err := client.ListRoles(ctx, &adminpb.ListRolesRequest{Parent: "projects/" + projectID}) if err != nil { return err } cm, err := cloudresourcemanager.NewService(context.Background()) if err != nil { return err } rb := &cloudresourcemanager.GetIamPolicyRequest{} policyResponse, err := cm.Projects.GetIamPolicy(projectID, rb).Context(context.Background()).Do() if err != nil { return err } g.Resources = g.createServiceAccountResources(serviceAccountsIterator) g.Resources = append(g.Resources, g.createIamCustomRoleResources(rolesResponse, projectID)...) g.Resources = append(g.Resources, g.createIamMemberResources(policyResponse, projectID)...) return nil }