miam 0.2.3 → 0.2.4.beta11

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: bb232253b3506a0387caa0817c099a76b0d5ec5f
4
- data.tar.gz: e10d873066aef538049bb703bf2977064c1ab586
3
+ metadata.gz: 9138483028ecd9f31271ee0104cc8315c3c2761d
4
+ data.tar.gz: 3d4561d7d711aa87e8476889638d2ecfb3f209f3
5
5
  SHA512:
6
- metadata.gz: d07415f6abcf2efa6d0572bf61302ee6d5334cc76f2a7739dbde62cf8b3b0cc0ceece4cf9613bbcc66776e0ad3758bfb5cf75196a286cfe47d95de467f02fa33
7
- data.tar.gz: eb2ecd520a5d43173249082dfdb29dd0b31fa36acc254cb356a57b04d9dd2befc4caaae70f4a7376189ffda32395b425195f7f014c0f223501dc1ac96d324f9b
6
+ metadata.gz: 83cc09da8add9757a5069ffe4b157faef21426e25b9573af06ad97dbe439aaa6bc10f04ae43dc5150bfd1651b9b5181ef0a6856c9f40001ad085ff393029f126
7
+ data.tar.gz: 44b226fc05224222876d99fe7f767c929f4e33d089e2ec7a8d69fe0d2b86c54f4c7200e0778e779565f0ae98251fa9bfe72765cf158ec80d0dbc073bd2e74777
data/.rspec CHANGED
@@ -1,4 +1,5 @@
1
1
  --require rspec/instafail
2
- --format RSpec::Instafail
2
+ --format documentation
3
+ #RSpec::Instafail
3
4
  --colour
4
5
  --require spec_helper
data/.travis.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.0.0
4
+ - 2.3.3
5
5
  script:
6
6
  - bundle install
7
- - bundle exec rake
7
+ - travis_wait bundle exec rake
8
8
  env:
9
9
  global:
10
10
  - secure: "Ec8bwSfp06anSzLJpGhkKjPz9EocMwl7H8t2LKoI3bKV/cz9JU0GhhUdUUmg3mCFH9+8/YGLzcbFKcxZIqnDK7ukdgTGsnGDevnctis0QwM7/nKHdkaK8JWhCx41TUXOqoiCKkNEnm1EbDtrILt4rJwb0BGXGnPjv6nLAyvdE2Y="
data/README.md CHANGED
@@ -22,6 +22,12 @@ It defines the state of IAM using DSL, and updates IAM according to DSL.
22
22
  * Sort policy array
23
23
  * `>= 0.2.3`
24
24
  * Support Custom Managed Policy
