miam 0.1.0 → 0.1.1

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: 1c277e2932203a2740972ef45fb3588f25e08ced
4
- data.tar.gz: 560435cc28118cc841397919249697a68a2e6851
3
+ metadata.gz: dac584f8c0f3829974bbf66a703a0514b0bba56b
4
+ data.tar.gz: 4c1554986b97d252d2e6fea8c17dbdee4e7c0072
5
5
  SHA512:
6
- metadata.gz: f631ea1267d5c62723f85129e26508dc712b5189ea53e47ada4aacbcbc4b75f22bf56971364dc7490734343d2e62d885a6bbf68636d622550495a35bda2585b5
7
- data.tar.gz: fa71e40019ca1342ec1472c07c1ae376b4233e1bda0129ed3715e9c151c751b43d1339e08f11018752ab080ed6cec1debcc79bc9a7104891f13f6eb99c4b3490
6
+ metadata.gz: a197de1545bb2bfdaa906a215d23e61eb4ff63759875929a6f01605a38c6a3c4d5bd3dfa753a6e77af7c4521e0ef5f22ac36a70c1d049c8ada9e4a211f969601
7
+ data.tar.gz: cad4724a8a76be2bfc6c92ebc5ef97bf95a5e2b08f97469ce2f1213b95cc8ac42c89d694d71cf2805b3ce7e93258a3212354e076455a1852351c81e1a1bb9c59
data/README.md CHANGED
@@ -63,7 +63,7 @@ Usage: miam [options]
63
63
  require 'other/iamfile'
64
64
 
65
65
  user "bob", :path => "/developer/" do
66
- login_profile password_reset_required: true
66
+ login_profile :password_reset_required=>true
67
67
 
