miam 0.2.1.beta → 0.2.1.beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36c61dfa27b8707f131eb351e67812370c895f13
4
- data.tar.gz: 032983200bcecaea10c62a3248c421b500a11f1a
3
+ metadata.gz: 4ae6239d6d5f9f0eef078614f4b493e041027e8c
4
+ data.tar.gz: 76dbd8857e2d4705823d7f09ca5fc9e611602ddf
5
5
  SHA512:
6
- metadata.gz: 1ad638d2a6d62919f5f747348201d013489ae232edc156d2b0669b69be526295315759843f573bdcbb49acc9f7eed54d8c8728cbb26b6c8135e96e0c960c95c2
7
- data.tar.gz: e735a72122942c6592517a09bb573aa69699f186afb209055257914c6a574ff21258be4b5a7e9f1707764d419b9f5ec0a14d72b013d576a6201ee0324a2f97a8
6
+ metadata.gz: 55489685bbd41ab9d6945a4e4f088f1af12af92a708ee910a812665c77ac0df7dfdb6ac4ccfa214de39eba8d129e45a82dc9714b40d179da364780d77756cc6b
7
+ data.tar.gz: ef9a4b34c0e49d1e15f3af8c9dd8b69eae4be274049a9f9d175c343079b2b34a47823ea905d3f706190cf3b7e0bec5a0daceee884be4fcd00cbc841c4b7bb35b
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test.rb
16
16
  IAMfile
17
17
  *.iam
18
18
  account.csv
19
+ *.json
data/README.md CHANGED
@@ -86,6 +86,10 @@ user "bob", :path => "/developer/" do
86
86
  "Effect"=>"Allow",
87
87
  "Resource"=>"*"}]}
88
88
  end
89
+
90
+ attached_managed_policies(
91
+ # attached_managed_policy
92
+ )
89
93
  end
90
94
 
91
95
  user "mary", :path => "/staff/" do
@@ -114,6 +118,11 @@ user "mary", :path => "/staff/" do
114
118
  "Effect"=>"Allow",
115
119
  "Resource"=>"*"}]}
116
120
  end
121
+
122
+ attached_managed_policies(
123
+ "arn:aws:iam::aws:policy/AdministratorAccess",
124
+ "arn:aws:iam::123456789012:policy/my_policy"
125
+ )
117
126
  end
118
127
 
119
128
  group "Admin", :path => "/admin/" do
data/bin/miam CHANGED
@@ -13,9 +13,14 @@ file = DEFAULT_FILENAME
13
13
  output_file = '-'
14
14
  account_output = 'account.csv'
15
15
  split = false
16
+ MAGIC_COMMENT = <<-EOS
17
+ # -*- mode: ruby -*-
18
+ # vi: set ft=ruby :
19
+ EOS
16
20
 
17
21
  options = {
18
22
  :dry_run => false,
23
+ :format => :ruby,
19
24
  :color => true,
20
25
  :debug => false,
21
26
  }
@@ -29,6 +34,7 @@ ARGV.options do |opt|
29
34
  region = nil
30
35
  profile_name = nil
31
36
  credentials_path = nil
37
+ format_passed = false
32
38
 
33
39
  opt.on('-p', '--profile PROFILE_NAME') {|v| profile_name = v }
34
40
  opt.on('' , '--credentials-path PATH') {|v| credentials_path = v }
@@ -43,6 +49,7 @@ ARGV.options do |opt|
43
49
  opt.on('-o', '--output FILE') {|v| output_file = v }
44
50
  opt.on('' , '--split') { split = true }
45
51
  opt.on('' , '--split-more') { split = :more }
52
+ opt.on('', '--format=FORMAT', [:ruby, :json]) {|v| format_passed = true; options[:format] = v }
46
53
  opt.on('' , '--export-concurrency N', Integer) {|v| options[:export_concurrency] = v }
47
54
  opt.on('' , '--target REGEXP') {|v| options[:target] = Regexp.new(v) }
48
55
  opt.on('' , '--no-color') { options[:color] = false }
@@ -70,6 +77,10 @@ ARGV.options do |opt|
70
77
 
71
78
  aws_opts[:region] = region if region
72
79
  Aws.config.update(aws_opts)
80
+
81
+ if not format_passed and [file, output_file].any? {|i| i =~ /\.json\z/ }
82
+ options[:format] = :json
83
+ end
73
84
  rescue => e
74
85
  $stderr.puts("[ERROR] #{e.message}")
75
86
  exit 1
@@ -97,9 +108,9 @@ begin
97
108
  output_file = DEFAULT_FILENAME if output_file == '-'
98
109
  requires = []
99
110
 
100
- client.export(:split_more => (split == :more)) do |args|
111
+ client.export(:split_more => (split == :more), :convert => (options[:format] == :ruby)) do |args|
101
112
  type, dsl = args.values_at(:type, :dsl)
102
- next if dsl.strip.empty?
113
+ next if dsl.empty?
103
114
 
104
115
  type = type.to_s
105
116
  dir = File.dirname(output_file)
@@ -117,27 +128,41 @@ begin
117
128
  requires << iam_filename
118
129
  end
119
130
 
131
+ if options[:format] == :json
132
+ iam_file << '.json'
133
+ end
134
+
120
135
  logger.info(" write `#{iam_file}`")
121
136
 
122
137
  open(iam_file, 'wb') do |f|
138
+ f.puts MAGIC_COMMENT if options[:format] == :ruby
123
139
  f.puts dsl