25
+ * `>= 0.2.4`
26
+ * Fix for Password Policy ([RP#22](https://github.com/winebarrel/miam/pull/22))
27
+ * Fix `--target` option for Policies ([RP#21](https://github.com/winebarrel/miam/pull/21))
28
+ * Fix for `Rate exceeded` ([PR#23](https://github.com/winebarrel/miam/pull/23))
29
+ * Fix for non-User credentials ([PR#17](https://github.com/winebarrel/miam/pull/17))
30
+ * Add `--exclude` option
25
31
 
26
32
  ## Installation
27
33
 
@@ -71,6 +77,7 @@ Usage: miam [options]
71
77
  --format=FORMAT
72
78
  --export-concurrency N
73
79
  --target REGEXP
80
+ --exclude REGEXP
74
81
  --ignore-login-profile
75
82
  --no-color
76
83
  --no-progress
data/bin/miam CHANGED
@@ -52,6 +52,7 @@ ARGV.options do |opt|
52
52
  opt.on('', '--format=FORMAT', [:ruby, :json]) {|v| format_passed = true; options[:format] = v }
53
53
  opt.on('' , '--export-concurrency N', Integer) {|v| options[:export_concurrency] = v }
54
54
  opt.on('' , '--target REGEXP') {|v| options[:target] = Regexp.new(v) }
55
+ opt.on('' , '--exclude REGEXP') {|v| options[:exclude] = Regexp.new(v) }
55
56
  opt.on('' , '--ignore-login-profile') { options[:ignore_login_profile] = true }
56
57
  opt.on('' , '--no-color') { options[:color] = false }
57
58
  opt.on('' , '--no-progress') { options[:no_progress] = true }
data/lib/miam/client.rb CHANGED
@@ -5,7 +5,8 @@ class Miam::Client
5
5
  @options = {:format => :ruby}.merge(options)
6
6
  aws_config = options.delete(:aws_config) || {}
7
7
  @iam = Aws::IAM::Client.new(aws_config)
8
- @driver = Miam::Driver.new(@iam, options)
8
+ @sts = Aws::STS::Client.new(aws_config)
9
+ @driver = Miam::Driver.new(@iam, @sts, options)
9
10
  @password_manager = options[:password_manager] || Miam::PasswordManager.new('-', options)
10
11
  end
11
12
 
@@ -129,7 +130,7 @@ class Miam::Client
129
130
  end
130
131
 
131
132
  if expected_login_profile and not actual_login_profile
132
- expected_login_profile[:password] ||= @password_manager.identify(user_name, :login_profile)
133
+ expected_login_profile[:password] ||= @password_manager.identify(user_name, :login_profile, @driver.password_policy)
133
134
  @driver.create_login_profile(user_name, expected_login_profile)
134
135
  updated = true
135
136
  elsif not expected_login_profile and actual_login_profile
@@ -445,6 +446,7 @@ class Miam::Client
445
446
  updated = false
446
447
 
447
448
  expected.each do |policy_name, expected_attrs|
449
+ next unless target_matched?(policy_name)
448
450
  actual_attrs = actual.delete(policy_name)
449
451
 
450
452
  if actual_attrs
@@ -452,7 +454,7 @@ class Miam::Client
452
454
  log(:warn, "ManagedPolicy `#{policy_name}`: 'path' cannot be updated", :color => :yellow)
453
455
  end
454
456
 
455
- updated = walk_managed_policy(policy_name, expected_attrs[:document], actual_attrs[:document]) || updated
457
+ updated = walk_managed_policy(policy_name, actual_attrs[:path], expected_attrs[:document], actual_attrs[:document]) || updated
456
458
  else
457
459
  @driver.create_managed_policy(policy_name, expected_attrs)
458
460
  updated = true
@@ -462,13 +464,13 @@ class Miam::Client
462
464
  updated
463
465
  end
464
466
 
465
- def walk_managed_policy(policy_name, expected_document, actual_document)
467
+ def walk_managed_policy(policy_name, policy_path, expected_document, actual_document)
466
468
  updated = false
467
469
  expected_document.sort_array!
468
470
  actual_document.sort_array!
469
471
 
470
472
  if expected_document != actual_document
471
- @driver.update_managed_policy(policy_name, expected_document, actual_document)
473
+ @driver.update_managed_policy(policy_name, policy_path, expected_document, actual_document)
472
474
  updated = true
473
475
  end
474
476
 
@@ -479,7 +481,8 @@ class Miam::Client
479
481
  updated = false
480
482
 
481
483
  actual.each do |policy_name, actual_attrs|
482
- @driver.delete_managed_policy(policy_name)
484
+ next unless target_matched?(policy_name)
485
+ @driver.delete_managed_policy(policy_name, actual_attrs[:path])
483
486
  updated = true
484
487
  end
485
488
 
@@ -505,11 +508,17 @@ class Miam::Client
505
508
  end
506
509
 
507
510
  def target_matched?(name)
511
+ result = true
512
+
513
+ if @options[:exclude]
514
+ result &&= name !~ @options[:exclude]
515
+ end
516
+
508
517
  if @options[:target]
509
- name =~ @options[:target]
510
- else
511
- true
518
+ result &&= name =~ @options[:target]
512
519
  end
520
+
521
+ result
513
522
  end
514
523
 
515
524
  def exec_by_format(proc_by_format)
data/lib/miam/driver.rb CHANGED
@@ -4,9 +4,11 @@ class Miam::Driver
4
4
  MAX_POLICY_SIZE = 2048
5
5
  MAX_POLICY_VERSIONS = 5
6
6
 
7
- def initialize(iam, options = {})
7
+ def initialize(iam, sts, options = {})
8
8
  @iam = iam
9
+ @sts = sts
9
10
  @options = options
11
+ @account_id = nil
10
12
  end
11
13
 
12
14
  def create_user(user_name, attrs)
@@ -67,6 +69,14 @@ class Miam::Driver
67
69
  @iam.delete_signing_certificate(:user_name => user_name, :certificate_id => certificate_id)
68
70
  end
69
71
 
72
+ mfa_devices = @iam.list_mfa_devices(:user_name => user_name).map {|resp|
73
+ resp.mfa_devices
74
+ }.flatten
75
+
76
+ mfa_devices.each do |md|
77
+ @iam.deactivate_mfa_device(:user_name => user_name, :serial_number => md.serial_number)
78
+ end
79
+
70
80
  @iam.delete_user(:user_name => user_name)
71
81
  end
72
82
  end
@@ -377,12 +387,12 @@ class Miam::Driver
377
387
  end
378
388
  end
379
389
 
380
- def delete_managed_policy(policy_name)
390
+ def delete_managed_policy(policy_name, policy_path)
381
391
  log(:info, "Delete ManagedPolicy `#{policy_name}`", :color => :red)
382
392
 
383
393
  unless_dry_run do
384
394
  policy_versions = @iam.list_policy_versions(
385
- :policy_arn => policy_arn(policy_name),
395
+ :policy_arn => policy_arn(policy_name, policy_path),
386
396
  :max_items => MAX_POLICY_VERSIONS
387
397
  )
388
398
 
@@ -390,24 +400,24 @@ class Miam::Driver
390
400
  pv.is_default_version
391
401
  }.each {|pv|
392
402
  @iam.delete_policy_version(
393
- :policy_arn => policy_arn(policy_name),
403
+ :policy_arn => policy_arn(policy_name, policy_path),
394
404
  :version_id => pv.version_id
395
405
  )
396
406
  }
397
407
 
398
408
  @iam.delete_policy(
399
- :policy_arn => policy_arn(policy_name)
409
+ :policy_arn => policy_arn(policy_name, policy_path)
400
410
  )
401
411
  end
402
412
  end
403
413
 
404
- def update_managed_policy(policy_name, policy_document, old_policy_document)
414
+ def update_managed_policy(policy_name, policy_path, policy_document, old_policy_document)
405
415
  log(:info, "Update ManagedPolicy `#{policy_name}`", :color => :green)
406
416
  log(:info, Miam::Utils.diff(old_policy_document, policy_document, :color => @options[:color]), :color => false)
407
417
 
408
418
  unless_dry_run do
409
419
  policy_versions = @iam.list_policy_versions(
410
- :policy_arn => policy_arn(policy_name),
420
+ :policy_arn => policy_arn(policy_name, policy_path),
411
421
  :max_items => MAX_POLICY_VERSIONS
412
422
  )
413
423
 
@@ -417,19 +427,27 @@ class Miam::Driver
417
427
  }.sort_by {|pv| pv.version_id[1..-1].to_i }.first
418
428
 
419
429
  @iam.delete_policy_version(
420
- :policy_arn => policy_arn(policy_name),
430
+ :policy_arn => policy_arn(policy_name, policy_path),
421
431
  :version_id => delete_policy_version.version_id
422
432
  )
423
433
  end
424
434
 
425
435
  @iam.create_policy_version(
426
- :policy_arn => policy_arn(policy_name),
436
+ :policy_arn => policy_arn(policy_name, policy_path),
427
437
  :policy_document => encode_document(policy_document),
428
438
  set_as_default: true
429
439
  )
430
440
  end
431
441
  end
432
442
 
443
+ def password_policy
444
+ return @password_policy if instance_variable_defined?(:@password_policy)
445
+
446
+ @password_policy = @iam.get_account_password_policy.password_policy
447
+ rescue Aws::IAM::Errors::NoSuchEntity
448
+ @password_policy = nil
449
+ end
450
+
433
451
  private
434
452
 
435
453
  def encode_document(policy_document)
@@ -455,11 +473,13 @@ class Miam::Driver
455
473
  yield unless @options[:dry_run]
456
474
  end
457
475
 
458
- def user_id
459
- @user_id ||= @iam.get_user.user.user_id
476
+ def account_id
477
+ # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
478
+ # http://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
479
+ @account_id ||= @sts.get_caller_identity.account
460
480
  end
461
481
 
462
- def policy_arn(policy_name)
463
- "arn:aws:iam::#{user_id}:policy/#{policy_name}"
482
+ def policy_arn(policy_name, policy_path)
483
+ File.join("arn:aws:iam::#{account_id}:policy", policy_path, policy_name)
464
484
  end
465
485
  end
@@ -193,10 +193,16 @@ end
193
193
  end
194
194
 
195
195
  def target_matched?(name)
196
+ result = true
197
+
198
+ if @options[:exclude]
199
+ result &&= name !~ @options[:exclude]
200
+ end
201
+
196
202
  if @options[:target]
197
- name =~ @options[:target]
198
- else
199
- true
203
+ result &&= name =~ @options[:target]
200
204
  end
205
+
206
+ result
201
207
  end
202
208
  end
data/lib/miam/exporter.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # coding: utf-8
2
2
  class Miam::Exporter
3
3
  AWS_MANAGED_POLICY_PREFIX = 'arn:aws:iam::aws:'
4
+ AWS_CN_MANAGED_POLICY_PREFIX = 'arn:aws-cn:iam::aws:'
4
5
 
5
6
  def self.export(iam, options = {})
6
7
  self.new(iam, options).export
@@ -200,7 +201,7 @@ class Miam::Exporter
200
201
  result = {}
201
202
 
202
203
  Parallel.each(policies, :in_threads => @concurrency) do |policy|
203
- if policy.arn.start_with?(AWS_MANAGED_POLICY_PREFIX)
204
+ if policy.arn.start_with?(AWS_MANAGED_POLICY_PREFIX) or policy.arn.start_with?(AWS_CN_MANAGED_POLICY_PREFIX)
204
205
  next
205
206
  end
206
207
 
@@ -262,10 +263,10 @@ class Miam::Exporter
262
263
  @iam.get_account_authorization_details.each do |resp|
263
264
  keys.each do |key|
264
265
  account_authorization_details[key].concat(resp[key])
266
+ end
265
267
 
266
- unless @options[:no_progress]
267
- progressbar.increment
268
- end
268
+ unless @options[:no_progress]
269
+ progressbar.increment
269
270
  end
270
271
  end
271
272
 
@@ -1,13 +1,19 @@
1
1
  class Miam::PasswordManager
2
2
  include Miam::Logger::Helper
3
3
 
4
+ LOWERCASES = ('a'..'z').to_a
5
+ UPPERCASES = ('A'..'Z').to_a
6
+ NUMBERS = ('0'..'9').to_a
7
+ SYMBOLS = "!@\#$%^&*()_+-=[]{}|'".split(//)
8
+
4
9
  def initialize(output, options = {})
5
10
  @output = output
6
11
  @options = options
7
12
  end
8
13
 
9
- def identify(user, type)
10
- password = mkpasswd
14
+ def identify(user, type, policy)
15
+ password = mkpasswd(policy)
16
+ log(:info, "mkpasswd: #{password}")
11
17
  puts_password(user, type, password)
12
18
  password
13
19
  end
@@ -22,8 +28,21 @@ class Miam::PasswordManager
22
28
 
23
29
  private
24
30
 
25
- def mkpasswd(len = 8)
26
- [*1..9, *'A'..'Z', *'a'..'z'].shuffle.slice(0, len).join
31
+ def mkpasswd(policy)
32
+ chars = []
33
+ len = 8
34
+
35
+ if policy
36
+ len = policy.minimum_password_length if policy.minimum_password_length > len
37
+ chars << LOWERCASES.shuffle.first if policy.require_lowercase_characters
38
+ chars << UPPERCASES.shuffle.first if policy.require_uppercase_characters
39
+ chars << NUMBERS.shuffle.first if policy.require_numbers
40
+ chars << SYMBOLS.shuffle.first if policy.require_symbols
41
+
42
+ len -= chars.length
43
+ end
44
+
45
+ (chars + [*1..9, *'A'..'Z', *'a'..'z'].shuffle.slice(0, len)).shuffle.join
27
46
  end
28
47
 
29
48
  def open_output
data/lib/miam/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Miam
2
- VERSION = '0.2.3'
2
+ VERSION = '0.2.4.beta11'
3
3
  end
data/miam.gemspec CHANGED
@@ -8,8 +8,6 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Miam::VERSION
9
9
  spec.authors = ['Genki Sugawara']
10
10
  spec.email = ['sgwr_dts@yahoo.co.jp']
11
- spec.summary = %q{TODO: Write a short summary. Required.}
12
- spec.description = %q{TODO: Write a longer description. Optional.}
13
11
  spec.summary = %q{Miam is a tool to manage IAM.}
14
12
  spec.description = %q{Miam is a tool to manage IAM. It defines the state of IAM using DSL, and updates IAM according to DSL.}
15
13
  spec.homepage = 'http://miam.codenize.tools/'
@@ -31,4 +29,5 @@ Gem::Specification.new do |spec|
31
29
  spec.add_development_dependency 'rspec', '>= 3.0.0'
32
30
  spec.add_development_dependency 'rspec-instafail'
33
31
  spec.add_development_dependency 'coveralls'
32
+ spec.add_development_dependency 'nokogiri'
34
33
  end
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.3
4
+ version: 0.2.4.beta11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-29 00:00:00.000000000 Z
11
+ date: 2017-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: nokogiri
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  description: Miam is a tool to manage IAM. It defines the state of IAM using DSL,
168
182
  and updates IAM according to DSL.
169
183
  email:
@@ -224,12 +238,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
238
  version: '0'
225
239
  required_rubygems_version: !ruby/object:Gem::Requirement
226
240
  requirements:
227
- - - ">="
241
+ - - ">"
228
242
  - !ruby/object:Gem::Version
229
- version: '0'
243
+ version: 1.3.1
230
244
  requirements: []
231
245
  rubyforge_project:
232
- rubygems_version: 2.4.5.1
246
+ rubygems_version: 2.5.2
233
247
  signing_key:
234
248
  specification_version: 4
235
249
  summary: Miam is a tool to manage IAM.