github.com/openshift/installer@v1.4.17/pkg/destroy/ibmcloud/iam.go (about) 1 package ibmcloud 2 3 import ( 4 "net/http" 5 "strings" 6 7 "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" 8 "github.com/pkg/errors" 9 ) 10 11 const iamAuthorizationTypeName = "iam authorization" 12 13 // listIAMAuthorizations lists IAM authorizations 14 func (o *ClusterUninstaller) listIAMAuthorizations() (cloudResources, error) { 15 o.Logger.Debugf("Listing IAM authorizations") 16 ctx, cancel := o.contextWithTimeout() 17 defer cancel() 18 19 options := o.iamPolicyManagementSvc.NewListPoliciesOptions(o.AccountID) 20 options.SetType("authorization") 21 resources, _, err := o.iamPolicyManagementSvc.ListPoliciesWithContext(ctx, options) 22 if err != nil { 23 return nil, errors.Wrapf(err, "Failed to list IAM authorizations") 24 } 25 26 result := []cloudResource{} 27 for _, policy := range resources.Policies { 28 if o.policyMatches(policy) { 29 result = append(result, cloudResource{ 30 key: *policy.ID, 31 name: *policy.ID, 32 status: *policy.State, 33 typeName: iamAuthorizationTypeName, 34 id: *policy.ID, 35 }) 36 } 37 } 38 39 return cloudResources{}.insert(result...), nil 40 } 41 42 // policyMatches returns true if the IAM Policy matches the one set up to allow 43 // the VPC service to read from the COS bucket containing the uploaded RHCOS image. 44 func (o *ClusterUninstaller) policyMatches(policy iampolicymanagementv1.PolicyTemplateMetaData) bool { 45 // Ideally we would match using the description field of the Policy type. However, 46 // this is not currently supported in the IBM Terraform Provider. An issue has 47 // been opened for this: https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2894 48 // Once implemented, this code can be updaed to check for a well-known 49 // description that includes the cluster's InfraID or something equivalent. 50 onlyOneSubject := len(policy.Subjects) == 1 51 subjectMatches := len(policy.Subjects[0].Attributes) == 3 && 52 *policy.Subjects[0].Attributes[0].Name == "accountId" && 53 *policy.Subjects[0].Attributes[0].Value == o.AccountID && 54 *policy.Subjects[0].Attributes[1].Name == "serviceName" && 55 *policy.Subjects[0].Attributes[1].Value == "is" && 56 *policy.Subjects[0].Attributes[2].Name == "resourceType" && 57 *policy.Subjects[0].Attributes[2].Value == "image" 58 59 onlyOneResource := len(policy.Resources) == 1 60 cosInstanceID, err := o.COSInstanceID() 61 if err != nil { 62 o.Logger.Warn("Unable to determine IAM policy match. Failed to obtain COS instance ID. ", err) 63 return false 64 } 65 resourceMatches := len(policy.Resources[0].Attributes) == 3 && 66 *policy.Resources[0].Attributes[0].Name == "accountId" && 67 *policy.Resources[0].Attributes[0].Value == o.AccountID && 68 *policy.Resources[0].Attributes[1].Name == "serviceName" && 69 *policy.Resources[0].Attributes[1].Value == "cloud-object-storage" && 70 *policy.Resources[0].Attributes[2].Name == "serviceInstance" && 71 strings.Contains(cosInstanceID, *policy.Resources[0].Attributes[2].Value) && 72 *policy.Resources[0].Attributes[2].Operator == "stringEquals" 73 74 return onlyOneSubject && onlyOneResource && subjectMatches && resourceMatches 75 } 76 77 func (o *ClusterUninstaller) deleteIAMAuthorization(item cloudResource) error { 78 o.Logger.Debugf("Deleting IAM authorization %q", item.name) 79 ctx, cancel := o.contextWithTimeout() 80 defer cancel() 81 82 options := o.iamPolicyManagementSvc.NewDeletePolicyOptions(item.id) 83 details, err := o.iamPolicyManagementSvc.DeletePolicyWithContext(ctx, options) 84 85 if err != nil && details != nil && details.StatusCode == http.StatusNotFound { 86 // The resource is gone 87 o.deletePendingItems(item.typeName, []cloudResource{item}) 88 o.Logger.Infof("Deleted IAM authorization %q", item.name) 89 return nil 90 } 91 92 if err != nil && details != nil && details.StatusCode != http.StatusNotFound { 93 return errors.Wrapf(err, "Failed to delete IAM authorization %s", item.name) 94 } 95 96 return nil 97 } 98 99 // destroyIAMAuthorizations removes all IAM authorization pertaining to the cluster ID. 100 func (o *ClusterUninstaller) destroyIAMAuthorizations() error { 101 found, err := o.listIAMAuthorizations() 102 if err != nil { 103 return err 104 } 105 106 items := o.insertPendingItems(iamAuthorizationTypeName, found.list()) 107 108 for _, item := range items { 109 if _, ok := found[item.key]; !ok { 110 // This item has finished deletion. 111 o.deletePendingItems(item.typeName, []cloudResource{item}) 112 o.Logger.Infof("Deleted IAM authorization %q", item.name) 113 continue 114 } 115 err = o.deleteIAMAuthorization(item) 116 if err != nil { 117 o.errorTracker.suppressWarning(item.key, err, o.Logger) 118 } 119 } 120 121 if items = o.getPendingItems(iamAuthorizationTypeName); len(items) > 0 { 122 return errors.Errorf("%d items pending", len(items)) 123 } 124 return nil 125 }