68
68
  groups(
69
69
  "Admin"
@@ -81,7 +81,7 @@ user "bob", :path => "/developer/" do
81
81
  end
82
82
 
83
83
  user "mary", :path => "/staff/" do
84
- # login_profile password_reset_required: true
84
+ # login_profile :password_reset_required=>true
85
85
 
86
86
  groups(
87
87
  # no group
@@ -113,6 +113,28 @@ group "Admin", :path => "/admin/" do
113
113
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
114
114
  end
115
115
  end
116
+
117
+ role "S3", :path => "/" do
118
+ instance_profiles(
119
+ "S3"
120
+ )
121
+
122
+ assume_role_policy_document do
123
+ {"Version"=>"2012-10-17",
124
+ "Statement"=>
125
+ [{"Sid"=>"",
126
+ "Effect"=>"Allow",
127
+ "Principal"=>{"Service"=>"ec2.amazonaws.com"},
128
+ "Action"=>"sts:AssumeRole"}]}
129
+ end
130
+
131
+ policy "S3-role-policy" do
132
+ {"Version"=>"2012-10-17",
133
+ "Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
134
+ end
135
+ end
136
+
137
+ instance_profile "S3", :path => "/"
116
138
  ```
117
139
 
118
140
  ## Rename
data/bin/miam CHANGED
@@ -94,8 +94,9 @@ begin
94
94
  output_file = DEFAULT_FILENAME if output_file == '-'
95
95
  requires = []
96
96
 
97
- client.export do |users_or_groups, dsl|
98
- iam_file = File.join(File.dirname(output_file), "#{users_or_groups}.iam")
97
+ client.export do |type, dsl|
98
+ next if dsl.strip.empty?
99
+ iam_file = File.join(File.dirname(output_file), "#{type}.iam")
99
100
  requires << iam_file
100
101
  logger.info(" write `#{iam_file}`")
101
102
 
@@ -114,10 +115,10 @@ begin
114
115
  else
115
116
  if output_file == '-'
116
117
  logger.info('# Export IAM')
117
- puts client.export
118
+ puts client.export.strip
118
119
  else
119
120
  logger.info("Export IAM to `#{output_file}`")
120
- open(output_file, 'wb') {|f| f.puts client.export }
121
+ open(output_file, 'wb') {|f| f.puts client.export.strip }
121
122
  end
122
123
  end
123
124
  when :apply
data/lib/miam.rb CHANGED
@@ -15,6 +15,7 @@ require 'miam/driver'
15
15
  require 'miam/dsl'
16
16
  require 'miam/dsl/context'
17
17
  require 'miam/dsl/context/group'
18
+ require 'miam/dsl/context/role'
18
19
  require 'miam/dsl/context/user'
19
20
  require 'miam/dsl/converter'
20
21
  require 'miam/exporter'
data/lib/miam/client.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  class Miam::Client
2
+ include Miam::Logger::Helper
3
+
2
4
  def initialize(options = {})
3
5
  @options = options
4
6
  aws_config = options.delete(:aws_config) || {}
@@ -8,15 +10,15 @@ class Miam::Client
8
10
  end
9
11
 
10
12
  def export
11
- exported, group_users = Miam::Exporter.export(@iam, @options) do |export_options|
13
+ exported, group_users, instance_profile_roles = Miam::Exporter.export(@iam, @options) do |export_options|
12
14
  progress(*export_options.values_at(:progress_total, :progress))
13
15
  end
14
16
 
15
17
  if block_given?
16
- [:users, :groups].each do |users_or_groups|
17
- splitted = {:users => {}, :groups => {}}
18
- splitted[users_or_groups] = exported[users_or_groups]
19
- yield(users_or_groups, Miam::DSL.convert(splitted, @options).strip)
18
+ [:users, :groups, :roles, :instance_profiles].each do |type|
19
+ splitted = {:users => {}, :groups => {}, :roles => {}, :instance_profiles => {}}
20
+ splitted[type] = exported[type]
21
+ yield(type, Miam::DSL.convert(splitted, @options).strip)
20
22
  end
21
23
  else
22
24
  Miam::DSL.convert(exported, @options)
@@ -32,12 +34,14 @@ class Miam::Client
32
34
  def walk(file)
33
35
  expected = load_file(file)
34
36
 
35
- actual, group_users = Miam::Exporter.export(@iam, @options) do |export_options|
37
+ actual, group_users, instance_profile_roles = Miam::Exporter.export(@iam, @options) do |export_options|
36
38
  progress(*export_options.values_at(:progress_total, :progress))
37
39
  end
38
40
 
39
41
  updated = walk_groups(expected[:groups], actual[:groups], actual[:users], group_users)
40
42
  updated = walk_users(expected[:users], actual[:users], group_users) || updated
43
+ updated = walk_instance_profiles(expected[:instance_profiles], actual[:instance_profiles], actual[:roles], instance_profile_roles) || updated
44
+ updated = walk_roles(expected[:roles], actual[:roles], instance_profile_roles) || updated
41
45
 
42
46
  if @options[:dry_run]
43
47
  false
@@ -168,6 +172,125 @@ class Miam::Client
168
172
  walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
169
173
  end
170
174
 
175
+ def walk_roles(expected, actual, instance_profile_roles)
176
+ updated = false
177
+
178
+ expected.each do |role_name, expected_attrs|
179
+ actual_attrs = actual.delete(role_name)
180
+
181
+ if actual_attrs
182
+ updated = walk_role(role_name, expected_attrs, actual_attrs) || updated
183
+ else
184
+ actual_attrs = @driver.create_role(role_name, expected_attrs)
185
+ walk_role(role_name, expected_attrs, actual_attrs)
186
+ updated = true
187
+ end
188
+ end
189
+
190
+ actual.each do |role_name, attrs|
191
+ instance_profile_names = []
192
+
193
+ instance_profile_roles.each do |instance_profile_name, roles|
194
+ if roles.include?(role_name)
195
+ instance_profile_names << instance_profile_name
196
+ end
197
+ end
198
+
199
+ @driver.delete_role(role_name, instance_profile_names, attrs)
200
+
201
+ instance_profile_roles.each do |instance_profile_name, roles|
202
+ roles.delete(role_name)
203
+ end
204
+
205
+ updated = true
206
+ end
207
+
208
+ updated
209
+ end
210
+
211
+ def walk_role(role_name, expected_attrs, actual_attrs)
212
+ if expected_attrs.values_at(:path) != actual_attrs.values_at(:path)
213
+ log(:warn, "Role `#{role_name}`: 'path' cannot be updated", :color => :yellow)
214
+ end
215
+
216
+ updated = walk_assume_role_policy(role_name, expected_attrs[:assume_role_policy_document], actual_attrs[:assume_role_policy_document])
217
+ updated = walk_role_instance_profiles(role_name, expected_attrs[:instance_profiles], actual_attrs[:instance_profiles]) || updated
218
+ walk_policies(:role, role_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
219
+ end
220
+
221
+ def walk_assume_role_policy(role_name, expected_assume_role_policy, actual_assume_role_policy)
222
+ updated = false
223
+
224
+ if expected_assume_role_policy != actual_assume_role_policy
225
+ @driver.update_assume_role_policy(role_name, expected_assume_role_policy)
226
+ updated = true
227
+ end
228
+
229
+ updated
230
+ end
231
+
232
+ def walk_role_instance_profiles(role_name, expected_instance_profiles, actual_instance_profiles)
233
+ expected_instance_profiles = expected_instance_profiles.sort
234
+ actual_instance_profiles = actual_instance_profiles.sort
235
+ updated = false
236
+
237
+ if expected_instance_profiles != actual_instance_profiles
238
+ add_instance_profiles = expected_instance_profiles - actual_instance_profiles
239
+ remove_instance_profiles = actual_instance_profiles - expected_instance_profiles
240
+
241
+ unless add_instance_profiles.empty?
242
+ @driver.add_role_to_instance_profiles(role_name, add_instance_profiles)
243
+ end
244
+
245
+ unless remove_instance_profiles.empty?
246
+ @driver.remove_role_from_instance_profiles(role_name, remove_instance_profiles)
247
+ end
248
+
249
+ updated = true
250
+ end
251
+
252
+ updated
253
+ end
254
+
255
+ def walk_instance_profiles(expected, actual, actual_roles, instance_profile_roles)
256
+ updated = false
257
+
258
+ expected.each do |instance_profile_name, expected_attrs|
259
+ actual_attrs = actual.delete(instance_profile_name)
260
+
261
+ if actual_attrs
262
+ updated = walk_instance_profile(instance_profile_name, expected_attrs, actual_attrs) || updated
263
+ else
264
+ actual_attrs = @driver.create_instance_profile(instance_profile_name, expected_attrs)
265
+ walk_instance_profile(instance_profile_name, expected_attrs, actual_attrs)
266
+ updated = true
267
+ end
268
+ end
269
+
270
+ actual.each do |instance_profile_name, attrs|
271
+ roles_in_instance_profile = instance_profile_roles.delete(instance_profile_name) || []
272
+ @driver.delete_instance_profile(instance_profile_name, attrs, roles_in_instance_profile)
273
+
274
+ actual_roles.each do |role_name, role_attrs|
275
+ role_attrs[:instance_profiles].delete(instance_profile_name)
276
+ end
277
+
278
+ updated = true
279
+ end
280
+
281
+ updated
282
+ end
283
+
284
+ def walk_instance_profile(instance_profile_name, expected_attrs, actual_attrs)
285
+ updated = false
286
+
287
+ if expected_attrs != actual_attrs
288
+ log(:warn, "InstanceProfile `#{instance_profile_name}`: 'path' cannot be updated", :color => :yellow)
289
+ end
290
+
291
+ updated
292
+ end
293
+
171
294
  def scan_rename(type, expected, actual, group_users)
172
295
  updated = false
173
296
 
data/lib/miam/driver.rb CHANGED
@@ -151,6 +151,106 @@ class Miam::Driver
151
151
  end
152
152
  end
153
153
 
154
+ def create_role(role_name, attrs)
155
+ log(:info, "Create Role `#{role_name}`", :color => :cyan)
156
+ assume_role_policy_document = attrs.fetch(:assume_role_policy_document)
157
+
158
+ unless_dry_run do
159
+ params = {
160
+ :role_name => role_name,
161
+ :assume_role_policy_document => encode_document(assume_role_policy_document),
162
+ }
163
+
164
+ params[:path] = attrs[:path] if attrs[:path]
165
+ @iam.create_role(params)
166
+ end
167
+
168
+ new_role_attrs = {
169
+ :instance_profiles => [],
170
+ :assume_role_policy_document => assume_role_policy_document,
171
+ :policies => {}
172
+ }
173
+
174
+ new_role_attrs[:path] = attrs[:path] if attrs[:path]
175
+ new_role_attrs
176
+ end
177
+
178
+ def delete_role(role_name, instance_profile_names, attrs)
179
+ log(:info, "Delete Role `#{role_name}`", :color => :red)
180
+
181
+ unless_dry_run do
182
+ attrs[:policies].keys.each do |policy_name|
183
+ @iam.delete_role_policy(:role_name => role_name, :policy_name => policy_name)
184
+ end
185
+
186
+ instance_profile_names.each do |instance_profile_name|
187
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
188
+ end
189
+
190
+ @iam.delete_role(:role_name => role_name)
191
+ end
192
+ end
193
+
194
+ def add_role_to_instance_profiles(role_name, instance_profile_names)
195
+ log(:info, "Update Role `#{role_name}`", :color => :green)
196
+ log(:info, " add instance_profiles=#{instance_profile_names.join(',')}", :color => :green)
197
+
198
+ unless_dry_run do
199
+ instance_profile_names.each do |instance_profile_name|
200
+ @iam.add_role_to_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
201
+ end
202
+ end
203
+ end
204
+
205
+ def remove_role_from_instance_profiles(role_name, instance_profile_names)
206
+ log(:info, "Update Role `#{role_name}`", :color => :green)
207
+ log(:info, " remove instance_profiles=#{instance_profile_names.join(',')}", :color => :green)
208
+
209
+ unless_dry_run do
210
+ instance_profile_names.each do |instance_profile_name|
211
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
212
+ end
213
+ end
214
+ end
215
+
216
+ def update_assume_role_policy(role_name, policy_document)
217
+ log(:info, "Update Role `#{role_name}` > AssumeRolePolicy", :color => :green)
218
+ log(:info, " #{policy_document.pretty_inspect.gsub("\n", "\n ").strip}", :color => :green)
219
+
220
+ unless_dry_run do
221
+ @iam.update_assume_role_policy(
222
+ :role_name => role_name,
223
+ :policy_document => encode_document(policy_document),
224
+ )
225
+ end
226
+ end
227
+
228
+ def create_instance_profile(instance_profile_name, attrs)
229
+ log(:info, "Create InstanceIrofile `#{instance_profile_name}`", :color => :cyan)
230
+
231
+ unless_dry_run do
232
+ params = {:instance_profile_name => instance_profile_name}
233
+ params[:path] = attrs[:path] if attrs[:path]
234
+ @iam.create_instance_profile(params)
235
+ end
236
+
237
+ new_instance_profile_attrs = {}
238
+ new_instance_profile_attrs[:path] = attrs[:path] if attrs[:path]
239
+ new_instance_profile_attrs
240
+ end
241
+
242
+ def delete_instance_profile(instance_profile_name, attrs, roles_in_instance_profile)
243
+ log(:info, "Delete InstanceProfile `#{instance_profile_name}`", :color => :red)
244
+
245
+ unless_dry_run do
246
+ roles_in_instance_profile.each do |role_name|
247
+ @iam.remove_role_from_instance_profile(:instance_profile_name => instance_profile_name, :role_name => role_name)
248
+ end
249
+
250
+ @iam.delete_instance_profile(:instance_profile_name => instance_profile_name)
251
+ end
252
+ end
253
+
154
254
  def update_name(type, user_or_group_name, new_name)
155
255
  log(:info, "Update #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}`", :color => :green)
156
256
  log(:info, " set name=#{new_name}", :color => :green)
@@ -10,7 +10,7 @@ class Miam::DSL::Context
10
10
  def initialize(path, options = {}, &block)
11
11
  @path = path
12
12
  @options = options
13
- @result = {:users => {}, :groups => {}}
13
+ @result = {:users => {}, :groups => {}, :roles => {}, :instance_profiles => {}}
14
14
  instance_eval(&block)
15
15
  end
16
16
 
@@ -49,4 +49,25 @@ class Miam::DSL::Context
49
49
  attrs = Miam::DSL::Context::Group.new(name, &block).result
50
50
  @result[:groups][name] = group_options.merge(attrs)
51
51
  end
52
+
53
+ def role(name, role_options = {}, &block)
54
+ name = name.to_s
55
+
56
+ if @result[:roles][name]
57
+ raise "Role `#{name}` is already defined"
58
+ end
59
+
60
+ attrs = Miam::DSL::Context::Role.new(name, &block).result
61
+ @result[:roles][name] = role_options.merge(attrs)
62
+ end
63
+
64
+ def instance_profile(name, instance_profile_options = {}, &block)
65
+ name = name.to_s
66
+
67
+ if @result[:instance_profiles][name]
68
+ raise "instance_profile `#{name}` is already defined"
69
+ end
70
+
71
+ @result[:instance_profiles][name] = instance_profile_options
72
+ end
52
73
  end
@@ -1,6 +1,6 @@
1
1
  class Miam::DSL::Context::Group
2
2
  def initialize(name, &block)
3
- @name = name
3
+ @group_name = name
4
4
  @result = {:policies => {}}
5
5
  instance_eval(&block)
6
6
  end
@@ -13,13 +13,13 @@ class Miam::DSL::Context::Group
13
13
  name = name.to_s
14
14
 
15
15
  if @result[:policies][name]
16
- raise "Group `#{name}` > Policy `#{name}`: already defined"
16
+ raise "Group `#{@group_name}` > Policy `#{name}`: already defined"
17
17
  end
18
18
 
19
19
  policy_document = yield
20
20
 
21
21
  unless policy_document.kind_of?(Hash)
22
- raise "Group `#{name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
22
+ raise "Group `#{@group_name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
23
23
  end
24
24
 
25
25
  @result[:policies][name] = policy_document
@@ -0,0 +1,51 @@
1
+ class Miam::DSL::Context::Role
2
+ def initialize(name, &block)
3
+ @role_name = name
4
+ @result = {:instance_profiles => [], :policies => {}}
5
+ instance_eval(&block)
6
+ end
7
+
8
+ def result
9
+ unless @result[:assume_role_policy_document]
10
+ raise "Role `#{@role_name}`: AssumeRolePolicyDocument is not defined"
11
+ end
12
+
13
+ @result
14
+ end
15
+
16
+ private
17
+
18
+ def instance_profiles(*profiles)
19
+ @result[:instance_profiles].concat(profiles.map {|i| i.to_s })
20
+ end
21
+
22
+ def assume_role_policy_document
23
+ if @result[:assume_role_policy_document]
24
+ raise "Role `#{@role_name}` > AssumeRolePolicyDocument: already defined"
25
+ end
26
+
27
+ assume_role_policy_document = yield
28
+
29
+ unless assume_role_policy_document.kind_of?(Hash)
30
+ raise "Role `#{@role_name}` > AssumeRolePolicyDocument: wrong argument type #{policy_document.class} (expected Hash)"
31
+ end
32
+
33
+ @result[:assume_role_policy_document] = assume_role_policy_document
34
+ end
35
+
36
+ def policy(name)
37
+ name = name.to_s
38
+
39
+ if @result[:policies][name]
40
+ raise "Role `#{@role_name}` > Policy `#{name}`: already defined"
41
+ end
42
+
43
+ policy_document = yield
44
+
45
+ unless policy_document.kind_of?(Hash)
46
+ raise "Role `#{@role_name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
47
+ end
48
+
49
+ @result[:policies][name] = policy_document
50
+ end
51
+ end