subiam 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,466 @@
1
+ class Subiam::Driver
2
+ include Subiam::Logger::Helper
3
+
4
+ MAX_POLICY_SIZE = 2048
5
+ MAX_POLICY_VERSIONS = 5
6
+
7
+ def initialize(iam, options = {})
8
+ @iam = iam
9
+ @options = options
10
+ end
11
+
12
+ def create_user(user_name, attrs)
13
+ log(:info, "Create User `#{user_name}`", :color => :cyan)
14
+
15
+ unless_dry_run do
16
+ params = {:user_name => user_name}
17
+ params[:path] = attrs[:path] if attrs[:path]
18
+ @iam.create_user(params)
19
+ end
20
+
21
+ new_user_attrs = {:groups => [], :policies => {}, :attached_managed_policies => []}
22
+ new_user_attrs[:path] = attrs[:path] if attrs[:path]
23
+ new_user_attrs
24
+ end
25
+
26
+ def create_access_key(user_name)
27
+ log(:info, "Create access key for User `#{user_name}`", :color => :cyan)
28
+ access_key = nil
29
+
30
+ unless_dry_run do
31
+ resp = @iam.create_access_key(:user_name => user_name)
32
+
33
+ access_key = {
34
+ :access_key_id => resp.access_key.access_key_id,
35
+ :secret_access_key => resp.access_key.secret_access_key,
36
+ }
37
+ end
38
+
39
+ access_key
40
+ end
41
+
42
+ def delete_user(user_name, attrs)
43
+ log(:info, "Delete User `#{user_name}`", :color => :red)
44
+
45
+ unless_dry_run do
46
+ if attrs[:login_profile]
47
+ @iam.delete_login_profile(:user_name => user_name)
48
+ end
49
+
50
+ attrs[:policies].keys.each do |policy_name|
51
+ @iam.delete_user_policy(:user_name => user_name, :policy_name => policy_name)
52
+ end
53
+
54
+ attrs[:groups].each do |group_name|
55
+ @iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
56
+ end
57
+
58
+ attrs[:attached_managed_policies].each do |policy_arn|
59
+ @iam.detach_user_policy(:user_name => user_name, :policy_arn => policy_arn)
60
+ end
61
+
62
+ list_access_key_ids(user_name).each do |access_key_id|
63
+ @iam.delete_access_key(:user_name => user_name, :access_key_id => access_key_id)
64
+ end
65
+
66
+ list_signing_certificate_ids(user_name).each do |certificate_id|
67
+ @iam.delete_signing_certificate(:user_name => user_name, :certificate_id => certificate_id)
68
+ end
69
+
70
+ @iam.delete_user(:user_name => user_name)
71
+ end
72
+ end
73
+
74
+ def create_login_profile(user_name, attrs)
75
+ log_attrs = attrs.dup
76
+ log_attrs.delete(:password)
77
+
78
+ log(:info, "Update User `#{user_name}`", :color => :green)
79
+ log(:info, " create login profile: #{log_attrs.inspect}", :color => :green)
80
+
81
+ unless_dry_run do
82
+ @iam.create_login_profile(attrs.merge(:user_name => user_name))
83
+ end
84
+ end
85
+
86
+ def delete_login_profile(user_name)
87
+ log(:info, "Update User `#{user_name}`", :color => :green)
88
+ log(:info, " delete login profile", :color => :green)
89
+
90
+ unless_dry_run do
91
+ @iam.delete_login_profile(:user_name => user_name)
92
+ end
93
+ end
94
+
95
+ def update_login_profile(user_name, attrs, old_attrs)
96
+ log_attrs = attrs.dup
97
+ log_attrs.delete(:password)
98
+
99
+ log(:info, "Update User `#{user_name}`", :color => :green)
100
+ log(:info, " login profile:\n".green + Subiam::Utils.diff(old_attrs, attrs, :color => @options[:color], :indent => ' '), :color => false)
101
+
102
+ unless_dry_run do
103
+ @iam.update_login_profile(attrs.merge(:user_name => user_name))
104
+ end
105
+ end
106
+
107
+ def add_user_to_groups(user_name, group_names)
108
+ log(:info, "Update User `#{user_name}`", :color => :green)
109
+ log(:info, " add groups=#{group_names.join(',')}", :color => :green)
110
+
111
+ unless_dry_run do
112
+ group_names.each do |group_name|
113
+ @iam.add_user_to_group(:group_name => group_name, :user_name => user_name)
114
+ end
115
+ end
116
+ end
117
+
118
+ def remove_user_from_groups(user_name, group_names)
119
+ log(:info, "Update User `#{user_name}`", :color => :green)
120
+ log(:info, " remove groups=#{group_names.join(',')}", :color => :green)
121
+
122
+ unless_dry_run do
123
+ group_names.each do |group_name|
124
+ @iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
125
+ end
126
+ end
127
+ end
128
+
129
+ def create_group(group_name, attrs)
130
+ log(:info, "Create Group `#{group_name}`", :color => :cyan)
131
+
132
+ unless_dry_run do
133
+ params = {:group_name => group_name}
134
+ params[:path] = attrs[:path] if attrs[:path]
135
+ @iam.create_group(params)
136
+ end
137
+
138
+ new_group_attrs = {:policies => {}, :attached_managed_policies => []}
139
+ new_group_attrs[:path] = attrs[:path] if attrs[:path]
140
+ new_group_attrs
141
+ end
142
+
143
+ def delete_group(group_name, attrs, users_in_group)
144
+ log(:info, "Delete Group `#{group_name}`", :color => :red)
145
+
146
+ unless_dry_run do
147
+ attrs[:policies].keys.each do |policy_name|
148
+ @iam.delete_group_policy(:group_name => group_name, :policy_name => policy_name)
149
+ end
150
+
151
+ users_in_group.each do |user_name|
152
+ @iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
153
+ end
154
+
155
+ attrs[:attached_managed_policies].each do |policy_arn|
156
+ @iam.detach_group_policy(:group_name => group_name, :policy_arn => policy_arn)
157
+ end
158
+
159
+ @iam.delete_group(:group_name => group_name)
160
+ end
161
+ end
162
+
163
+ def create_role(role_name, attrs)
164
+ log(:info, "Create Role `#{role_name}`", :color => :cyan)
165
+ assume_role_policy_document = attrs.fetch(:assume_role_policy_document)
166
+
167
+ unless_dry_run do
168
+ params = {
169
+ :role_name => role_name,
170
+ :assume_role_policy_document => encode_document(assume_role_policy_document),
171
+ }
172
+
173
+ params[:path] = attrs[:path] if attrs[:path]
174
+ @iam.create_role(params)
175
+ end
176
+
177
+ new_role_attrs = {
178
+ :instance_profiles => [],
179
+ :assume_role_policy_document => assume_role_policy_document,
180
+ :policies => {},
181
+ :attached_managed_policies => [],
182
+ }
183
+
184
+ new_role_attrs[:path] = attrs[:path] if attrs[:path]
185
+ new_role_attrs
186
+ end
187
+
188
+ def delete_role(role_name, instance_profile_names, attrs)
189
+ log(:info, "Delete Role `#{role_name}`", :color => :red)
190
+
191
+ unless_dry_run do
192
+ attrs[:policies].keys.each do |policy_name|
193
+ @iam.delete_role_policy(:role_name => role_name, :policy_name => policy_name)
194
+ end
195
+
196
+ instance_profile_names.each do |instance_profile_name|
197
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
198
+ end
199
+
200
+ attrs[:attached_managed_policies].each do |policy_arn|
201
+ @iam.detach_role_policy(:role_name => role_name, :policy_arn => policy_arn)
202
+ end
203
+
204
+ @iam.delete_role(:role_name => role_name)
205
+ end
206
+ end
207
+
208
+ def add_role_to_instance_profiles(role_name, instance_profile_names)
209
+ log(:info, "Update Role `#{role_name}`", :color => :green)
210
+ log(:info, " add instance_profiles=#{instance_profile_names.join(',')}", :color => :green)
211
+
212
+ unless_dry_run do
213
+ instance_profile_names.each do |instance_profile_name|
214
+ @iam.add_role_to_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
215
+ end
216
+ end
217
+ end
218
+
219
+ def remove_role_from_instance_profiles(role_name, instance_profile_names)
220
+ log(:info, "Update Role `#{role_name}`", :color => :green)
221
+ log(:info, " remove instance_profiles=#{instance_profile_names.join(',')}", :color => :green)
222
+
223
+ unless_dry_run do
224
+ instance_profile_names.each do |instance_profile_name|
225
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
226
+ end
227
+ end
228
+ end
229
+
230
+ def update_assume_role_policy(role_name, policy_document, old_policy_document)
231
+ log(:info, "Update Role `#{role_name}` > AssumeRolePolicy", :color => :green)
232
+ log(:info, Subiam::Utils.diff(old_policy_document, policy_document, :color => @options[:color]), :color => false)
233
+
234
+ unless_dry_run do
235
+ @iam.update_assume_role_policy(
236
+ :role_name => role_name,
237
+ :policy_document => encode_document(policy_document),
238
+ )
239
+ end
240
+ end
241
+
242
+ def create_instance_profile(instance_profile_name, attrs)
243
+ log(:info, "Create InstanceProfile `#{instance_profile_name}`", :color => :cyan)
244
+
245
+ unless_dry_run do
246
+ params = {:instance_profile_name => instance_profile_name}
247
+ params[:path] = attrs[:path] if attrs[:path]
248
+ @iam.create_instance_profile(params)
249
+ end
250
+
251
+ new_instance_profile_attrs = {}
252
+ new_instance_profile_attrs[:path] = attrs[:path] if attrs[:path]
253
+ new_instance_profile_attrs
254
+ end
255
+
256
+ def delete_instance_profile(instance_profile_name, attrs, roles_in_instance_profile)
257
+ log(:info, "Delete InstanceProfile `#{instance_profile_name}`", :color => :red)
258
+
259
+ unless_dry_run do
260
+ roles_in_instance_profile.each do |role_name|
261
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
262
+ end
263
+
264
+ @iam.delete_instance_profile(:instance_profile_name => instance_profile_name)
265
+ end
266
+ end
267
+
268
+ def update_name(type, user_or_group_name, new_name)
269
+ log(:info, "Update #{Subiam::Utils.camelize(type.to_s)} `#{user_or_group_name}`", :color => :green)
270
+ log(:info, " name:\n".green + Subiam::Utils.diff(user_or_group_name, new_name, :color => @options[:color], :indent => ' '), :color => false)
271
+ update_user_or_group(type, user_or_group_name, "new_#{type}_name".to_sym => new_name)
272
+ end
273
+
274
+ def update_path(type, user_or_group_name, new_path, old_path)
275
+ log(:info, "Update #{Subiam::Utils.camelize(type.to_s)} `#{user_or_group_name}`", :color => :green)
276
+ log(:info, " path:\n".green + Subiam::Utils.diff(old_path, new_path, :color => @options[:color], :indent => ' '), :color => false)
277
+ update_user_or_group(type, user_or_group_name, :new_path => new_path)
278
+ end
279
+
280
+ def update_user_or_group(type, user_or_group_name, params)
281
+ unless_dry_run do
282
+ params["#{type}_name".to_sym] = user_or_group_name
283
+ @iam.send("update_#{type}", params)
284
+ end
285
+ end
286
+
287
+ def create_policy(type, user_or_group_name, policy_name, policy_document)
288
+ log(:info, "Create #{Subiam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`", :color => :cyan)
289
+ log(:info, " #{policy_document.pretty_inspect.gsub("\n", "\n ").strip}", :color => :cyan)
290
+ put_policy(type, user_or_group_name, policy_name, policy_document)
291
+ end
292
+
293
+ def update_policy(type, user_or_group_name, policy_name, policy_document, old_policy_document)
294
+ log(:info, "Update #{Subiam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`", :color => :green)
295
+ log(:info, Subiam::Utils.diff(old_policy_document, policy_document, :color => @options[:color]), :color => false)
296
+ put_policy(type, user_or_group_name, policy_name, policy_document)
297
+ end
298
+
299
+ def delete_policy(type, user_or_group_name, policy_name)
300
+ logmsg = "Delete #{Subiam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`"
301
+ log(:info, logmsg, :color => :red)
302
+
303
+ unless_dry_run do
304
+ params = {:policy_name => policy_name}
305
+ params["#{type}_name".to_sym] = user_or_group_name
306
+ @iam.send("delete_#{type}_policy", params)
307
+ end
308
+ end
309
+
310
+ def put_policy(type, user_or_group_name, policy_name, policy_document)
311
+ unless_dry_run do
312
+ params = {
313
+ :policy_name => policy_name,
314
+ :policy_document => encode_document(policy_document),
315
+ }
316
+
317
+ params["#{type}_name".to_sym] = user_or_group_name
318
+ @iam.send("put_#{type}_policy", params)
319
+ end
320
+ end
321
+
322
+ def attach_policies(type, name, policies)
323
+ type = type.to_s
324
+ type_s = type.slice(0, 1).upcase + type.slice(1..-1)
325
+
326
+ log(:info, "Update #{type_s} `#{name}`", :color => :green)
327
+ log(:info, " attach policies=#{policies.join(',')}", :color => :green)
328
+
329
+ unless_dry_run do
330
+ policies.each do |arn|
331
+ @iam.send("attach_#{type}_policy", :"#{type}_name" => name, :policy_arn => arn)
332
+ end
333
+ end
334
+ end
335
+
336
+ def detach_policies(type, name, policies)
337
+ type = type.to_s
338
+ type_s = type.slice(0, 1).upcase + type.slice(1..-1)
339
+
340
+ log(:info, "Update #{type_s} `#{name}`", :color => :green)
341
+ log(:info, " detach policies=#{policies.join(',')}", :color => :green)
342
+
343
+ unless_dry_run do
344
+ policies.each do |arn|
345
+ @iam.send("detach_#{type}_policy", :"#{type}_name" => name, :policy_arn => arn)
346
+ end
347
+ end
348
+ end
349
+
350
+ def list_access_key_ids(user_name)
351
+ @iam.list_access_keys(:user_name => user_name).map {|resp|
352
+ resp.access_key_metadata.map do |metadata|
353
+ metadata.access_key_id
354
+ end
355
+ }.flatten
356
+ end
357
+
358
+ def list_signing_certificate_ids(user_name)
359
+ @iam.list_signing_certificates(:user_name => user_name).map {|resp|
360
+ resp.certificates.map do |cert|
361
+ cert.certificate_id
362
+ end
363
+ }.flatten
364
+ end
365
+
366
+ def create_managed_policy(policy_name, attrs)
367
+ log(:info, "Create ManagedPolicy `#{policy_name}`", :color => :cyan)
368
+
369
+ unless_dry_run do
370
+ params = {
371
+ :policy_name => policy_name,
372
+ :path => attrs[:path],
373
+ :policy_document => encode_document(attrs[:document]),
374
+ }
375
+
376
+ @iam.create_policy(params)
377
+ end
378
+ end
379
+
380
+ def delete_managed_policy(policy_name)
381
+ log(:info, "Delete ManagedPolicy `#{policy_name}`", :color => :red)
382
+
383
+ unless_dry_run do
384
+ policy_versions = @iam.list_policy_versions(
385
+ :policy_arn => policy_arn(policy_name),
386
+ :max_items => MAX_POLICY_VERSIONS
387
+ )
388
+
389
+ policy_versions.versions.reject {|pv|
390
+ pv.is_default_version
391
+ }.each {|pv|
392
+ @iam.delete_policy_version(
393
+ :policy_arn => policy_arn(policy_name),
394
+ :version_id => pv.version_id
395
+ )
396
+ }
397
+
398
+ @iam.delete_policy(
399
+ :policy_arn => policy_arn(policy_name)
400
+ )
401
+ end
402
+ end
403
+
404
+ def update_managed_policy(policy_name, policy_document, old_policy_document)
405
+ log(:info, "Update ManagedPolicy `#{policy_name}`", :color => :green)
406
+ log(:info, Subiam::Utils.diff(old_policy_document, policy_document, :color => @options[:color]), :color => false)
407
+
408
+ unless_dry_run do
409
+ policy_versions = @iam.list_policy_versions(
410
+ :policy_arn => policy_arn(policy_name),
411
+ :max_items => MAX_POLICY_VERSIONS
412
+ )
413
+
414
+ if policy_versions.versions.length >= MAX_POLICY_VERSIONS
415
+ delete_policy_version = policy_versions.versions.reject {|pv|
416
+ pv.is_default_version
417
+ }.sort_by {|pv| pv.version_id[1..-1].to_i }.first
418
+
419
+ @iam.delete_policy_version(
420
+ :policy_arn => policy_arn(policy_name),
421
+ :version_id => delete_policy_version.version_id
422
+ )
423
+ end
424
+
425
+ @iam.create_policy_version(
426
+ :policy_arn => policy_arn(policy_name),
427
+ :policy_document => encode_document(policy_document),
428
+ set_as_default: true
429
+ )
430
+ end
431
+ end
432
+
433
+ private
434
+
435
+ def encode_document(policy_document)
436
+ if @options[:disable_form_json]
437
+ JSON.dump(policy_document)
438
+ else
439
+ encoded = JSON.pretty_generate(policy_document)
440
+
441
+ if Subiam::Utils.bytesize(encoded) > MAX_POLICY_SIZE
442
+ encoded = JSON.pretty_generate(policy_document)
443
+ encoded = encoded.gsub(/^\s+/m, '').strip
444
+ end
445
+
446
+ if Subiam::Utils.bytesize(encoded) > MAX_POLICY_SIZE
447
+ encoded = JSON.dump(policy_document)
448
+ end
449
+
450
+ encoded
451
+ end
452
+ end
453
+
454
+ def unless_dry_run
455
+ yield unless @options[:dry_run]
456
+ end
457
+
458
+ def account_id
459
+ # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
460
+ @account_id ||= @iam.get_user.user.arn.split(':').fetch(4)
461
+ end
462
+
463
+ def policy_arn(policy_name)
464
+ "arn:aws:iam::#{account_id}:policy/#{policy_name}"
465
+ end
466
+ end
@@ -0,0 +1,35 @@
1
+ class Subiam::DSL::Context::Group
2
+ include Subiam::TemplateHelper
3
+ include Subiam::DSL::Helper::Arn
4
+
5
+ def initialize(context, name, &block)
6
+ @group_name = name
7
+ @context = context.merge(:group_name => name)
8
+ @result = {:policies => {}, :attached_managed_policies => []}
9
+ instance_eval(&block)
10
+ end
11
+
12
+ attr_reader :result
13
+
14
+ private
15
+
16
+ def policy(name)
17
+ name = name.to_s
18
+
19
+ if @result[:policies][name]
20
+ raise "Group `#{@group_name}` > Policy `#{name}`: already defined"
21
+ end
22
+
23
+ policy_document = yield
24
+
25
+ unless policy_document.kind_of?(Hash)
26
+ raise "Group `#{@group_name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
27
+ end
28
+
29
+ @result[:policies][name] = policy_document.keys_to_s_recursive
30
+ end
31
+
32
+ def attached_managed_policies(*policies)
33
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ class Subiam::DSL::Context::ManagedPolicy
2
+ include Subiam::TemplateHelper
3
+
4
+ def initialize(context, name, &block)
5
+ @policy_name = name
6
+ @context = context.merge(:policy_name => name)
7
+ @result = {:document => get_document(block)}
8
+ end
9
+
10
+ attr_reader :result
11
+
12
+ private
13
+
14
+ def get_document(block)
15
+ document = instance_eval(&block)
16
+
17
+ unless document.kind_of?(Hash)
18
+ raise "ManagedPolicy `#{@policy_name}`: wrong argument type #{document.class} (expected Hash)"
19
+ end
20
+
21
+ document.keys_to_s_recursive
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ class Subiam::DSL::Context::Role
2
+ include Subiam::TemplateHelper
3
+ include Subiam::DSL::Helper::Arn
4
+
5
+ def initialize(context, name, &block)
6
+ @role_name = name
7
+ @context = context.merge(:role_name => name)
8
+ @result = {:instance_profiles => [], :policies => {}, :attached_managed_policies => []}
9
+ instance_eval(&block)
10
+ end
11
+
12
+ def result
13
+ unless @result[:assume_role_policy_document]
14
+ raise "Role `#{@role_name}`: AssumeRolePolicyDocument is not defined"
15
+ end
16
+
17
+ @result
18
+ end
19
+
20
+ private
21
+
22
+ def instance_profiles(*profiles)
23
+ @result[:instance_profiles].concat(profiles.map(&:to_s))
24
+ end
25
+
26
+ def assume_role_policy_document
27
+ if @result[:assume_role_policy_document]
28
+ raise "Role `#{@role_name}` > AssumeRolePolicyDocument: already defined"
29
+ end
30
+
31
+ assume_role_policy_document = yield
32
+
33
+ unless assume_role_policy_document.kind_of?(Hash)
34
+ raise "Role `#{@role_name}` > AssumeRolePolicyDocument: wrong argument type #{policy_document.class} (expected Hash)"
35
+ end
36
+
37
+ @result[:assume_role_policy_document] = assume_role_policy_document.keys_to_s_recursive
38
+ end
39
+
40
+ def policy(name)
41
+ name = name.to_s
42
+
43
+ if @result[:policies][name]
44
+ raise "Role `#{@role_name}` > Policy `#{name}`: already defined"
45
+ end
46
+
47
+ policy_document = yield
48
+
49
+ unless policy_document.kind_of?(Hash)
50
+ raise "Role `#{@role_name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
51
+ end
52
+
53
+ @result[:policies][name] = policy_document.keys_to_s_recursive
54
+ end
55
+
56
+ def attached_managed_policies(*policies)
57
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
58
+ end
59
+ end
@@ -0,0 +1,43 @@
1
+ class Subiam::DSL::Context::User
2
+ include Subiam::TemplateHelper
3
+ include Subiam::DSL::Helper::Arn
4
+
5
+ def initialize(context, name, &block)
6
+ @user_name = name
7
+ @context = context.merge(:user_name => name)
8
+ @result = {:groups => [], :policies => {}, :attached_managed_policies => []}
9
+ instance_eval(&block)
10
+ end
11
+
12
+ attr_reader :result
13
+
14
+ private
15
+
16
+ def login_profile(value)
17
+ @result[:login_profile] = value
18
+ end
19
+
20
+ def groups(*grps)
21
+ @result[:groups].concat(grps.map(&:to_s))
22
+ end
23
+
24
+ def policy(name)
25
+ name = name.to_s
26
+
27
+ if @result[:policies][name]
28
+ raise "User `#{@user_name}` > Policy `#{name}`: already defined"
29
+ end
30
+
31
+ policy_document = yield
32
+
33
+ unless policy_document.kind_of?(Hash)
34
+ raise "User `#{@user_name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
35
+ end
36
+
37
+ @result[:policies][name] = policy_document.keys_to_s_recursive
38
+ end
39
+
40
+ def attached_managed_policies(*policies)
41
+ @result[:attached_managed_policies].concat(policies.map(&:to_s))
42
+ end
43
+ end