124
140
  end
125
141
  end
126
142
 
127
- logger.info(" write `#{output_file}`")
143
+ if options[:format] == :ruby
144
+ logger.info(" write `#{output_file}`")
128
145
 
129
- open(output_file, 'wb') do |f|
130
- requires.each do |iam_file|
131
- f.puts "require '#{iam_file}'"
146
+ open(output_file, 'wb') do |f|
147
+ f.puts MAGIC_COMMENT
148
+
149
+ requires.each do |iam_file|
150
+ f.puts "require '#{iam_file}'"
151
+ end
132
152
  end
133
153
  end
134
154
  else
155
+ exported = client.export(:convert => (options[:format] == :ruby))
156
+
135
157
  if output_file == '-'
136
158
  logger.info('# Export IAM')
137
- puts client.export.strip
159
+ puts exported
138
160
  else
139
161
  logger.info("Export IAM to `#{output_file}`")
140
- open(output_file, 'wb') {|f| f.puts client.export.strip }
162
+ open(output_file, 'wb') do |f|
163
+ f.puts MAGIC_COMMENT if options[:format] == :ruby
164
+ f.puts exported
165
+ end
141
166
  end
142
167
  end
143
168
  when :apply
@@ -2,7 +2,7 @@ class Miam::Client
2
2
  include Miam::Logger::Helper
3
3
 
4
4
  def initialize(options = {})
5
- @options = options
5
+ @options = {:format => :ruby}.merge(options)
6
6
  aws_config = options.delete(:aws_config) || {}
7
7
  @iam = Aws::IAM::Client.new(aws_config)
8
8
  @driver = Miam::Driver.new(@iam, options)
@@ -21,15 +21,30 @@ class Miam::Client
21
21
  more_splitted = splitted.dup
22
22
  more_splitted[type] = {}
23
23
  more_splitted[type][name] = attrs
24
- yield(:type => type, :name => name, :dsl => Miam::DSL.convert(more_splitted, @options).strip)
24
+
25
+ dsl = exec_by_format(
26
+ :ruby => proc { Miam::DSL.convert(more_splitted, @options).strip },
27
+ :json => proc { JSON.pretty_generate(more_splitted) }
28
+ )
29
+
30
+ yield(:type => type, :name => name, :dsl => dsl)
25
31
  end
26
32
  else
27
33
  splitted[type] = exported[type]
28
- yield(:type => type, :dsl => Miam::DSL.convert(splitted, @options).strip)
34
+
35
+ dsl = exec_by_format(
36
+ :ruby => proc { Miam::DSL.convert(splitted, @options).strip },
37
+ :json => proc { JSON.pretty_generate(splitted) }
38
+ )
39
+
40
+ yield(:type => type, :dsl => dsl)
29
41
  end
30
42
  end
31
43
  else
32
- Miam::DSL.convert(exported, @options)
44
+ dsl = exec_by_format(
45
+ :ruby => proc { Miam::DSL.convert(exported, @options).strip },
46
+ :json => proc { JSON.pretty_generate(exported) }
47
+ )
33
48
  end
34
49
  end
35
50
 
@@ -97,6 +112,7 @@ class Miam::Client
97
112
  def walk_user(user_name, expected_attrs, actual_attrs)
98
113
  updated = walk_login_profile(user_name, expected_attrs[:login_profile], actual_attrs[:login_profile])
99
114
  updated = walk_user_groups(user_name, expected_attrs[:groups], actual_attrs[:groups]) || updated
