Skip to content

Commit

Permalink
OCM-12806 | feat: Delete operator roles auto mode (and changes to acc…
Browse files Browse the repository at this point in the history
…ount roles)
  • Loading branch information
hunterkepley committed Nov 28, 2024
1 parent fb96dce commit 1ab99b6
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 39 deletions.
4 changes: 2 additions & 2 deletions cmd/create/accountroles/creators.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,7 @@ func (hcp *hcpManagedPoliciesCreator) printCommands(r *rosa.Runtime, input *acco
if isHcpInstallerRole && input.isSharedVpc { // HCP shared VPC (Installer role policies)
for _, arn := range []string{args.route53RoleArn, args.vpcEndpointRoleArn} {
// Shared VPC role arn (route53)
exists, createPolicyCommand, policyName, err := roles.GetHcpSharedVpcPolicyDetails(r, arn,
iamTags)
exists, createPolicyCommand, policyName, err := roles.GetHcpSharedVpcPolicyDetails(r, arn)
if err != nil {
return err
}
Expand Down Expand Up @@ -489,6 +488,7 @@ func attachHcpSharedVpcPolicy(r *rosa.Runtime, sharedVpcRoleArn string, roleName

policyTags := map[string]string{
tags.RedHatManaged: aws.TrueString,
tags.HcpSharedVpc: aws.TrueString,
}

userProvidedRoleName, err := aws.GetResourceIdFromARN(sharedVpcRoleArn)
Expand Down
6 changes: 2 additions & 4 deletions cmd/create/operatorroles/by_prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,7 @@ func buildCommandsFromPrefix(r *rosa.Runtime, env string,
// Precreate HCP shared VPC policies for less memory usage + time to execute
// Shared VPC role arn (route53)
var policyDetails = make(map[string]roles.ManualSharedVpcPolicyDetails)
exists, createPolicyCommand, policyName, err := roles.GetHcpSharedVpcPolicyDetails(r, sharedVpcRoleArn,
iamTags)
exists, createPolicyCommand, policyName, err := roles.GetHcpSharedVpcPolicyDetails(r, sharedVpcRoleArn)
if err != nil {
return "", err
}
Expand All @@ -541,8 +540,7 @@ func buildCommandsFromPrefix(r *rosa.Runtime, env string,
AlreadyExists: exists,
}
// VPC endpoint role arn
exists, createPolicyCommand, policyName, err = roles.GetHcpSharedVpcPolicyDetails(r, vpcEndpointRoleArn,
iamTags)
exists, createPolicyCommand, policyName, err = roles.GetHcpSharedVpcPolicyDetails(r, vpcEndpointRoleArn)
if err != nil {
return "", err
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/create/operatorroles/common_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@ func getHcpSharedVpcPolicy(r *rosa.Runtime, roleArn string, defaultPolicyVersion
return "", err
}

iamTags := map[string]string{
tags.RedHatManaged: helper.True,
tags.HcpSharedVpc: helper.True,
}

policyArn, err := r.AWSClient.EnsurePolicy(policy, interpolatedPolicyDetails, defaultPolicyVersion,
map[string]string{tags.RedHatManaged: helper.True}, path)
iamTags, path)
if err != nil {
return policyArn, err
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/dlt/accountroles/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/openshift/rosa/pkg/interactive"
"github.com/openshift/rosa/pkg/interactive/confirm"
"github.com/openshift/rosa/pkg/ocm"
"github.com/openshift/rosa/pkg/roles"
"github.com/openshift/rosa/pkg/rosa"
)

Expand Down Expand Up @@ -204,12 +205,16 @@ func deleteAccountRoles(r *rosa.Runtime, env string, prefix string, clusters []*
r.Reporter.Infof(fmt.Sprintf("Deleting %saccount roles", roleTypeString))

r.OCMClient.LogEvent("ROSADeleteAccountRoleModeAuto", nil)
deleteHcpSharedVpcPolicies := false
if roles.CheckIfRolesAreHcpSharedVpc(r, finalRoleList) {
deleteHcpSharedVpcPolicies = confirm.Prompt(true, "Attempt to delete Hosted CP shared VPC policies?")
}
for _, role := range finalRoleList {
if !confirm.Prompt(true, "Delete the account role '%s'?", role) {
continue
}
r.Reporter.Infof("Deleting account role '%s'", role)
err := r.AWSClient.DeleteAccountRole(role, prefix, managedPolicies)
err := r.AWSClient.DeleteAccountRole(role, prefix, managedPolicies, deleteHcpSharedVpcPolicies)
if err != nil {
r.Reporter.Warnf("There was an error deleting the account roles or policies: %s", err)
continue
Expand Down
20 changes: 19 additions & 1 deletion cmd/dlt/operatorrole/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/openshift/rosa/pkg/interactive"
"github.com/openshift/rosa/pkg/interactive/confirm"
"github.com/openshift/rosa/pkg/ocm"
"github.com/openshift/rosa/pkg/roles"
"github.com/openshift/rosa/pkg/rosa"
)

Expand Down Expand Up @@ -220,6 +221,13 @@ func run(cmd *cobra.Command, _ []string) {
switch mode {
case interactive.ModeAuto:
r.OCMClient.LogEvent("ROSADeleteOperatorroleModeAuto", nil)

// Only ask user if they want to delete policies if they are deleting HcpSharedVpc roles
deleteHcpSharedVpcPolicies := false
if roles.CheckIfRolesAreHcpSharedVpc(r, foundOperatorRoles) {
deleteHcpSharedVpcPolicies = confirm.Prompt(true, "Attempt to delete Hosted CP shared VPC policies?")
}
allSharedVpcPoliciesNotDeleted := make(map[string]bool)
for _, role := range foundOperatorRoles {
if !confirm.Prompt(true, "Delete the operator role '%s'?", role) {
continue
Expand All @@ -228,7 +236,11 @@ func run(cmd *cobra.Command, _ []string) {
if spin != nil {
spin.Start()
}
err := r.AWSClient.DeleteOperatorRole(role, managedPolicies)
sharedVpcPoliciesNotDeleted, err := r.AWSClient.DeleteOperatorRole(role, managedPolicies,
deleteHcpSharedVpcPolicies)
for key, value := range sharedVpcPoliciesNotDeleted {
allSharedVpcPoliciesNotDeleted[key] = value
}

if err != nil {
if spin != nil {
Expand All @@ -242,6 +254,12 @@ func run(cmd *cobra.Command, _ []string) {
spin.Stop()
}
}
for policyOutput, notDeleted := range allSharedVpcPoliciesNotDeleted {
if notDeleted {
r.Logger.Warnf("Unable to delete policy %s: Policy still attached to other resources",
policyOutput)
}
}
if !errOccured {
r.Reporter.Infof("Successfully deleted the operator roles")
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/aws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ type Client interface {
ListOidcProviders(targetClusterId string, config *cmv1.OidcConfig) ([]OidcProviderOutput, error)
GetRoleByARN(roleARN string) (iamtypes.Role, error)
GetRoleByName(roleName string) (iamtypes.Role, error)
DeleteOperatorRole(roles string, managedPolicies bool) error
DeleteOperatorRole(roles string, managedPolicies bool, deleteHcpSharedVpcPolicies bool) (map[string]bool, error)
GetOperatorRolesFromAccountByClusterID(
clusterID string,
credRequests map[string]*cmv1.STSOperator,
Expand All @@ -156,11 +156,12 @@ type Client interface {
GetAccountRoleForCurrentEnv(env string, roleName string) (Role, error)
GetAccountRoleForCurrentEnvWithPrefix(env string, rolePrefix string,
accountRolesMap map[string]AccountRole) ([]Role, error)
DeleteAccountRole(roleName string, prefix string, managedPolicies bool) error
DeleteAccountRole(roleName string, prefix string, managedPolicies bool, deleteHcpSharedVpcPolicies bool) error
DeleteOCMRole(roleARN string, managedPolicies bool) error
DeleteUserRole(roleName string) error
GetAccountRolePolicies(roles []string, prefix string) (map[string][]PolicyDetail, map[string][]PolicyDetail, error)
GetAttachedPolicy(role *string) ([]PolicyDetail, error)
GetPolicyDetailsFromRole(role *string) ([]*iam.GetPolicyOutput, error)
HasPermissionsBoundary(roleName string) (bool, error)
GetOpenIDConnectProviderByClusterIdTag(clusterID string) (string, error)
GetOpenIDConnectProviderByOidcEndpointUrl(oidcEndpointUrl string) (string, error)
Expand Down
36 changes: 26 additions & 10 deletions pkg/aws/client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 95 additions & 11 deletions pkg/aws/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -1065,15 +1065,37 @@ func checkIfROSAOperatorRole(role iamtypes.Role, credRequest map[string]*cmv1.ST
return false
}

func (c *awsClient) DeleteOperatorRole(roleName string, managedPolicies bool) error {
func (c *awsClient) GetPolicyDetailsFromRole(role *string) ([]*iam.GetPolicyOutput, error) {
policies, err := c.iamClient.ListAttachedRolePolicies(context.Background(), &iam.ListAttachedRolePoliciesInput{
RoleName: role,
})
if err != nil {
return nil, err
}
finalOutput := make([]*iam.GetPolicyOutput, 0)
for _, attachedPolicy := range policies.AttachedPolicies {
policy, err := c.iamClient.GetPolicy(context.Background(), &iam.GetPolicyInput{
PolicyArn: attachedPolicy.PolicyArn,
})
if err != nil {
return nil, err
}
finalOutput = append(finalOutput, policy)
}
return finalOutput, nil
}

func (c *awsClient) DeleteOperatorRole(roleName string, managedPolicies bool,
deleteHcpSharedVpcPolicies bool) (map[string]bool, error) {
role := aws.String(roleName)
sharedVpcPoliciesNotDeleted := make(map[string]bool)
tagFilter, err := getOperatorRolePolicyTags(c.iamClient, roleName)
if err != nil {
return err
return sharedVpcPoliciesNotDeleted, err
}
policies, excludedPolicies, err := getAttachedPolicies(c.iamClient, roleName, tagFilter)
if err != nil {
return err
return sharedVpcPoliciesNotDeleted, err
}
err = c.detachOperatorRolePolicies(role)
if err != nil {
Expand All @@ -1086,25 +1108,55 @@ func (c *awsClient) DeleteOperatorRole(roleName string, managedPolicies bool) er
err = nil
}
if err != nil {
return err
return sharedVpcPoliciesNotDeleted, err
}
}
err = c.DeleteRole(*role)
if err != nil {
return err
return sharedVpcPoliciesNotDeleted, err
}
if !managedPolicies {
_, err = c.deletePolicies(policies)
} else {
} else if deleteHcpSharedVpcPolicies {
var sharedVpcHcpPolicies []string
for _, policy := range excludedPolicies {
if strings.Contains(policy, SharedVpcAssumeRolePrefix) {
sharedVpcHcpPolicies = append(sharedVpcHcpPolicies, policy)
policyOutput, err := c.iamClient.GetPolicy(context.Background(), &iam.GetPolicyInput{
PolicyArn: aws.String(policy),
})
if err != nil || policyOutput == nil {
return sharedVpcPoliciesNotDeleted, err
}

containsManagedTag := false
containsHcpSharedVpcTag := false
for _, policyTag := range policyOutput.Policy.Tags {
switch strings.Trim(*policyTag.Key, " ") {
case tags.RedHatManaged:
containsManagedTag = true
case tags.HcpSharedVpc:
containsHcpSharedVpcTag = true
}
}
// Delete if no attachments and correct tags showing it's a hcp sharedvpc policy
if containsManagedTag && containsHcpSharedVpcTag {
if *policyOutput.Policy.AttachmentCount == 0 {
// If the policy is deleted, remove from the warning outputs
sharedVpcPoliciesNotDeleted[*policyOutput.Policy.Arn] = false

// Add to list of sharedVpc policies to be actually deleted
c.logger.Infof("Deleting policy '%s'", policy)
sharedVpcHcpPolicies = append(sharedVpcHcpPolicies, policy)
} else {
// Print warning message after all roles are checked (will result in duplicated warnings without
// adding to this map and displaying at the end of role deletion due to multiple roles having
// one of the policies)
sharedVpcPoliciesNotDeleted[*policyOutput.Policy.Arn] = true
}
}
}
_, err = c.deletePolicies(sharedVpcHcpPolicies)
}
return err
return sharedVpcPoliciesNotDeleted, err
}

func (c *awsClient) DeleteRole(role string) error {
Expand Down Expand Up @@ -1140,13 +1192,14 @@ func (c *awsClient) GetInstanceProfilesForRole(r string) ([]string, error) {
return instanceProfiles, nil
}

func (c *awsClient) DeleteAccountRole(roleName string, prefix string, managedPolicies bool) error {
func (c *awsClient) DeleteAccountRole(roleName string, prefix string, managedPolicies bool,
deleteHcpSharedVpcPolicies bool) error {
role := aws.String(roleName)
err := c.DeleteInlineRolePolicies(aws.ToString(role))
if err != nil {
return err
}
policyMap, _, err := getAttachedPolicies(c.iamClient, roleName, getAcctRolePolicyTags(prefix))
policyMap, excludedPolicyMap, err := getAttachedPolicies(c.iamClient, roleName, getAcctRolePolicyTags(prefix))
if err != nil {
return err
}
Expand All @@ -1173,6 +1226,37 @@ func (c *awsClient) DeleteAccountRole(roleName string, prefix string, managedPol
}
if !managedPolicies {
_, err = c.deletePolicies(policyMap)
} else if deleteHcpSharedVpcPolicies {
var sharedVpcHcpPolicies []string
for _, policy := range excludedPolicyMap {
policyOutput, err := c.iamClient.GetPolicy(context.Background(), &iam.GetPolicyInput{
PolicyArn: aws.String(policy),
})
if err != nil || policyOutput == nil {
return err
}

containsManagedTag := false
containsHcpSharedVpcTag := false
for _, policyTag := range policyOutput.Policy.Tags {
switch strings.Trim(*policyTag.Key, " ") {
case tags.RedHatManaged:
containsManagedTag = true
case tags.HcpSharedVpc:
containsHcpSharedVpcTag = true
}
}
if containsManagedTag && containsHcpSharedVpcTag {
if *policyOutput.Policy.AttachmentCount == 0 {
c.logger.Infof("Deleting policy '%s'", policy)
sharedVpcHcpPolicies = append(sharedVpcHcpPolicies, policy)
} else {
c.logger.Warnf("Unable to delete policy %s: Policy still attached to %v other resource(s)",
*policyOutput.Policy.PolicyName, *policyOutput.Policy.AttachmentCount)
}
}
}
_, err = c.deletePolicies(sharedVpcHcpPolicies)
}
return err
}
Expand Down
Loading

0 comments on commit 1ab99b6

Please sign in to comment.