miam 0.2.1.beta → 0.2.1.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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