115
+ updated = walk_attached_managed_policies(:user, user_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
100
116
  walk_policies(:user, user_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
101
117
  end
102
118
 
@@ -182,7 +198,8 @@ class Miam::Client
182
198
  end
183
199
 
184
200
  def walk_group(group_name, expected_attrs, actual_attrs)
185
- walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
201
+ updated = walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
202
+ walk_attached_managed_policies(:group, group_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
186
203
  end
187
204
 
188
205
  def walk_roles(expected, actual, instance_profile_roles)
@@ -232,6 +249,7 @@ class Miam::Client
232
249
 
233
250
  updated = walk_assume_role_policy(role_name, expected_attrs[:assume_role_policy_document], actual_attrs[:assume_role_policy_document])
234
251
  updated = walk_role_instance_profiles(role_name, expected_attrs[:instance_profiles], actual_attrs[:instance_profiles]) || updated
252
+ updated = walk_attached_managed_policies(:role, role_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
235
253
  walk_policies(:role, role_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
236
254
  end
237
255
 
@@ -389,13 +407,43 @@ class Miam::Client
389
407
  updated
390
408
  end
391
409
 
410
+ def walk_attached_managed_policies(type, name, expected_attached_managed_policies, actual_attached_managed_policies)
411
+ expected_attached_managed_policies = expected_attached_managed_policies.sort
412
+ actual_attached_managed_policies = actual_attached_managed_policies.sort
413
+ updated = false
414
+
415
+ if expected_attached_managed_policies != actual_attached_managed_policies
416
+ add_attached_managed_policies = expected_attached_managed_policies - actual_attached_managed_policies
417
+ remove_attached_managed_policies = actual_attached_managed_policies - expected_attached_managed_policies
418
+
419
+ unless add_attached_managed_policies.empty?
420
+ @driver.attach_policies(type, name, add_attached_managed_policies)
421
+ end
422
+
423
+ unless remove_attached_managed_policies.empty?
424
+ @driver.detach_policies(type, name, remove_attached_managed_policies)
425
+ end
426
+
427
+ updated = true
428
+ end
429
+
430
+ updated
431
+ end
432
+
433
+
392
434
  def load_file(file)
393
435
  if file.kind_of?(String)
394
436
  open(file) do |f|
395
- Miam::DSL.parse(f.read, file)
437
+ exec_by_format(
438
+ :ruby => proc { Miam::DSL.parse(f.read, file) },
439
+ :json => proc { load_json(f) }
440
+ )
396
441
  end
397
442
  elsif file.respond_to?(:read)
398
- Miam::DSL.parse(file.read, file.path)
443
+ exec_by_format(
444
+ :ruby => proc { Miam::DSL.parse(file.read, file.path) },
445
+ :json => proc { load_json(f) }
446
+ )
399
447
  else
400
448
  raise TypeError, "can't convert #{file} into File"
401
449
  end
@@ -408,4 +456,37 @@ class Miam::Client
408
456
  true
409
457
  end
410
458
  end
459
+
460
+ def exec_by_format(proc_by_format)
461
+ format_proc = proc_by_format[@options[:format]]
462
+ raise "Invalid format: #{@options[:format]}" unless format_proc
463
+ format_proc.call
464
+ end
465
+
466
+ def load_json(json)
467
+ json = JSON.load(json)
468
+ normalized = {}
469
+
470
+ json.each do |top_key, top_value|
471
+ normalized[top_key.to_sym] = top_attrs = {}
472
+
473
+ top_value.each do |second_key, second_value|
474
+ top_attrs[second_key] = second_attrs = {}
475
+
476
+ second_value.each do |third_key, third_value|
477
+ third_key = third_key.to_sym
478
+
479
+ if third_key == :login_profile
480
+ new_third_value = {}
481
+ third_value.each {|k, v| new_third_value[k.to_sym] = v }
482
+ third_value = new_third_value
483
+ end
484
+
485
+ second_attrs[third_key] = third_value
486
+ end
487
+ end
488
+ end
489
+
490
+ normalized
491
+ end
411
492
  end
@@ -17,7 +17,7 @@ class Miam::Driver
17
17
  @iam.create_user(params)
18
18
  end
19
19
 
20
- new_user_attrs = {:groups => [], :policies => {}}
20
+ new_user_attrs = {:groups => [], :policies => {}, :attached_managed_policies => []}
21
21
  new_user_attrs[:path] = attrs[:path] if attrs[:path]
22
22
  new_user_attrs
23
23
  end
@@ -54,6 +54,10 @@ class Miam::Driver
54
54
  @iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
55
55
  end
56
56
 
57
+ attrs[:attached_managed_policies].each do |policy_arn|
58
+ @iam.detach_user_policy(:user_name => user_name, :policy_arn => policy_arn)
59
+ end
60
+
57
61
  list_access_key_ids(user_name).each do |access_key_id|
58
62
  @iam.delete_access_key(:user_name => user_name, :access_key_id => access_key_id)
59
63
  end
@@ -130,7 +134,7 @@ class Miam::Driver
130
134
  @iam.create_group(params)
131
135
  end
132
136
 
133
- new_group_attrs = {:policies => {}}
137
+ new_group_attrs = {:policies => {}, :attached_managed_policies => []}
134
138
  new_group_attrs[:path] = attrs[:path] if attrs[:path]
135
139
  new_group_attrs
136
140
  end
@@ -147,6 +151,10 @@ class Miam::Driver
147
151
  @iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
148
152
  end
149
153
 
154
+ attrs[:attached_managed_policies].each do |policy_arn|
155
+ @iam.detach_group_policy(:group_name => group_name, :policy_arn => policy_arn)
156
+ end
157
+
150
158
  @iam.delete_group(:group_name => group_name)
151
159
  end
152
160
  end
@@ -168,7 +176,8 @@ class Miam::Driver
168
176
  new_role_attrs = {
169
177
  :instance_profiles => [],
170
178
  :assume_role_policy_document => assume_role_policy_document,
171
- :policies => {}
179
+ :policies => {},
180
+ :attached_managed_policies => [],
172
181
  }
173
182
 
174
183
  new_role_attrs[:path] = attrs[:path] if attrs[:path]
@@ -187,6 +196,10 @@ class Miam::Driver
187
196
  @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
188
197
  end
189
198
 
199
+ attrs[:attached_managed_policies].each do |policy_arn|
200
+ @iam.detach_role_policy(:role_name => role_name, :policy_arn => policy_arn)
201
+ end
202
+
190
203
  @iam.delete_role(:role_name => role_name)
191
204
  end
192
205
  end
@@ -305,6 +318,34 @@ class Miam::Driver
305
318
  end
306
319
  end
307
320
 
321
+ def attach_policies(type, name, policies)
322
+ type = type.to_s
323
+ type_s = type.slice(0, 1).upcase + type.slice(1..-1)
324
+
325
+ log(:info, "Update #{type_s} `#{name}`", :color => :green)
326
+ log(:info, " attach policies=#{policies.join(',')}", :color => :green)
327
+
328
+ unless_dry_run do
329
+ policies.each do |arn|
330
+ @iam.send("attach_#{type}_policy", :"#{type}_name" => name, :policy_arn => arn)
331
+ end
332
+ end
333
+ end
334
+
335
+ def detach_policies(type, name, policies)
336
+ type = type.to_s
337
+ type_s = type.slice(0, 1).upcase + type.slice(1..-1)
338
+
339
+ log(:info, "Update #{type_s} `#{name}`", :color => :green)
340
+ log(:info, " detach policies=#{policies.join(',')}", :color => :green)
341
+
342
+ unless_dry_run do
343
+ policies.each do |arn|
344
+ @iam.send("detach_#{type}_policy", :"#{type}_name" => name, :policy_arn => arn)
345
+ end
346
+ end
347
+ end
348
+
308
349
  def list_access_key_ids(user_name)
309
350
  @iam.list_access_keys(:user_name => user_name).map {|resp|
310
351
  resp.access_key_metadata.map do |metadata|
@@ -1,7 +1,7 @@
1
1
  class Miam::DSL::Context::Group
2
2
  def initialize(name, &block)
3
3
  @group_name = name
4
- @result = {:policies => {}}
4
+ @result = {:policies => {}, :attached_managed_policies => []}
5
5
  instance_eval(&block)
6
6
  end
7
7
 
@@ -24,4 +24,8 @@ class Miam::DSL::Context::Group
24
24
 
25
25
  @result[:policies][name] = policy_document
26
26
  end
27
+
28
+ def attached_managed_policies(*policies)
29
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
30
+ end
27
31
  end
@@ -1,7 +1,7 @@
1
1
  class Miam::DSL::Context::Role
2
2
  def initialize(name, &block)
3
3
  @role_name = name
4
- @result = {:instance_profiles => [], :policies => {}}
4
+ @result = {:instance_profiles => [], :policies => {}, :attached_managed_policies => []}
5
5
  instance_eval(&block)
6
6
  end
7
7
 
@@ -16,7 +16,7 @@ class Miam::DSL::Context::Role
16
16
  private
17
17
 
18
18
  def instance_profiles(*profiles)
19
- @result[:instance_profiles].concat(profiles.map {|i| i.to_s })
19
+ @result[:instance_profiles].concat(profiles.map(&:to_s))
20
20
  end
21
21
 
22
22
  def assume_role_policy_document
@@ -48,4 +48,8 @@ class Miam::DSL::Context::Role
48
48
 
49
49
  @result[:policies][name] = policy_document
50
50
  end
51
+
52
+ def attached_managed_policies(*policies)
53
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
54
+ end
51
55
  end
@@ -1,7 +1,7 @@
1
1
  class Miam::DSL::Context::User
2
2
  def initialize(name, &block)
3
3
  @user_name = name
4
- @result = {:groups => [], :policies => {}}
4
+ @result = {:groups => [], :policies => {}, :attached_managed_policies => []}
5
5
  instance_eval(&block)
6
6
  end
7
7
 
@@ -14,7 +14,7 @@ class Miam::DSL::Context::User
14
14
  end
15
15
 
16
16
  def groups(*grps)
17
- @result[:groups].concat(grps.map {|i| i.to_s })
17
+ @result[:groups].concat(grps.map(&:to_s))
18
18
  end
19
19
 
20
20
  def policy(name)
@@ -32,4 +32,8 @@ class Miam::DSL::Context::User
32
32
 
33
33
  @result[:policies][name] = policy_document
34
34
  end
35
+
36
+ def attached_managed_policies(*policies)
37
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
38
+ end
35
39
  end
@@ -36,6 +36,8 @@ user #{user_name.inspect}, #{Miam::Utils.unbrace(user_options.inspect)} do
36
36
  #{output_user_groups(attrs[:groups])}
37
37
 
38
38
  #{output_policies(attrs[:policies])}
39
+
40
+ #{output_attached_managed_policies(attrs[:attached_managed_policies])}
39
41
  end
40
42
  EOS
41
43
  end
@@ -72,6 +74,8 @@ end
72
74
  <<-EOS
73
75
  group #{group_name.inspect}, #{Miam::Utils.unbrace(group_options.inspect)} do
74
76
  #{output_policies(attrs[:policies])}
77
+
78
+ #{output_attached_managed_policies(attrs[:attached_managed_policies])}
75
79
  end
76
80
  EOS
77
81
  end
@@ -93,6 +97,8 @@ role #{role_name.inspect}, #{Miam::Utils.unbrace(role_options.inspect)} do
93
97
  #{output_assume_role_policy_document(attrs[:assume_role_policy_document])}
94
98
 
95
99
  #{output_policies(attrs[:policies])}
100
+
101
+ #{output_attached_managed_policies(attrs[:attached_managed_policies])}
96
102
  end
97
103
  EOS
98
104
  end
@@ -155,6 +161,17 @@ instance_profile #{instance_profile_name.inspect}, #{Miam::Utils.unbrace(instanc
155
161
  EOS
156
162
  end
157
163
 
164
+ def output_attached_managed_policies(attached_managed_policies)
165
+ if attached_managed_policies.empty?
166
+ attached_managed_policies = ['# attached_managed_policy']
167
+ else
168
+ attached_managed_policies = attached_managed_policies.map {|i| i.inspect }
169
+ end
170
+
171
+ attached_managed_policies = "\n " + attached_managed_policies.join(",\n ") + "\n "
172
+ "attached_managed_policies(#{attached_managed_policies})"
173
+ end
174
+
158
175
  def target_matched?(name)
159
176
  if @options[:target]
160
177
  name =~ @options[:target]
@@ -52,6 +52,7 @@ class Miam::Exporter
52
52
  groups = user.group_list
53
53
  policies = export_user_policies(user)
54
54
  login_profile = export_login_profile(user_name)
55
+ attached_managed_policies = user.attached_managed_policies.map(&:policy_arn)
55
56
 
56
57
  @mutex.synchronize do
57
58
  groups.each do |group_name|
@@ -63,6 +64,7 @@ class Miam::Exporter
63
64
  :path => user.path,
64
65
  :groups => groups,
65
66
  :policies => policies,
67
+ :attached_managed_policies => attached_managed_policies
66
68
  }
67
69
 
68
70
  if login_profile
@@ -102,11 +104,13 @@ class Miam::Exporter
102
104
  Parallel.each(groups, :in_threads => @concurrency) do |group|
103
105
  group_name = group.group_name
104
106
  policies = export_group_policies(group)
107
+ attached_managed_policies = group.attached_managed_policies.map(&:policy_arn)
105
108
 
106
109
  @mutex.synchronize do
107
110
  result[group_name] = {
108
111
  :path => group.path,
109
112
  :policies => policies,
113
+ :attached_managed_policies => attached_managed_policies,
110
114
  }
111
115
 
112
116
  progress
@@ -134,6 +138,7 @@ class Miam::Exporter
134
138
  role_name = role.role_name
135
139
  instance_profiles = role.instance_profile_list.map {|i| i.instance_profile_name }
136
140
  policies = export_role_policies(role)
141
+ attached_managed_policies = role.attached_managed_policies.map(&:policy_arn)
137
142
 
138
143
  @mutex.synchronize do
139
144
  instance_profiles.each do |instance_profile_name|
@@ -148,6 +153,7 @@ class Miam::Exporter
148
153
  :assume_role_policy_document => JSON.parse(document),
149
154
  :instance_profiles => instance_profiles,
150
155
  :policies => policies,
156
+ :attached_managed_policies => attached_managed_policies,
151
157
  }
152
158
 
153
159
  progress
@@ -1,3 +1,3 @@
1
1
  module Miam
2
- VERSION = '0.2.1.beta'
2
+ VERSION = '0.2.1.beta2'
3
3
  end
@@ -20,12 +20,12 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_dependency 'aws-sdk-core', '~> 2.0.22'
23
+ spec.add_dependency 'aws-sdk-core', '~> 2.0.42'
24
24
  spec.add_dependency 'ruby-progressbar'
25
25
  spec.add_dependency 'parallel'
26
26
  spec.add_dependency 'term-ansicolor'
27
- spec.add_development_dependency 'bundler', '~> 1.7'
28
- spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake'
29
29
  spec.add_development_dependency 'rspec', '>= 3.0.0'
30
30
  spec.add_development_dependency 'rspec-instafail'
31
31
  spec.add_development_dependency 'coveralls'
@@ -0,0 +1,382 @@
1
+ describe 'attach/detach policy' do
2
+ let(:dsl) do
3
+ <<-RUBY
4
+ user "bob", :path=>"/devloper/" do
5
+ login_profile :password_reset_required=>true
6
+
7
+ groups(
8
+ "Admin",
9
+ "SES"
10
+ )
11
+
12
+ policy "S3" do
13
+ {"Statement"=>
14
+ [{"Action"=>
15
+ ["s3:Get*",
16
+ "s3:List*"],
17
+ "Effect"=>"Allow",
18
+ "Resource"=>"*"}]}
19
+ end
20
+
21
+ attached_managed_policies(
22
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
23
+ )
24
+ end
25
+
26
+ user "mary", :path=>"/staff/" do
27
+ policy "S3" do
28
+ {"Statement"=>
29
+ [{"Action"=>
30
+ ["s3:Get*",
31
+ "s3:List*"],
32
+ "Effect"=>"Allow",
33
+ "Resource"=>"*"}]}
34
+ end
35
+
36
+ attached_managed_policies(
37
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
38
+ )
39
+ end
40
+
41
+ group "Admin", :path=>"/admin/" do
42
+ policy "Admin" do
43
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
44
+ end
45
+
46
+ attached_managed_policies(
47
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
48
+ )
49
+ end
50
+
51
+ group "SES", :path=>"/ses/" do
52
+ policy "ses-policy" do
53
+ {"Statement"=>
54
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
55
+ end
56
+
57
+ attached_managed_policies(
58
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
59
+ )
60
+ end
61
+
62
+ role "my-role", :path=>"/any/" do
63
+ instance_profiles(
64
+ "my-instance-profile"
65
+ )
66
+
67
+ assume_role_policy_document do
68
+ {"Version"=>"2012-10-17",
69
+ "Statement"=>
70
+ [{"Sid"=>"",
71
+ "Effect"=>"Allow",
72
+ "Principal"=>{"Service"=>"ec2.amazonaws.com"},
73
+ "Action"=>"sts:AssumeRole"}]}
74
+ end
75
+
76
+ policy "role-policy" do
77
+ {"Statement"=>
78
+ [{"Action"=>
79
+ ["s3:Get*",
80
+ "s3:List*"],
81
+ "Effect"=>"Allow",
82
+ "Resource"=>"*"}]}
83
+ end
84
+
85
+ attached_managed_policies(
86
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
87
+ )
88
+ end
89
+
90
+ instance_profile "my-instance-profile", :path=>"/profile/"
91
+ RUBY
92
+ end
93
+
94
+ let(:expected) do
95
+ {:users=>
96
+ {"bob"=>
97
+ {:path=>"/devloper/",
98
+ :groups=>["Admin", "SES"],
99
+ :attached_managed_policies=>[
100
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"],
101
+ :policies=>
102
+ {"S3"=>
103
+ {"Statement"=>
104
+ [{"Action"=>["s3:Get*", "s3:List*"],
105
+ "Effect"=>"Allow",
106
+ "Resource"=>"*"}]}},
107
+ :login_profile=>{:password_reset_required=>true}},
108
+ "mary"=>
109
+ {:path=>"/staff/",
110
+ :groups=>[],
111
+ :attached_managed_policies=>[
112
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"],
113
+ :policies=>
114
+ {"S3"=>
115
+ {"Statement"=>
116
+ [{"Action"=>["s3:Get*", "s3:List*"],
117
+ "Effect"=>"Allow",
118
+ "Resource"=>"*"}]}}}},
119
+ :groups=>
120
+ {"Admin"=>
121
+ {:path=>"/admin/",
122
+ :attached_managed_policies=>[
123
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"],
124
+ :policies=>
125
+ {"Admin"=>
126
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
127
+ "SES"=>
128
+ {:path=>"/ses/",
129
+ :attached_managed_policies=>[
130
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"],
131
+ :policies=>
132
+ {"ses-policy"=>
133
+ {"Statement"=>
134
+ [{"Effect"=>"Allow",
135
+ "Action"=>"ses:SendRawEmail",
136
+ "Resource"=>"*"}]}}}},
137
+ :roles=>
138
+ {"my-role"=>
139
+ {:path=>"/any/",
140
+ :assume_role_policy_document=>
141
+ {"Version"=>"2012-10-17",
142
+ "Statement"=>
143
+ [{"Sid"=>"",
144
+ "Effect"=>"Allow",
145
+ "Principal"=>{"Service"=>"ec2.amazonaws.com"},
146
+ "Action"=>"sts:AssumeRole"}]},
147
+ :instance_profiles=>["my-instance-profile"],
148
+ :attached_managed_policies=>[
149
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"],
150
+ :policies=>
151
+ {"role-policy"=>
152
+ {"Statement"=>
153
+ [{"Action"=>["s3:Get*", "s3:List*"],
154
+ "Effect"=>"Allow",
155
+ "Resource"=>"*"}]}}}},
156
+ :instance_profiles=>{"my-instance-profile"=>{:path=>"/profile/"}}}
157
+ end
158
+
159
+ before(:each) do
160
+ apply { dsl }
161
+ end
162
+
163
+ context 'when no change' do
164
+ subject { client }
165
+
166
+ it do
167
+ updated = apply(subject) { dsl }
168
+ expect(updated).to be_falsey
169
+ expect(export).to eq expected
170
+ end
171
+ end
172
+
173
+ context 'when attach policy' do
174
+ let(:update_policy_dsl) do
175
+ <<-RUBY
176
+ user "bob", :path=>"/devloper/" do
177
+ login_profile :password_reset_required=>true
178
+
179
+ groups(
180
+ "Admin",
181
+ "SES"
182
+ )
183
+
184
+ policy "S3" do
185
+ {"Statement"=>
186
+ [{"Action"=>
187
+ ["s3:Get*",
188
+ "s3:List*"],
189
+ "Effect"=>"Allow",
190
+ "Resource"=>"*"}]}
191
+ end
192
+
193
+ attached_managed_policies(
194
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
195
+ )
196
+ end
197
+
198
+ user "mary", :path=>"/staff/" do
199
+ policy "S3" do
200
+ {"Statement"=>
201
+ [{"Action"=>
202
+ ["s3:Get*",
203
+ "s3:List*"],
204
+ "Effect"=>"Allow",
205
+ "Resource"=>"*"}]}
206
+ end
207
+
208
+ attached_managed_policies(
209
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess",
210
+ "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
211
+ )
212
+ end
213
+
214
+ group "Admin", :path=>"/admin/" do
215
+ policy "Admin" do
216
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
217
+ end
218
+
219
+ attached_managed_policies(
220
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
221
+ )
222
+ end
223
+
224
+ group "SES", :path=>"/ses/" do
225
+ policy "ses-policy" do
226
+ {"Statement"=>
227
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
228
+ end
229
+
230
+ attached_managed_policies(
231
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess",
232
+ "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
233
+ )
234
+ end
235
+
236
+ role "my-role", :path=>"/any/" do
237
+ instance_profiles(
238
+ "my-instance-profile"
239
+ )
240
+
241
+ assume_role_policy_document do
242
+ {"Version"=>"2012-10-17",
243
+ "Statement"=>
244
+ [{"Sid"=>"",
245
+ "Effect"=>"Allow",
246
+ "Principal"=>{"Service"=>"ec2.amazonaws.com"},
247
+ "Action"=>"sts:AssumeRole"}]}
248
+ end
249
+
250
+ policy "role-policy" do
251
+ {"Statement"=>
252
+ [{"Action"=>
253
+ ["s3:Get*",
254
+ "s3:List*"],
255
+ "Effect"=>"Allow",
256
+ "Resource"=>"*"}]}
257
+ end
258
+
259
+ attached_managed_policies(
260
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess",
261
+ "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
262
+ )
263
+ end
264
+
265
+ instance_profile "my-instance-profile", :path=>"/profile/"
266
+ RUBY
267
+ end
268
+
269
+ subject { client }
270
+
271
+ it do
272
+ updated = apply(subject) { update_policy_dsl }
273
+ expect(updated).to be_truthy
274
+ expected[:users]["mary"][:attached_managed_policies] << "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
275
+ expected[:groups]["SES"][:attached_managed_policies] << "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
276
+ expected[:roles]["my-role"][:attached_managed_policies] << "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
277
+ expect(export).to eq expected
278
+ end
279
+ end
280
+
281
+ context 'when detach policy' do
282
+ let(:update_policy_dsl) do
283
+ <<-RUBY
284
+ user "bob", :path=>"/devloper/" do
285
+ login_profile :password_reset_required=>true
286
+
287
+ groups(
288
+ "Admin",
289
+ "SES"
290
+ )
291
+
292
+ policy "S3" do
293
+ {"Statement"=>
294
+ [{"Action"=>
295
+ ["s3:Get*",
296
+ "s3:List*"],
297
+ "Effect"=>"Allow",
298
+ "Resource"=>"*"}]}
299
+ end
300
+
301
+ attached_managed_policies(
302
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
303
+ )
304
+ end
305
+
306
+ user "mary", :path=>"/staff/" do
307
+ policy "S3" do
308
+ {"Statement"=>
309
+ [{"Action"=>
310
+ ["s3:Get*",
311
+ "s3:List*"],
312
+ "Effect"=>"Allow",
313
+ "Resource"=>"*"}]}
314
+ end
315
+
316
+ attached_managed_policies(
317
+ )
318
+ end
319
+
320
+ group "Admin", :path=>"/admin/" do
321
+ policy "Admin" do
322
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
323
+ end
324
+
325
+ attached_managed_policies(
326
+ "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
327
+ )
328
+ end
329
+
330
+ group "SES", :path=>"/ses/" do
331
+ policy "ses-policy" do
332
+ {"Statement"=>
333
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
334
+ end
335
+
336
+ attached_managed_policies(
337
+ )
338
+ end
339
+
340
+ role "my-role", :path=>"/any/" do
341
+ instance_profiles(
342
+ "my-instance-profile"
343
+ )
344
+
345
+ assume_role_policy_document do
346
+ {"Version"=>"2012-10-17",
347
+ "Statement"=>
348
+ [{"Sid"=>"",
349
+ "Effect"=>"Allow",
350
+ "Principal"=>{"Service"=>"ec2.amazonaws.com"},
351
+ "Action"=>"sts:AssumeRole"}]}
352
+ end
353
+
354
+ policy "role-policy" do
355
+ {"Statement"=>
356
+ [{"Action"=>
357
+ ["s3:Get*",
358
+ "s3:List*"],
359
+ "Effect"=>"Allow",
360
+ "Resource"=>"*"}]}
361
+ end
362
+
363
+ attached_managed_policies(
364
+ )
365
+ end
366
+
367
+ instance_profile "my-instance-profile", :path=>"/profile/"
368
+ RUBY
369
+ end
370
+
371
+ subject { client }
372
+
373
+ it do
374
+ updated = apply(subject) { update_policy_dsl }
375
+ expect(updated).to be_truthy
376
+ expected[:users]["mary"][:attached_managed_policies].clear
377
+ expected[:groups]["SES"][:attached_managed_policies].clear
378
+ expected[:roles]["my-role"][:attached_managed_policies].clear
379
+ expect(export).to eq expected
380
+ end
381
+ end
382
+ end
@@ -93,6 +93,7 @@ describe 'create' do
93
93
  {"bob"=>
94
94
  {:path=>"/devloper/",
95
95
  :groups=>["Admin", "SES"],
96
+ :attached_managed_policies=>[],
96
97
  :policies=>
97
98
  {"S3"=>
98
99
  {"Statement"=>
@@ -103,6 +104,7 @@ describe 'create' do
103
104
  "mary"=>
104
105
  {:path=>"/staff/",
105
106
  :groups=>[],
107
+ :attached_managed_policies=>[],
106
108
  :policies=>
107
109
  {"S3"=>
108
110
  {"Statement"=>
@@ -112,11 +114,13 @@ describe 'create' do
112
114
  :groups=>
113
115
  {"Admin"=>
114
116
  {:path=>"/admin/",
117
+ :attached_managed_policies=>[],
115
118
  :policies=>
116
119
  {"Admin"=>
117
120
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
118
121
  "SES"=>
119
122
  {:path=>"/ses/",
123
+ :attached_managed_policies=>[],
120
124
  :policies=>
121
125
  {"ses-policy"=>
122
126
  {"Statement"=>
@@ -134,6 +138,7 @@ describe 'create' do
134
138
  "Principal"=>{"Service"=>"ec2.amazonaws.com"},
135
139
  "Action"=>"sts:AssumeRole"}]},
136
140
  :instance_profiles=>["my-instance-profile"],
141
+ :attached_managed_policies=>[],
137
142
  :policies=>
138
143
  {"role-policy"=>
139
144
  {"Statement"=>
@@ -76,6 +76,7 @@ describe 'delete' do
76
76
  {"bob"=>
77
77
  {:path=>"/devloper/",
78
78
  :groups=>["Admin", "SES"],
79
+ :attached_managed_policies=>[],
79
80
  :policies=>
80
81
  {"S3"=>
81
82
  {"Statement"=>
@@ -86,6 +87,7 @@ describe 'delete' do
86
87
  "mary"=>
87
88
  {:path=>"/staff/",
88
89
  :groups=>[],
90
+ :attached_managed_policies=>[],
89
91
  :policies=>
90
92
  {"S3"=>
91
93
  {"Statement"=>
@@ -95,11 +97,13 @@ describe 'delete' do
95
97
  :groups=>
96
98
  {"Admin"=>
97
99
  {:path=>"/admin/",
100
+ :attached_managed_policies=>[],
98
101
  :policies=>
99
102
  {"Admin"=>
100
103
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
101
104
  "SES"=>
102
105
  {:path=>"/ses/",
106
+ :attached_managed_policies=>[],
103
107
  :policies=>
104
108
  {"ses-policy"=>
105
109
  {"Statement"=>
@@ -117,6 +121,7 @@ describe 'delete' do
117
121
  "Principal"=>{"Service"=>"ec2.amazonaws.com"},
118
122
  "Action"=>"sts:AssumeRole"}]},
119
123
  :instance_profiles=>["my-instance-profile"],
124
+ :attached_managed_policies=>[],
120
125
  :policies=>
121
126
  {"role-policy"=>
122
127
  {"Statement"=>
@@ -76,6 +76,7 @@ describe 'update' do
76
76
  {"bob"=>
77
77
  {:path=>"/devloper/",
78
78
  :groups=>["Admin", "SES"],
79
+ :attached_managed_policies=>[],
79
80
  :policies=>
80
81
  {"S3"=>
81
82
  {"Statement"=>
@@ -86,6 +87,7 @@ describe 'update' do
86
87
  "mary"=>
87
88
  {:path=>"/staff/",
88
89
  :groups=>[],
90
+ :attached_managed_policies=>[],
89
91
  :policies=>
90
92
  {"S3"=>
91
93
  {"Statement"=>
@@ -95,11 +97,13 @@ describe 'update' do
95
97
  :groups=>
96
98
  {"Admin"=>
97
99
  {:path=>"/admin/",
100
+ :attached_managed_policies=>[],
98
101
  :policies=>
99
102
  {"Admin"=>
100
103
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
101
104
  "SES"=>
102
105
  {:path=>"/ses/",
106
+ :attached_managed_policies=>[],
103
107
  :policies=>
104
108
  {"ses-policy"=>
105
109
  {"Statement"=>
@@ -117,6 +121,7 @@ describe 'update' do
117
121
  "Principal"=>{"Service"=>"ec2.amazonaws.com"},
118
122
  "Action"=>"sts:AssumeRole"}]},
119
123
  :instance_profiles=>["my-instance-profile"],
124
+ :attached_managed_policies=>[],
120
125
  :policies=>
121
126
  {"role-policy"=>
122
127
  {"Statement"=>
@@ -76,6 +76,7 @@ describe 'update' do
76
76
  {"bob"=>
77
77
  {:path=>"/devloper/",
78
78
  :groups=>["Admin", "SES"],
79
+ :attached_managed_policies=>[],
79
80
  :policies=>
80
81
  {"S3"=>
81
82
  {"Statement"=>
@@ -86,6 +87,7 @@ describe 'update' do
86
87
  "mary"=>
87
88
  {:path=>"/staff/",
88
89
  :groups=>[],
90
+ :attached_managed_policies=>[],
89
91
  :policies=>
90
92
  {"S3"=>
91
93
  {"Statement"=>
@@ -95,11 +97,13 @@ describe 'update' do
95
97
  :groups=>
96
98
  {"Admin"=>
97
99
  {:path=>"/admin/",
100
+ :attached_managed_policies=>[],
98
101
  :policies=>
99
102
  {"Admin"=>
100
103
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
101
104
  "SES"=>
102
105
  {:path=>"/ses/",
106
+ :attached_managed_policies=>[],
103
107
  :policies=>
104
108
  {"ses-policy"=>
105
109
  {"Statement"=>
@@ -117,6 +121,7 @@ describe 'update' do
117
121
  "Principal"=>{"Service"=>"ec2.amazonaws.com"},
118
122
  "Action"=>"sts:AssumeRole"}]},
119
123
  :instance_profiles=>["my-instance-profile"],
124
+ :attached_managed_policies=>[],
120
125
  :policies=>
121
126
  {"role-policy"=>
122
127
  {"Statement"=>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1.beta
4
+ version: 0.2.1.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-16 00:00:00.000000000 Z
11
+ date: 2015-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.22
19
+ version: 2.0.42
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.22
26
+ version: 2.0.42
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ruby-progressbar
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -70,30 +70,30 @@ dependencies:
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
- version: '1.7'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
- version: '1.7'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - '>='
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - '>='
95
95
  - !ruby/object:Gem::Version
96
- version: '10.0'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -169,6 +169,7 @@ files:
169
169
  - lib/miam/utils.rb
170
170
  - lib/miam/version.rb
171
171
  - miam.gemspec
172
+ - spec/miam/attach_detach_policy_spec.rb
172
173
  - spec/miam/create_spec.rb
173
174
  - spec/miam/delete_spec.rb
174
175
  - spec/miam/rename_spec.rb
@@ -199,6 +200,7 @@ signing_key:
199
200
  specification_version: 4
200
201
  summary: Miam is a tool to manage IAM.
201
202
  test_files:
203
+ - spec/miam/attach_detach_policy_spec.rb
202
204
  - spec/miam/create_spec.rb
203
205
  - spec/miam/delete_spec.rb
204
206
  - spec/miam/rename_spec.rb