class Cumulus::IAM::IamResource

Internal: Represents the manager of a type of IamResource. Base class for groups, roles, and users.

Public Class Methods

new(iam) click to toggle source

Public: Constructor

iam - the IAM client to use

# File lib/iam/manager/IamResource.rb, line 92
def initialize(iam)
  @iam = iam
  @migration_root = "generated"
end

Public Instance Methods

aws_resources() click to toggle source

Public: Get resources from AWS

Returns an array of resources from AWS

# File lib/iam/manager/IamResource.rb, line 56
def aws_resources
  nil
end
create(difference) click to toggle source

Public: Create a resource in AWS

difference - the Diff object that contains the local differences

Returns the created resource

# File lib/iam/manager/IamResource.rb, line 65
def create(difference)
  nil
end
diff() click to toggle source

Public: Print out the diff between the local configuration and the IAMS in AWS

# File lib/iam/manager/IamResource.rb, line 99
def diff
  each_difference(local_resources, true, &@@diff)
end
diff_one(name) click to toggle source

Public: Print out the diff between local configuration and AWS for one resource

name - the name of the resource to diff

# File lib/iam/manager/IamResource.rb, line 107
def diff_one(name)
  each_difference({ name => one_local(name) }, false, &@@diff)
end
empty_config() click to toggle source

Public: Create an empty config object

Returns the created config object

# File lib/iam/manager/IamResource.rb, line 72
def empty_config
  nil
end
list() click to toggle source

Public: Print out a list of resources defined by local configuration.

# File lib/iam/manager/IamResource.rb, line 112
def list
  puts local_resources.map { |name, resource| name }.join(" ")
end
local_resources() click to toggle source

Methods to be overridden

Public: Get the local resources

Returns an array of resources

# File lib/iam/manager/IamResource.rb, line 40
def local_resources
  nil
end
migrate() click to toggle source

Public: Migrate AWS IAMs to Cumulus configuration.

# File lib/iam/manager/IamResource.rb, line 131
def migrate
  assets = "#{@migration_root}/#{@migration_dir}"
  policies_dir = "#{@migration_root}/policies"
  statics_dir = "#{policies_dir}/static"

  if !Dir.exists?(@migration_root)
    Dir.mkdir(@migration_root)
  end
  if !Dir.exists?(assets)
    Dir.mkdir(assets)
  end
  if !Dir.exists?(policies_dir)
    Dir.mkdir(policies_dir)
  end
  if !Dir.exists?(statics_dir)
    Dir.mkdir(statics_dir)
  end

  # generate the configuration objects. This MUST be done separate from
  # writing to file, because the unifier will change the configuration objects
  # as it finds ways to unify configured attributes.
  policy_unifier = PolicyUnifier.new(statics_dir)
  configs = aws_resources.map do |resource|
    puts "Processing #{@type} #{resource.name}..."
    config = empty_config
    config.name = resource.name

    config.attached_policies = resource.attached_policies.map { |p| p.arn }

    resource.policies.each do |policy|
      statements = JSON.parse(URI.decode(policy.policy_document))["Statement"]
      statements.each { |statement| statement.delete("Sid") }
      policy_unifier.unify(config, statements, policy.name)
    end

    [config, resource]
  end

  migrate_additional(configs)
  configs = configs.map { |config, resource| config }

  # write the configuration to file
  puts "Writing configuration to file..."
  configs.each do |config|
    File.open("#{assets}/#{config.name}.json", 'w') { |f| f.write(config.json) }
  end

  puts "Done."
end
migrate_additional(configs_to_aws) click to toggle source

Public: When migrating, provide a config with any resource type specific data.

configs_to_aws - an array of arrays where each inner array's first element

is the configuration generated so far, and the second
element is the corresponding aws resource
# File lib/iam/manager/IamResource.rb, line 82
def migrate_additional(configs_to_aws)
end
one_local(name) click to toggle source

Public: Get one local resource

name - the name of the resource to load

Returns one local resource

# File lib/iam/manager/IamResource.rb, line 49
def one_local(name)
  nil
end
sync() click to toggle source

Public: Sync the local configuration with the configuration in AWS. Will not delete resources that are not locally configured; also will not remove inline policies that are not locally configured.

