modules/mu/clouds/aws/role.rb in cloud-mu-2.1.0beta vs modules/mu/clouds/aws/role.rb in cloud-mu-3.0.0beta

- old
+ new

@@ -15,24 +15,15 @@ module MU class Cloud class AWS # A user as configured in {MU::Config::BasketofKittens::roles} class Role < MU::Cloud::Role - @deploy = nil - @config = nil - attr_reader :mu_name - attr_reader :config - attr_reader :cloud_id - # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member. - # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::roles} - def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil) - @deploy = mommacat - @config = MU::Config.manxify(kitten_cfg) - @cloud_id ||= cloud_id - @mu_name = mu_name - @cloud_id ||= @mu_name # should be the same + # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us. + # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat + def initialize(**args) + super @mu_name ||= @deploy.getResourceName(@config["name"]) end # Called automatically by {MU::Deploy#createResources} def create @@ -130,12 +121,21 @@ version = MU::Cloud::AWS.iam(credentials: @config['credentials']).get_policy_version( policy_arn: arn, version_id: desc.policy.default_version_id ) - if version.policy_version.document != URI.encode(JSON.generate(policy.values.first), /[^a-z0-9\-]/i) - MU.log "Updating IAM policy #{policy_name}", MU::NOTICE, details: policy.values.first + if version.policy_version.document != URI.encode_www_form(JSON.generate(policy.values.first), /[^a-z0-9\-]/i) + # Special exception- we don't want to overwrite extra rules + # in MuSecrets policies, because our siblings might have + # (will have) injected those and they should stay. + if policy.size == 1 and policy["MuSecrets"] + ext = JSON.parse(URI.decode_www_form(version.policy_version.document)) + if (ext["Statement"][0]["Resource"] & policy["MuSecrets"]["Statement"][0]["Resource"]).sort == policy["MuSecrets"]["Statement"][0]["Resource"].sort + next + end + end + MU.log "Updating IAM policy #{policy_name}", MU::NOTICE, details: policy update_policy(arn, policy.values.first) MU::Cloud::AWS.iam(credentials: @config['credentials']).get_policy(policy_arn: arn) else desc end @@ -269,44 +269,59 @@ def self.purgePolicy(policy_arn, credentials) attachments = MU::Cloud::AWS.iam(credentials: credentials).list_entities_for_policy( policy_arn: policy_arn ) attachments.policy_users.each { |u| - MU::Cloud::AWS.iam(credentials: credentials).detach_user_policy( - user_name: u.user_name, - policy_arn: policy_arn - ) + begin + MU::Cloud::AWS.iam(credentials: credentials).detach_user_policy( + user_name: u.user_name, + policy_arn: policy_arn + ) + rescue ::Aws::IAM::Errors::NoSuchEntity + end } attachments.policy_groups.each { |g| - MU::Cloud::AWS.iam(credentials: credentials).detach_group_policy( - group_name: g.group_name, - policy_arn: policy_arn - ) + begin + MU::Cloud::AWS.iam(credentials: credentials).detach_group_policy( + group_name: g.group_name, + policy_arn: policy_arn + ) + rescue ::Aws::IAM::Errors::NoSuchEntity + end } attachments.policy_roles.each { |r| - MU::Cloud::AWS.iam(credentials: credentials).detach_role_policy( - role_name: r.role_name, - policy_arn: policy_arn - ) + begin + MU::Cloud::AWS.iam(credentials: credentials).detach_role_policy( + role_name: r.role_name, + policy_arn: policy_arn + ) + rescue ::Aws::IAM::Errors::NoSuchEntity + end } versions = MU::Cloud::AWS.iam(credentials: credentials).list_policy_versions( policy_arn: policy_arn, ).versions versions.each { |v| next if v.is_default_version - MU::Cloud::AWS.iam(credentials: credentials).delete_policy_version( - policy_arn: policy_arn, - version_id: v.version_id - ) + begin + MU::Cloud::AWS.iam(credentials: credentials).delete_policy_version( + policy_arn: policy_arn, + version_id: v.version_id + ) + rescue ::Aws::IAM::Errors::NoSuchEntity + end } # Delete the policy, unless it's one of the global canned ones owned # by AWS if !policy_arn.match(/^arn:aws:iam::aws:/) - MU::Cloud::AWS.iam(credentials: credentials).delete_policy( - policy_arn: policy_arn - ) + begin + MU::Cloud::AWS.iam(credentials: credentials).delete_policy( + policy_arn: policy_arn + ) + rescue ::Aws::IAM::Errors::NoSuchEntity + end end end # Does this resource type exist as a global (cloud-wide) artifact, or # is it localized to a region/zone? @@ -338,15 +353,29 @@ purgePolicy(policy.arn, credentials) end } end + deleteme = [] resp = MU::Cloud::AWS.iam(credentials: credentials).list_roles( path_prefix: "/"+MU.deploy_id+"/" ) - if resp and resp.roles - resp.roles.each { |r| + deleteme.concat(resp.roles) if resp and resp.roles + if flags and flags["known"] + resp = MU::Cloud::AWS.iam(credentials: credentials).list_roles( + max_items: 1000 + ) + if resp and resp.roles + resp.roles.each { |r| + deleteme << r if flags["known"].include?(r.role_name) + } + end + deleteme.uniq! + end + + if deleteme.size > 0 + deleteme.each { |r| MU.log "Deleting IAM role #{r.role_name}" if !noop # purgePolicy won't touch roles we don't own, so gently detach # those first detachables = MU::Cloud::AWS.iam(credentials: credentials).list_attached_role_policies( @@ -442,11 +471,11 @@ if entitytype == "user" resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).list_attached_user_policies( path_prefix: "/"+@deploy.deploy_id+"/", user_name: entityname ) - if !resp or !resp.attached_policies.map { |p| p.policy_name }.include?(p.policy_name) + if !resp or !resp.attached_policies.map { |a_p| a_p.policy_name }.include?(p.policy_name) MU.log "Attaching IAM policy #{p.policy_name} to user #{entityname}", MU::NOTICE MU::Cloud::AWS.iam(credentials: @config['credentials']).attach_user_policy( policy_arn: p.arn, user_name: entityname ) @@ -454,11 +483,11 @@ elsif entitytype == "group" resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).list_attached_group_policies( path_prefix: "/"+@deploy.deploy_id+"/", group_name: entityname ) - if !resp or !resp.attached_policies.map { |p| p.policy_name }.include?(p.policy_name) + if !resp or !resp.attached_policies.map { |a_p| a_p.policy_name }.include?(p.policy_name) MU.log "Attaching policy #{p.policy_name} to group #{entityname}", MU::NOTICE MU::Cloud::AWS.iam(credentials: @config['credentials']).attach_group_policy( policy_arn: p.arn, group_name: entityname ) @@ -466,10 +495,10 @@ elsif entitytype == "role" resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).list_attached_role_policies( role_name: entityname ) - if !resp or !resp.attached_policies.map { |p| p.policy_name }.include?(p.policy_name) + if !resp or !resp.attached_policies.map { |a_p| a_p.policy_name }.include?(p.policy_name) MU.log "Attaching policy #{p.policy_name} to role #{entityname}", MU::NOTICE MU::Cloud::AWS.iam(credentials: @config['credentials']).attach_role_policy( policy_arn: p.arn, role_name: entityname )