Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.2.1 #8

Merged
merged 24 commits into from
Jul 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ test.rb
IAMfile
*.iam
account.csv
*.json
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Usage: miam [options]
-o, --output FILE
--split
--split-more
--format=FORMAT
--export-concurrency N
--target REGEXP
--no-color
Expand Down Expand Up @@ -86,6 +87,10 @@ user "bob", :path => "/developer/" do
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
# attached_managed_policy
)
end

user "mary", :path => "/staff/" do
Expand Down Expand Up @@ -114,6 +119,11 @@ user "mary", :path => "/staff/" do
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AdministratorAccess",
"arn:aws:iam::123456789012:policy/my_policy"
)
end

group "Admin", :path => "/admin/" do
Expand Down
41 changes: 33 additions & 8 deletions bin/miam
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ file = DEFAULT_FILENAME
output_file = '-'
account_output = 'account.csv'
split = false
MAGIC_COMMENT = <<-EOS
# -*- mode: ruby -*-
# vi: set ft=ruby :
EOS

options = {
:dry_run => false,
:format => :ruby,
:color => true,
:debug => false,
}
Expand All @@ -29,6 +34,7 @@ ARGV.options do |opt|
region = nil
profile_name = nil
credentials_path = nil
format_passed = false

opt.on('-p', '--profile PROFILE_NAME') {|v| profile_name = v }
opt.on('' , '--credentials-path PATH') {|v| credentials_path = v }
Expand All @@ -43,6 +49,7 @@ ARGV.options do |opt|
opt.on('-o', '--output FILE') {|v| output_file = v }
opt.on('' , '--split') { split = true }
opt.on('' , '--split-more') { split = :more }
opt.on('', '--format=FORMAT', [:ruby, :json]) {|v| format_passed = true; options[:format] = v }
opt.on('' , '--export-concurrency N', Integer) {|v| options[:export_concurrency] = v }
opt.on('' , '--target REGEXP') {|v| options[:target] = Regexp.new(v) }
opt.on('' , '--no-color') { options[:color] = false }
Expand Down Expand Up @@ -70,6 +77,10 @@ ARGV.options do |opt|

aws_opts[:region] = region if region
Aws.config.update(aws_opts)

if not format_passed and [file, output_file].any? {|i| i =~ /\.json\z/ }
options[:format] = :json
end
rescue => e
$stderr.puts("[ERROR] #{e.message}")
exit 1
Expand Down Expand Up @@ -97,9 +108,9 @@ begin
output_file = DEFAULT_FILENAME if output_file == '-'
requires = []

client.export(:split_more => (split == :more)) do |args|
client.export(:split_more => (split == :more), :convert => (options[:format] == :ruby)) do |args|
type, dsl = args.values_at(:type, :dsl)
next if dsl.strip.empty?
next if dsl.empty?

type = type.to_s
dir = File.dirname(output_file)
Expand All @@ -117,27 +128,41 @@ begin
requires << iam_filename
end

if options[:format] == :json
iam_file << '.json'
end

logger.info(" write `#{iam_file}`")

open(iam_file, 'wb') do |f|
f.puts MAGIC_COMMENT if options[:format] == :ruby
f.puts dsl
end
end

logger.info(" write `#{output_file}`")
if options[:format] == :ruby
logger.info(" write `#{output_file}`")

open(output_file, 'wb') do |f|
requires.each do |iam_file|
f.puts "require '#{iam_file}'"
open(output_file, 'wb') do |f|
f.puts MAGIC_COMMENT

requires.each do |iam_file|
f.puts "require '#{iam_file}'"
end
end
end
else
exported = client.export(:convert => (options[:format] == :ruby))

if output_file == '-'
logger.info('# Export IAM')
puts client.export.strip
puts exported
else
logger.info("Export IAM to `#{output_file}`")
open(output_file, 'wb') {|f| f.puts client.export.strip }
open(output_file, 'wb') do |f|
f.puts MAGIC_COMMENT if options[:format] == :ruby
f.puts exported
end
end
end
when :apply
Expand Down
1 change: 0 additions & 1 deletion lib/miam.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ module Miam; end
require 'miam/dsl/context/user'
require 'miam/dsl/converter'
require 'miam/exporter'
require 'miam/ext/aws_ext'
require 'miam/ext/string_ext'
require 'miam/password_manager'
require 'miam/utils'
Expand Down
95 changes: 88 additions & 7 deletions lib/miam/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class Miam::Client
include Miam::Logger::Helper