# File lib/iam/manager/IamResource.rb, line 119
def sync
  each_difference(local_resources, true) { |name, diffs| sync_difference(name, diffs) }
end
sync_one(name) click to toggle source

Public: Sync the local configuration for one resource with AWS

name - the name of the resource to sync

# File lib/iam/manager/IamResource.rb, line 126
def sync_one(name)
  each_difference({ name => one_local(name) }, false) { |name, diffs| sync_difference(name, diffs) }
end
update(resource, diffs) click to toggle source

Public: Update a resource in AWS

resource - the resource to update diffs - the diff objects to be used when updating the resource

# File lib/iam/manager/IamResource.rb, line 185
def update(resource, diffs)
  if diffs.size == 1 and diffs[0].type == Common::DiffChange::ADD
    if !diffs[0].local.policy.empty?
      update_policy(resource, diffs[0].local.generated_policy_name, diffs[0].local.policy)
    end
    if !diffs[0].local.attached_policies.empty?
      update_attached(resource, diffs[0].local.attached_policies, [])
    end
  else
    diffs.each do |diff|
      case diff.type
      when IamChange::POLICY
        update_policy(resource, diff.policy_name, diff.local)
      when IamChange::ATTACHED
        update_attached(resource, diff.attached, diff.detached)
      when IamChange::ADDED_POLICY
        update_policy(resource, diff.policy_name, diff.local)
      when IamChange::UNMANAGED_POLICY
        puts Colors.unmanaged("\t#{diff.policy_name} is not managed by Cumulus")
      end
    end
  end
end

Private Instance Methods

each_difference(locals, include_unmanaged, &f) click to toggle source

Internal: Loop through the differences between local configuration and AWS

locals - the local configurations to compare against include_unmanaged - whether to include unmanaged resources in the list of

changes

f - will be passed the name of the resource and an array of

IamDiffs
# File lib/iam/manager/IamResource.rb, line 218
def each_difference(locals, include_unmanaged, &f)
  aws = Hash[aws_resources.map { |aws| [aws.name, aws] }]

  if include_unmanaged
    aws.each do |name, resource|
      f.call(name, [IamDiff.unmanaged(resource)]) if !locals.include?(name)
    end
  end
  locals.each do |name, resource|
    if !aws.include?(name)
      f.call(name, [IamDiff.added(resource)])
    else
      f.call(name, resource.diff(aws[name]))
    end
  end
end
sync_difference(name, diffs) click to toggle source

Internal: Sync differences

name - the name of the resource to sync diffs - the differences between the configuration and AWS

# File lib/iam/manager/IamResource.rb, line 239
def sync_difference(name, diffs)
  aws = Hash[aws_resources.map { |aws| [aws.name, aws] }]
  if diffs.size > 0
    StatusCodes::set_status(StatusCodes::SYNC_DIFFS)

    if diffs[0].type == Common::DiffChange::UNMANAGED
      puts diffs[0]
    elsif diffs[0].type == Common::DiffChange::ADD
      puts Colors.added("creating #{name}...")
      resource = create(diffs[0])
      update(resource, diffs)
    else
      puts Colors.blue("updating #{name}...")
      resource = aws[name]
      update(resource, diffs)
    end
  end
end
update_attached(resource, attach, detach) click to toggle source

Internal: Update the attached policies

resource - the AWS resource to update attach - the policy arns to attach detach - the policy arns to detach

# File lib/iam/manager/IamResource.rb, line 280
def update_attached(resource, attach, detach)
  puts Colors.blue("\tupdating attached policies...")
  attach.each { |arn| resource.attach_policy({ :policy_arn => arn }) }
  detach.each { |arn| resource.detach_policy({ :policy_arn => arn }) }
end
update_policy(resource, name, config) click to toggle source

Internal: Update the generated policy

resource - the AWS resource to update name - the name of the policy to update config - the policy config to use when updating

# File lib/iam/manager/IamResource.rb, line 263
def update_policy(resource, name, config)
  puts Colors.blue("\tupdating policy #{name}...")
  policy = resource.policy(name)
  if config.empty?
    policy.delete()
  else
    policy.put({
      :policy_document => config.as_pretty_json
    })
  end
end