miam 0.1.0.beta
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +112 -0
- data/Rakefile +2 -0
- data/bin/miam +143 -0
- data/lib/miam.rb +24 -0
- data/lib/miam/client.rb +268 -0
- data/lib/miam/driver.rb +248 -0
- data/lib/miam/dsl.rb +9 -0
- data/lib/miam/dsl/context.rb +52 -0
- data/lib/miam/dsl/context/group.rb +27 -0
- data/lib/miam/dsl/context/user.rb +35 -0
- data/lib/miam/dsl/converter.rb +91 -0
- data/lib/miam/exporter.rb +137 -0
- data/lib/miam/ext/string_ext.rb +25 -0
- data/lib/miam/logger.rb +28 -0
- data/lib/miam/password_manager.rb +37 -0
- data/lib/miam/utils.rb +19 -0
- data/lib/miam/version.rb +3 -0
- data/miam.gemspec +28 -0
- metadata +137 -0
data/lib/miam/driver.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
class Miam::Driver
|
2
|
+
include Miam::Logger::Helper
|
3
|
+
|
4
|
+
MAX_POLICY_SIZE = 2048
|
5
|
+
|
6
|
+
def initialize(iam, options = {})
|
7
|
+
@iam = iam
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_user(user_name, attrs)
|
12
|
+
log(:info, "Create User `#{user_name}`", :color => :cyan)
|
13
|
+
|
14
|
+
unless_dry_run do
|
15
|
+
params = {:user_name => user_name}
|
16
|
+
params[:path] = attrs[:path] if attrs[:path]
|
17
|
+
@iam.create_user(params)
|
18
|
+
end
|
19
|
+
|
20
|
+
new_user_attrs = {:groups => [], :policies => {}}
|
21
|
+
new_user_attrs[:path] = attrs[:path] if attrs[:path]
|
22
|
+
new_user_attrs
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_access_key(user_name)
|
26
|
+
log(:info, "Create access key for User `#{user_name}`", :color => :cyan)
|
27
|
+
access_key = nil
|
28
|
+
|
29
|
+
unless_dry_run do
|
30
|
+
resp = @iam.create_access_key(:user_name => user_name)
|
31
|
+
|
32
|
+
access_key = {
|
33
|
+
:access_key_id => resp.access_key.access_key_id,
|
34
|
+
:secret_access_key => resp.access_key.secret_access_key,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
access_key
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_user(user_name, attrs)
|
42
|
+
log(:info, "Delete User `#{user_name}`", :color => :red)
|
43
|
+
|
44
|
+
unless_dry_run do
|
45
|
+
if attrs[:login_profile]
|
46
|
+
@iam.delete_login_profile(:user_name => user_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
attrs[:policies].keys.each do |policy_name|
|
50
|
+
@iam.delete_user_policy(:user_name => user_name, :policy_name => policy_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
attrs[:groups].each do |group_name|
|
54
|
+
@iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
list_access_key_ids(user_name).each do |access_key_id|
|
58
|
+
@iam.delete_access_key(:user_name => user_name, :access_key_id => access_key_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
list_signing_certificate_ids(user_name).each do |certificate_id|
|
62
|
+
@iam.delete_signing_certificate(:user_name => user_name, :certificate_id => certificate_id)
|
63
|
+
end
|
64
|
+
|
65
|
+
@iam.delete_user(:user_name => user_name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_login_profile(user_name, attrs)
|
70
|
+
log_attrs = attrs.dup
|
71
|
+
log_attrs.delete(:password)
|
72
|
+
|
73
|
+
log(:info, "Update User `#{user_name}`", :color => :green)
|
74
|
+
log(:info, " create login profile: #{log_attrs.inspect}", :color => :green)
|
75
|
+
|
76
|
+
unless_dry_run do
|
77
|
+
@iam.create_login_profile(attrs.merge(:user_name => user_name))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete_login_profile(user_name)
|
82
|
+
log(:info, "Update User `#{user_name}`", :color => :green)
|
83
|
+
log(:info, " delete login profile", :color => :green)
|
84
|
+
|
85
|
+
unless_dry_run do
|
86
|
+
@iam.delete_login_profile(:user_name => user_name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def update_login_profile(user_name, attrs)
|
91
|
+
log_attrs = attrs.dup
|
92
|
+
log_attrs.delete(:password)
|
93
|
+
|
94
|
+
log(:info, "Update User `#{user_name}`", :color => :green)
|
95
|
+
log(:info, " update login profile: #{log_attrs.inspect}", :color => :green)
|
96
|
+
|
97
|
+
unless_dry_run do
|
98
|
+
@iam.update_login_profile(attrs.merge(:user_name => user_name))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_user_to_groups(user_name, group_names)
|
103
|
+
log(:info, "Update User `#{user_name}`", :color => :green)
|
104
|
+
log(:info, " add groups=#{group_names.join(',')}", :color => :green)
|
105
|
+
|
106
|
+
unless_dry_run do
|
107
|
+
group_names.each do |group_name|
|
108
|
+
@iam.add_user_to_group(:group_name => group_name, :user_name => user_name)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def remove_user_from_groups(user_name, group_names)
|
114
|
+
log(:info, "Update User `#{user_name}`", :color => :green)
|
115
|
+
log(:info, " remove groups=#{group_names.join(',')}", :color => :green)
|
116
|
+
|
117
|
+
unless_dry_run do
|
118
|
+
group_names.each do |group_name|
|
119
|
+
@iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_group(group_name, attrs)
|
125
|
+
log(:info, "Create Group `#{group_name}`", :color => :cyan)
|
126
|
+
|
127
|
+
unless_dry_run do
|
128
|
+
params = {:group_name => group_name}
|
129
|
+
params[:path] = attrs[:path] if attrs[:path]
|
130
|
+
@iam.create_group(params)
|
131
|
+
end
|
132
|
+
|
133
|
+
new_group_attrs = {:policies => {}}
|
134
|
+
new_group_attrs[:path] = attrs[:path] if attrs[:path]
|
135
|
+
new_group_attrs
|
136
|
+
end
|
137
|
+
|
138
|
+
def delete_group(group_name, attrs, users_in_group)
|
139
|
+
log(:info, "Delete Group `#{group_name}`", :color => :red)
|
140
|
+
|
141
|
+
unless_dry_run do
|
142
|
+
attrs[:policies].keys.each do |policy_name|
|
143
|
+
@iam.delete_group_policy(:group_name => group_name, :policy_name => policy_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
users_in_group.each do |user_name|
|
147
|
+
@iam.remove_user_from_group(:group_name => group_name, :user_name => user_name)
|
148
|
+
end
|
149
|
+
|
150
|
+
@iam.delete_group(:group_name => group_name)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def update_name(type, user_or_group_name, new_name)
|
155
|
+
log(:info, "Update #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}`", :color => :green)
|
156
|
+
log(:info, " set name=#{new_name}", :color => :green)
|
157
|
+
update_user_or_group(type, user_or_group_name, "new_#{type}_name".to_sym => new_name)
|
158
|
+
end
|
159
|
+
|
160
|
+
def update_path(type, user_or_group_name, new_path)
|
161
|
+
log(:info, "Update #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}`", :color => :green)
|
162
|
+
log(:info, " set path=#{new_path}", :color => :green)
|
163
|
+
update_user_or_group(type, user_or_group_name, :new_path => new_path)
|
164
|
+
end
|
165
|
+
|
166
|
+
def update_user_or_group(type, user_or_group_name, params)
|
167
|
+
unless_dry_run do
|
168
|
+
params["#{type}_name".to_sym] = user_or_group_name
|
169
|
+
@iam.send("update_#{type}", params)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def create_policy(type, user_or_group_name, policy_name, policy_document)
|
174
|
+
log(:info, "Create #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`", :color => :cyan)
|
175
|
+
log(:info, " #{policy_document.pretty_inspect.gsub("\n", "\n ").strip}", :color => :cyan)
|
176
|
+
put_policy(type, user_or_group_name, policy_name, policy_document)
|
177
|
+
end
|
178
|
+
|
179
|
+
def update_policy(type, user_or_group_name, policy_name, policy_document)
|
180
|
+
log(:info, "Update #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`", :color => :green)
|
181
|
+
log(:info, " #{policy_document.pretty_inspect.gsub("\n", "\n ").strip}", :color => :green)
|
182
|
+
put_policy(type, user_or_group_name, policy_name, policy_document)
|
183
|
+
end
|
184
|
+
|
185
|
+
def delete_policy(type, user_or_group_name, policy_name)
|
186
|
+
logmsg = "Delete #{Miam::Utils.camelize(type.to_s)} `#{user_or_group_name}` > Policy `#{policy_name}`"
|
187
|
+
log(:info, logmsg, :color => :red)
|
188
|
+
|
189
|
+
unless_dry_run do
|
190
|
+
params = {:policy_name => policy_name}
|
191
|
+
params["#{type}_name".to_sym] = user_or_group_name
|
192
|
+
@iam.send("delete_#{type}_policy", params)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def put_policy(type, user_or_group_name, policy_name, policy_document)
|
197
|
+
unless_dry_run do
|
198
|
+
params = {
|
199
|
+
:policy_name => policy_name,
|
200
|
+
:policy_document => encode_document(policy_document),
|
201
|
+
}
|
202
|
+
|
203
|
+
params["#{type}_name".to_sym] = user_or_group_name
|
204
|
+
@iam.send("put_#{type}_policy", params)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def list_access_key_ids(user_name)
|
209
|
+
@iam.list_access_keys(:user_name => user_name).map {|resp|
|
210
|
+
resp.access_key_metadata.map do |metadata|
|
211
|
+
metadata.access_key_id
|
212
|
+
end
|
213
|
+
}.flatten
|
214
|
+
end
|
215
|
+
|
216
|
+
def list_signing_certificate_ids(user_name)
|
217
|
+
@iam.list_signing_certificates(:user_name => user_name).map {|resp|
|
218
|
+
resp.certificates.map do |cert|
|
219
|
+
cert.certificate_id
|
220
|
+
end
|
221
|
+
}.flatten
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
def encode_document(policy_document)
|
227
|
+
if @options[:disable_form_json]
|
228
|
+
JSON.dump(policy_document)
|
229
|
+
else
|
230
|
+
encoded = JSON.pretty_generate(policy_document)
|
231
|
+
|
232
|
+
if Miam::Utils.bytesize(encoded) > MAX_POLICY_SIZE
|
233
|
+
encoded = JSON.pretty_generate(policy_document)
|
234
|
+
encoded = encoded.gsub(/^\s+/m, '').strip
|
235
|
+
end
|
236
|
+
|
237
|
+
if Miam::Utils.bytesize(encoded) > MAX_POLICY_SIZE
|
238
|
+
encoded = JSON.dump(policy_document)
|
239
|
+
end
|
240
|
+
|
241
|
+
encoded
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def unless_dry_run
|
246
|
+
yield unless @options[:dry_run]
|
247
|
+
end
|
248
|
+
end
|
data/lib/miam/dsl.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class Miam::DSL::Context
|
2
|
+
def self.eval(dsl, path, options = {})
|
3
|
+
self.new(path, options) {
|
4
|
+
eval(dsl, binding, path)
|
5
|
+
}
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :result
|
9
|
+
|
10
|
+
def initialize(path, options = {}, &block)
|
11
|
+
@path = path
|
12
|
+
@options = options
|
13
|
+
@result = {:users => {}, :groups => {}}
|
14
|
+
instance_eval(&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def require(file)
|
20
|
+
iamfile = (file =~ %r|\A/|) ? file : File.expand_path(File.join(File.dirname(@path), file))
|
21
|
+
|
22
|
+
if File.exist?(iamfile)
|
23
|
+
instance_eval(File.read(iamfile), iamfile)
|
24
|
+
elsif File.exist?(iamfile + '.rb')
|
25
|
+
instance_eval(File.read(iamfile + '.rb'), iamfile + '.rb')
|
26
|
+
else
|
27
|
+
Kernel.require(file)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def user(name, user_options = {}, &block)
|
32
|
+
name = name.to_s
|
33
|
+
|
34
|
+
if @result[:users][name]
|
35
|
+
raise "User `#{name}` is already defined"
|
36
|
+
end
|
37
|
+
|
38
|
+
attrs = Miam::DSL::Context::User.new(name, &block).result
|
39
|
+
@result[:users][name] = user_options.merge(attrs)
|
40
|
+
end
|
41
|
+
|
42
|
+
def group(name, group_options = {}, &block)
|
43
|
+
name = name.to_s
|
44
|
+
|
45
|
+
if @result[:groups][name]
|
46
|
+
raise "Group `#{name}` is already defined"
|
47
|
+
end
|
48
|
+
|
49
|
+
attrs = Miam::DSL::Context::Group.new(name, &block).result
|
50
|
+
@result[:groups][name] = group_options.merge(attrs)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Miam::DSL::Context::Group
|
2
|
+
def initialize(name, &block)
|
3
|
+
@name = name
|
4
|
+
@result = {:policies => {}}
|
5
|
+
instance_eval(&block)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :result
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def policy(name)
|
13
|
+
name = name.to_s
|
14
|
+
|
15
|
+
if @result[:policies][name]
|
16
|
+
raise "Group `#{name}` > Policy `#{name}`: already defined"
|
17
|
+
end
|
18
|
+
|
19
|
+
policy_document = yield
|
20
|
+
|
21
|
+
unless policy_document.kind_of?(Hash)
|
22
|
+
raise "Group `#{name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
|
23
|
+
end
|
24
|
+
|
25
|
+
@result[:policies][name] = policy_document
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Miam::DSL::Context::User
|
2
|
+
def initialize(name, &block)
|
3
|
+
@name = name
|
4
|
+
@result = {:groups => [], :policies => {}}
|
5
|
+
instance_eval(&block)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :result
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def login_profile(value)
|
13
|
+
@result[:login_profile] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def groups(*grps)
|
17
|
+
@result[:groups].concat(grps.map {|i| i.to_s })
|
18
|
+
end
|
19
|
+
|
20
|
+
def policy(name)
|
21
|
+
name = name.to_s
|
22
|
+
|
23
|
+
if @result[:policies][name]
|
24
|
+
raise "User `#{name}` > Policy `#{name}`: already defined"
|
25
|
+
end
|
26
|
+
|
27
|
+
policy_document = yield
|
28
|
+
|
29
|
+
unless policy_document.kind_of?(Hash)
|
30
|
+
raise "User `#{name}` > Policy `#{name}`: wrong argument type #{policy_document.class} (expected Hash)"
|
31
|
+
end
|
32
|
+
|
33
|
+
@result[:policies][name] = policy_document
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class Miam::DSL::Converter
|
2
|
+
def self.convert(exported, options = {})
|
3
|
+
self.new(exported, options).convert
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize(exported, options = {})
|
7
|
+
@exported = exported
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert
|
12
|
+
[
|
13
|
+
output_users(@exported[:users]),
|
14
|
+
output_groups(@exported[:groups]),
|
15
|
+
].join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def output_users(users)
|
21
|
+
users.each.sort_by {|k, v| k }.map {|user_name, attrs|
|
22
|
+
output_user(user_name, attrs)
|
23
|
+
}.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def output_user(user_name, attrs)
|
27
|
+
user_options = {:path => attrs[:path]}
|
28
|
+
|
29
|
+
<<-EOS
|
30
|
+
user #{user_name.inspect}, #{Miam::Utils.unbrace(user_options.inspect)} do
|
31
|
+
#{output_login_profile(attrs[:login_profile])}
|
32
|
+
|
33
|
+
#{output_user_groups(attrs[:groups])}
|
34
|
+
|
35
|
+
#{output_policies(attrs[:policies])}
|
36
|
+
end
|
37
|
+
EOS
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_user_groups(groups)
|
41
|
+
if groups.empty?
|
42
|
+
groups = ['# no group']
|
43
|
+
else
|
44
|
+
groups = groups.map {|i| i.inspect }
|
45
|
+
end
|
46
|
+
|
47
|
+
groups = "\n " + groups.join(",\n ") + "\n "
|
48
|
+
"groups(#{groups})"
|
49
|
+
end
|
50
|
+
|
51
|
+
def output_login_profile(login_profile)
|
52
|
+
if login_profile
|
53
|
+
"login_profile #{Miam::Utils.unbrace(login_profile.inspect)}"
|
54
|
+
else
|
55
|
+
'# login_profile :password_reset_required=>true'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def output_groups(groups)
|
60
|
+
groups.each.sort_by {|k, v| k }.map {|group_name, attrs|
|
61
|
+
output_group(group_name, attrs)
|
62
|
+
}.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
def output_group(group_name, attrs)
|
66
|
+
group_options = {:path => attrs[:path]}
|
67
|
+
|
68
|
+
<<-EOS
|
69
|
+
group #{group_name.inspect}, #{Miam::Utils.unbrace(group_options.inspect)} do
|
70
|
+
#{output_policies(attrs[:policies])}
|
71
|
+
end
|
72
|
+
EOS
|
73
|
+
end
|
74
|
+
|
75
|
+
def output_policies(policies)
|
76
|
+
policies.map {|policy_name, policy_document|
|
77
|
+
output_policy(policy_name, policy_document)
|
78
|
+
}.join("\n\n ").strip
|
79
|
+
end
|
80
|
+
|
81
|
+
def output_policy(policy_name, policy_document)
|
82
|
+
policy_document = policy_document.pretty_inspect
|
83
|
+
policy_document.gsub!("\n", "\n ").strip!
|
84
|
+
|
85
|
+
<<-EOS.strip
|
86
|
+
policy #{policy_name.inspect} do
|
87
|
+
#{policy_document}
|
88
|
+
end
|
89
|
+
EOS
|
90
|
+
end
|
91
|
+
end
|