def initialize(options = {})
@options = options
@options = {:format => :ruby}.merge(options)
aws_config = options.delete(:aws_config) || {}
@iam = Aws::IAM::Client.new(aws_config)
@driver = Miam::Driver.new(@iam, options)
Expand All @@ -21,15 +21,30 @@ def export(export_options = {})
more_splitted = splitted.dup
more_splitted[type] = {}
more_splitted[type][name] = attrs
yield(:type => type, :name => name, :dsl => Miam::DSL.convert(more_splitted, @options).strip)

dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(more_splitted, @options).strip },
:json => proc { JSON.pretty_generate(more_splitted) }
)

yield(:type => type, :name => name, :dsl => dsl)
end
else
splitted[type] = exported[type]
yield(:type => type, :dsl => Miam::DSL.convert(splitted, @options).strip)

dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(splitted, @options).strip },
:json => proc { JSON.pretty_generate(splitted) }
)

yield(:type => type, :dsl => dsl)
end
end
else
Miam::DSL.convert(exported, @options)
dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(exported, @options).strip },
:json => proc { JSON.pretty_generate(exported) }
)
end
end

Expand Down Expand Up @@ -97,6 +112,7 @@ def walk_users(expected, actual, group_users)
def walk_user(user_name, expected_attrs, actual_attrs)
updated = walk_login_profile(user_name, expected_attrs[:login_profile], actual_attrs[:login_profile])
updated = walk_user_groups(user_name, expected_attrs[:groups], actual_attrs[:groups]) || updated
updated = walk_attached_managed_policies(:user, user_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
walk_policies(:user, user_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
end

Expand Down Expand Up @@ -182,7 +198,8 @@ def walk_groups(expected, actual, actual_users, group_users)
end

def walk_group(group_name, expected_attrs, actual_attrs)
walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
updated = walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
walk_attached_managed_policies(:group, group_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
end

def walk_roles(expected, actual, instance_profile_roles)
Expand Down Expand Up @@ -232,6 +249,7 @@ def walk_role(role_name, expected_attrs, actual_attrs)

updated = walk_assume_role_policy(role_name, expected_attrs[:assume_role_policy_document], actual_attrs[:assume_role_policy_document])
updated = walk_role_instance_profiles(role_name, expected_attrs[:instance_profiles], actual_attrs[:instance_profiles]) || updated
updated = walk_attached_managed_policies(:role, role_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
walk_policies(:role, role_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
end

Expand Down Expand Up @@ -389,13 +407,43 @@ def walk_policy(type, user_or_group_name, policy_name, expected_document, actual
updated
end

def walk_attached_managed_policies(type, name, expected_attached_managed_policies, actual_attached_managed_policies)
expected_attached_managed_policies = expected_attached_managed_policies.sort
actual_attached_managed_policies = actual_attached_managed_policies.sort
updated = false

if expected_attached_managed_policies != actual_attached_managed_policies
add_attached_managed_policies = expected_attached_managed_policies - actual_attached_managed_policies
remove_attached_managed_policies = actual_attached_managed_policies - expected_attached_managed_policies

unless add_attached_managed_policies.empty?
@driver.attach_policies(type, name, add_attached_managed_policies)
end

unless remove_attached_managed_policies.empty?
@driver.detach_policies(type, name, remove_attached_managed_policies)
end

updated = true
end

updated
end


def load_file(file)
if file.kind_of?(String)
open(file) do |f|
Miam::DSL.parse(f.read, file)
exec_by_format(
:ruby => proc { Miam::DSL.parse(f.read, file) },
:json => proc { load_json(f) }
)
end
elsif file.respond_to?(:read)
Miam::DSL.parse(file.read, file.path)
exec_by_format(
:ruby => proc { Miam::DSL.parse(file.read, file.path) },
:json => proc { load_json(f) }
)
else
raise TypeError, "can't convert #{file} into File"
end
Expand All @@ -408,4 +456,37 @@ def target_matched?(name)
true
end
end

def exec_by_format(proc_by_format)
format_proc = proc_by_format[@options[:format]]
raise "Invalid format: #{@options[:format]}" unless format_proc
format_proc.call
end

def load_json(json)
json = JSON.load(json)
normalized = {}

json.each do |top_key, top_value|
normalized[top_key.to_sym] = top_attrs = {}

top_value.each do |second_key, second_value|
top_attrs[second_key] = second_attrs = {}

second_value.each do |third_key, third_value|
third_key = third_key.to_sym

if third_key == :login_profile
new_third_value = {}
third_value.each {|k, v| new_third_value[k.to_sym] = v }
third_value = new_third_value
end

second_attrs[third_key] = third_value
end
end
end

normalized
end
end
Loading