build-cloud 0.0.19 → 0.0.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/bin/build-cloud +3 -0
- data/build-cloud.gemspec +1 -1
- data/lib/build-cloud.rb +6 -0
- data/lib/build-cloud/iamgroup.rb +248 -0
- data/lib/build-cloud/iammanagedpolicy.rb +56 -0
- data/lib/build-cloud/iamrole.rb +119 -20
- data/lib/build-cloud/iamuser.rb +191 -0
- data/lib/build-cloud/s3bucket.rb +36 -6
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a52e42a2f9f37f73e8cb750ff3d71454eed4a51f
|
4
|
+
data.tar.gz: 4445d3159b1cfbcd1808ca5bc182f65a97a4c54a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f53a03aaecae0169ca975f7a79bf88b4ba0e206fcef9f41b2556a7863cdea98dfdc5f10af358899bbab3da5381d4df008e4060654e6cdc4f66af03843d7e4234
|
7
|
+
data.tar.gz: dd3fb1f7f7fc8da8c70b78ab8afaedc25f18d462e0ee0da0a6bd7432728b944b3afa55de8e49b262bd641c0b622b5d8d572896d796d59c221fd4f64ddb5b1675
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
2016-07-08 - version 0.0.20 - Add support for creating Users, Groups and lifecycle management of their policies. Add support for creating and deleting custom Managed Policies, no lifecycle support for policy versions. Improve IAM role support, lifecycle support for policies: now removes and updates role policies if they change/removed. Add policy lifecycle to S3 buckets.
|
4
|
+
|
3
5
|
2016-06-17 - version 0.0.19 - add sqs support
|
4
6
|
|
5
7
|
2016-06-16 - version 0.0.18 - fix cache parameter group creation for elasticache
|
data/bin/build-cloud
CHANGED
@@ -22,7 +22,10 @@ require 'build-cloud/dbparametergroup'
|
|
22
22
|
require 'build-cloud/cachesubnetgroup'
|
23
23
|
require 'build-cloud/cachecluster'
|
24
24
|
require 'build-cloud/cacheparametergroup'
|
25
|
+
require 'build-cloud/iammanagedpolicy'
|
26
|
+
require 'build-cloud/iamgroup'
|
25
27
|
require 'build-cloud/iamrole'
|
28
|
+
require 'build-cloud/iamuser'
|
26
29
|
require 'build-cloud/s3bucket'
|
27
30
|
require 'build-cloud/instance'
|
28
31
|
require 'build-cloud/ebsvolume'
|
data/build-cloud.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "build-cloud"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.20"
|
8
8
|
spec.authors = ["The Scale Factory"]
|
9
9
|
spec.email = ["info@scalefactory.com"]
|
10
10
|
spec.summary = %q{Tools for building resources in AWS}
|
data/lib/build-cloud.rb
CHANGED
@@ -162,6 +162,9 @@ class BuildCloud
|
|
162
162
|
:cache_clusters => BuildCloud::CacheCluster,
|
163
163
|
:cache_parameter_groups => BuildCloud::CacheParameterGroup,
|
164
164
|
:iam_roles => BuildCloud::IAMRole,
|
165
|
+
:iam_managed_policies => BuildCloud::IAMManagedPolicy,
|
166
|
+
:iam_groups => BuildCloud::IAMGroup,
|
167
|
+
:iam_users => BuildCloud::IAMUser,
|
165
168
|
:s3_buckets => BuildCloud::S3Bucket,
|
166
169
|
:instances => BuildCloud::Instance,
|
167
170
|
:ebs_volumes => BuildCloud::EBSVolume,
|
@@ -176,7 +179,10 @@ class BuildCloud
|
|
176
179
|
:dhcp_options_sets,
|
177
180
|
:vpcs,
|
178
181
|
:internet_gateways,
|
182
|
+
:iam_managed_policies,
|
179
183
|
:iam_roles,
|
184
|
+
:iam_users,
|
185
|
+
:iam_groups,
|
180
186
|
:subnets,
|
181
187
|
:db_subnet_groups,
|
182
188
|
:cache_subnet_groups,
|
@@ -0,0 +1,248 @@
|
|
1
|
+
class BuildCloud::IAMGroup
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
include ::BuildCloud::Component
|
6
|
+
|
7
|
+
@@objects = []
|
8
|
+
|
9
|
+
def initialize ( fog_interfaces, log, options = {} )
|
10
|
+
|
11
|
+
@iam = fog_interfaces[:iam]
|
12
|
+
@log = log
|
13
|
+
@options = options
|
14
|
+
|
15
|
+
@log.debug( options.inspect )
|
16
|
+
|
17
|
+
required_options(:name)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
|
23
|
+
policies = @options.delete(:policies)
|
24
|
+
users = @options.delete(:users)
|
25
|
+
|
26
|
+
unless exists?
|
27
|
+
|
28
|
+
@log.info( "Creating new IAM group #{@options[:name]}" )
|
29
|
+
|
30
|
+
group = @iam.groups.new( @options )
|
31
|
+
group.save
|
32
|
+
|
33
|
+
@log.debug( group.inspect )
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
rationalise_policies ( policies )
|
38
|
+
rationalise_users ( users )
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def read
|
43
|
+
@iam.groups.select { |r| r.name == @options[:name] }.first
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def rationalise_policies( policies )
|
48
|
+
|
49
|
+
policies = {} if policies.nil?
|
50
|
+
|
51
|
+
managed_policies_to_add = []
|
52
|
+
group_policies_to_add = []
|
53
|
+
current_managed_policies = []
|
54
|
+
current_group_policies = []
|
55
|
+
|
56
|
+
fog_object.attached_policies.each do |p|
|
57
|
+
current_managed_policies << { :arn => p.arn }
|
58
|
+
end
|
59
|
+
|
60
|
+
# fog_object.policies doesn't return id/policy name
|
61
|
+
@iam.list_group_policies(fog_object.name).body['PolicyNames'].each do |pn|
|
62
|
+
p = @iam.get_group_policy(pn, fog_object.name).body
|
63
|
+
policy = { :document => p['Policy']['PolicyDocument'], :id => p['PolicyName'] }
|
64
|
+
current_group_policies << policy
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build add lists
|
68
|
+
policies.each do |p|
|
69
|
+
@log.debug("Policy action on is #{p}")
|
70
|
+
if p[:arn]
|
71
|
+
@log.debug("For group #{fog_object.name} checking managed policy #{p[:arn]}")
|
72
|
+
# Assume adding policy
|
73
|
+
add_policy = true
|
74
|
+
current_managed_policies.each do |cmp|
|
75
|
+
add_policy = false if cmp[:arn] == p[:arn]
|
76
|
+
end
|
77
|
+
if add_policy
|
78
|
+
@log.debug("Adding #{p[:arn]} to list" )
|
79
|
+
managed_policies_to_add << { :arn => p[:arn] }
|
80
|
+
end
|
81
|
+
elsif p[:id]
|
82
|
+
@log.debug("For group #{fog_object.name} checking policy #{p[:id]}")
|
83
|
+
# Assume adding policy
|
84
|
+
pa = {
|
85
|
+
:document => JSON.parse(p[:document]),
|
86
|
+
:id => p[:id],
|
87
|
+
}
|
88
|
+
group_policies_to_add << pa
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
policies.each do |p|
|
93
|
+
# If we find a current policy that matches the desired policy, then
|
94
|
+
# remove that from the list of current policies - we will remove any
|
95
|
+
# remaining policies
|
96
|
+
if p[:arn]
|
97
|
+
current_managed_policies.delete_if do |c|
|
98
|
+
if c[:arn] == p[:arn]
|
99
|
+
@log.debug( "#{p[:arn]} already exists" )
|
100
|
+
true # so that delete_if removes the list item
|
101
|
+
else
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
elsif p[:id]
|
106
|
+
current_group_policies.delete_if do |c|
|
107
|
+
if c[:id] == p[:id]
|
108
|
+
@log.debug( "#{p[:id]} already exists" )
|
109
|
+
|
110
|
+
# Remove from the policies to add if the policy documents match
|
111
|
+
group_policies_to_add.delete_if do |a|
|
112
|
+
if (c[:id] == a[:id]) and
|
113
|
+
(c[:document] == a[:document])
|
114
|
+
@log.debug("#{p[:id]} is a match" )
|
115
|
+
true
|
116
|
+
else
|
117
|
+
false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
true # so that delete_if removes the list item
|
121
|
+
else
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# At the end of this loop, anything left in the user_current_policies list
|
129
|
+
# represents a policy that's present on the infra, but should be deleted
|
130
|
+
# (since there's no matching desired policy), so delete those.
|
131
|
+
# Changing a rule maps to "delete old rule, create new one".
|
132
|
+
|
133
|
+
current_group_policies.each do |p|
|
134
|
+
@log.debug( "Removing policy #{p.inspect}" )
|
135
|
+
@log.info( "For group #{fog_object.name} removing policy #{p[:id]}" )
|
136
|
+
@iam.delete_group_policy(fog_object.name, p[:id])
|
137
|
+
end
|
138
|
+
|
139
|
+
group_policies_to_add.each do |p|
|
140
|
+
@log.debug( "For group #{fog_object.name} adding/updating policy #{p}" )
|
141
|
+
@log.info( "For group #{fog_object.name} adding/updating policy #{p[:id]}" )
|
142
|
+
@iam.put_group_policy( fog_object.name, p[:id], p[:document] )
|
143
|
+
end
|
144
|
+
|
145
|
+
# And the same for managed policies, but we just detatch them:
|
146
|
+
current_managed_policies.each do |p|
|
147
|
+
@log.debug( "Detatching policy #{p.inspect}" )
|
148
|
+
@log.info( "For group #{fog_object.name} detatcing policy #{p[:arn]}" )
|
149
|
+
@iam.detach_group_policy(fog_object.name, p[:arn])
|
150
|
+
end
|
151
|
+
|
152
|
+
managed_policies_to_add.each do |p|
|
153
|
+
@log.debug( "For group #{fog_object.name} attaching policy #{p}" )
|
154
|
+
@log.info( "For group #{fog_object.name} attaching policy #{p[:arn]}" )
|
155
|
+
@iam.attach_group_policy(fog_object.name, p[:arn])
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
def rationalise_users( users )
|
161
|
+
|
162
|
+
users = {} if users.nil?
|
163
|
+
|
164
|
+
users_to_add = []
|
165
|
+
current_users = []
|
166
|
+
|
167
|
+
@log.debug("Users info: #{@iam.get_group(@options[:name]).body['Users'].inspect}")
|
168
|
+
# can't use fog_object.users as always empty
|
169
|
+
@iam.get_group(@options[:name]).body['Users'].each do |u|
|
170
|
+
current_users << { :id => u['UserName']}
|
171
|
+
end
|
172
|
+
|
173
|
+
@log.debug("Current users: #{current_users}")
|
174
|
+
# Build list of users to add
|
175
|
+
users.each do |u|
|
176
|
+
@log.debug("User acting on is #{u}")
|
177
|
+
@log.debug("For group #{fog_object.name} checking user #{u}")
|
178
|
+
|
179
|
+
# Assume adding user
|
180
|
+
add_user = true
|
181
|
+
current_users.each do |cmu|
|
182
|
+
add_user = false if cmu[:id] == u
|
183
|
+
end
|
184
|
+
if add_user
|
185
|
+
# If we find a user that's not currently present we prepare to add it
|
186
|
+
@log.debug("Adding #{u} to list" )
|
187
|
+
users_to_add << { :id => u }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Find users to remove
|
192
|
+
users.each do |u|
|
193
|
+
# If we find a current user that matches the desired user, then
|
194
|
+
# remove that from the list of current users - we will remove any
|
195
|
+
# remaining users
|
196
|
+
current_users.delete_if do |c|
|
197
|
+
if c[:id] == u
|
198
|
+
@log.debug( "#{u} already exists" )
|
199
|
+
true # so that delete_if removes the list item
|
200
|
+
else
|
201
|
+
false
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# At the end of this loop, anything left in the current_users list
|
207
|
+
# represents a group that's present on the user, but should be removed
|
208
|
+
# (since there's no matching desired group), so delete those.
|
209
|
+
|
210
|
+
current_users.each do |u|
|
211
|
+
@log.debug( "Removing group #{u.inspect} from #{u}" )
|
212
|
+
@log.info( "For group #{fog_object.name} removing user #{u[:id]}" )
|
213
|
+
@iam.remove_user_from_group(fog_object.name, u[:id])
|
214
|
+
end
|
215
|
+
|
216
|
+
users_to_add.each do |u|
|
217
|
+
@log.debug( "For group #{fog_object.name} attaching user #{u}" )
|
218
|
+
@log.info( "For group #{fog_object.name} attaching user #{u[:id]}" )
|
219
|
+
fog_object.add_user(u[:id])
|
220
|
+
end
|
221
|
+
fog_object.save
|
222
|
+
end
|
223
|
+
|
224
|
+
alias_method :fog_object, :read
|
225
|
+
|
226
|
+
def delete
|
227
|
+
|
228
|
+
return unless exists?
|
229
|
+
@log.info( "Deleting IAM group for #{@options[:name]}" )
|
230
|
+
|
231
|
+
#detach all policies
|
232
|
+
fog_object.attached_policies.each do |p|
|
233
|
+
fog_object.detach(p)
|
234
|
+
end
|
235
|
+
|
236
|
+
fog_object.policies.each do |p|
|
237
|
+
@iam.delete_user_policy(@options[:id], p.id)
|
238
|
+
end
|
239
|
+
|
240
|
+
#remove all users
|
241
|
+
fog_object.users.each do |u|
|
242
|
+
@iam.remove_user_from_group(fog_object.name, u.id)
|
243
|
+
end
|
244
|
+
|
245
|
+
fog_object.destroy
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
# IAM Managed Policy is not updated once created, because fog doesn't support policy versioning right now
|
3
|
+
|
4
|
+
class BuildCloud::IAMManagedPolicy
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
include ::BuildCloud::Component
|
9
|
+
|
10
|
+
@@objects = []
|
11
|
+
|
12
|
+
def initialize ( fog_interfaces, log, options = {} )
|
13
|
+
|
14
|
+
@iam = fog_interfaces[:iam]
|
15
|
+
@log = log
|
16
|
+
@options = options
|
17
|
+
|
18
|
+
@log.debug( options.inspect )
|
19
|
+
|
20
|
+
required_options(:name, :policy_document)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def create
|
26
|
+
|
27
|
+
unless exists?
|
28
|
+
|
29
|
+
@log.info( "Creating new IAM policy #{@options[:name]}" )
|
30
|
+
|
31
|
+
policy = @iam.create_policy(@options[:name],JSON.parse(@options[:policy_document]), @options[:policy_path], @options[:policy_description])
|
32
|
+
|
33
|
+
@log.debug( policy.inspect )
|
34
|
+
|
35
|
+
else
|
36
|
+
policy = fog_object
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def read
|
42
|
+
@iam.managed_policies.select { |r| r.name == @options[:name] }.first
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :fog_object, :read
|
46
|
+
|
47
|
+
def delete
|
48
|
+
|
49
|
+
return unless exists?
|
50
|
+
|
51
|
+
@log.info( "Deleting IAM managed policy #{@options[:name]}" )
|
52
|
+
@fog.delete_policy(fog_object['Arn'])
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/build-cloud/iamrole.rb
CHANGED
@@ -19,43 +19,143 @@ class BuildCloud::IAMRole
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def create
|
22
|
-
|
23
|
-
return if exists?
|
24
|
-
|
25
|
-
@log.info( "Creating new IAM role for #{@options[:rolename]}" )
|
26
22
|
|
27
23
|
policies = @options.delete(:policies)
|
28
24
|
|
29
|
-
|
30
|
-
# this stuff. In particular how roles, instance profiles etc. relate
|
31
|
-
#
|
32
|
-
# It does what we need right now though, and can be revisited if necessary
|
25
|
+
unless exists?
|
33
26
|
|
34
|
-
|
35
|
-
role.save
|
27
|
+
@log.info( "Creating new IAM role for #{@options[:rolename]}" )
|
36
28
|
|
37
|
-
|
29
|
+
# Genuinely don't think I've understood the data model with
|
30
|
+
# this stuff. In particular how roles, instance profiles etc. relate
|
31
|
+
#
|
32
|
+
# It does what we need right now though, and can be revisited if necessary
|
38
33
|
|
39
|
-
|
34
|
+
role = @iam.roles.new( @options )
|
35
|
+
role.save
|
40
36
|
|
41
|
-
|
37
|
+
@log.debug( role.inspect )
|
42
38
|
|
43
|
-
@
|
39
|
+
@iam.create_instance_profile( @options[:rolename] )
|
44
40
|
|
45
|
-
|
46
|
-
|
47
|
-
@iam.put_role_policy( @options[:rolename], policy[:policy_name],
|
48
|
-
policy_document )
|
41
|
+
@iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] )
|
49
42
|
|
50
43
|
end
|
51
44
|
|
52
|
-
|
45
|
+
rationalise_policies( policies )
|
53
46
|
|
54
47
|
end
|
55
48
|
|
56
49
|
def read
|
57
50
|
@iam.roles.select { |r| r.rolename == @options[:rolename] }.first
|
58
51
|
end
|
52
|
+
|
53
|
+
|
54
|
+
def rationalise_policies( policies )
|
55
|
+
|
56
|
+
policies = {} if policies.nil?
|
57
|
+
|
58
|
+
managed_policies_to_add = []
|
59
|
+
current_policies = []
|
60
|
+
policies_to_add = []
|
61
|
+
|
62
|
+
# Read all the existing policies from the role object. Turn what we find into
|
63
|
+
# a list of hashes, where the hash parameter names match those that we use
|
64
|
+
# in the YAML description. This will aid comparison of current vs. desired policies
|
65
|
+
|
66
|
+
policy_names = @iam.list_role_policies(fog_object.rolename).body["PolicyNames"]
|
67
|
+
|
68
|
+
unless policy_names.nil?
|
69
|
+
|
70
|
+
policy_names.each do |policy_name|
|
71
|
+
|
72
|
+
c = {
|
73
|
+
:policy_document => @iam.get_role_policy(fog_object.rolename, policy_name).body["Policy"]["PolicyDocument"],
|
74
|
+
:policy_name => policy_name,
|
75
|
+
}
|
76
|
+
|
77
|
+
current_policies << c
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Build add lists
|
83
|
+
policies.each do |p|
|
84
|
+
@log.debug("Policy action on is #{p}")
|
85
|
+
if p[:arn]
|
86
|
+
# Ensure any Managed Policies are attached. Fog support is limited, so always adds
|
87
|
+
@log.debug("For group #{fog_object.rolename} adding managed policy #{p[:arn]}")
|
88
|
+
managed_policies_to_add << { :arn => p[:arn] }
|
89
|
+
elsif p[:policy_name]
|
90
|
+
@log.debug("For role #{fog_object.rolename} checking policy #{p[:policy_name]}")
|
91
|
+
# Assume adding policy
|
92
|
+
pa = {
|
93
|
+
:policy_document => JSON.parse(p[:policy_document]),
|
94
|
+
:policy_name => p[:policy_name],
|
95
|
+
}
|
96
|
+
policies_to_add << pa
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
policies.each do |p|
|
102
|
+
@log.debug("For role #{fog_object.rolename} policy #{p.inspect}")
|
103
|
+
|
104
|
+
# If we find a current policy that matches the desired policy, then
|
105
|
+
# remove that from the list of current policies - we will remove any
|
106
|
+
# remaining policies
|
107
|
+
current_policies.delete_if do |c|
|
108
|
+
if c[:policy_name] == p[:policy_name]
|
109
|
+
@log.debug( "#{p[:policy_name]} already exists" )
|
110
|
+
|
111
|
+
# Remove from the policies to add if the policy documents match
|
112
|
+
policies_to_add.delete_if do |a|
|
113
|
+
if (c[:policy_name] == a[:policy_name]) and
|
114
|
+
(c[:policy_document] == a[:policy_document])
|
115
|
+
@log.debug("#{p[:policy_name]} is a match" )
|
116
|
+
true
|
117
|
+
else
|
118
|
+
@log.debug("#{p[:policy_name]} is different" )
|
119
|
+
@log.debug("new policy is '#{a[:policy_document]}'")
|
120
|
+
@log.debug("current policy is '#{c[:policy_document]}'")
|
121
|
+
false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
true # so that delete_if removes the list item
|
125
|
+
else
|
126
|
+
false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# At the end of this loop, anything left in the current_policies list
|
132
|
+
# represents a policy that's present on the infra, but should be deleted
|
133
|
+
# (since there's no matching desired policy), so delete those.
|
134
|
+
|
135
|
+
current_policies.each do |p|
|
136
|
+
|
137
|
+
@log.debug( "Removing policy #{p.inspect}" )
|
138
|
+
@log.info( "For role #{fog_object.rolename} removing policy #{p[:policy_name]}" )
|
139
|
+
@iam.delete_role_policy(fog_object.rolename, p[:policy_name])
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
policies_to_add.each do |p|
|
144
|
+
|
145
|
+
@log.debug( "For role #{fog_object.rolename} adding/updating policy #{p}" )
|
146
|
+
@log.info( "For role #{fog_object.rolename} adding/updating policy #{p[:policy_name]}" )
|
147
|
+
@iam.put_role_policy( fog_object.rolename, p[:policy_name], p[:policy_document] )
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
# IAM Role Policy support is not complete in fog-aws, always attach policy
|
152
|
+
managed_policies_to_add.each do |p|
|
153
|
+
@log.debug( "For role #{fog_object.rolename} attaching policy #{p}" )
|
154
|
+
@log.info( "For role #{fog_object.rolename} attaching policy #{p[:arn]}" )
|
155
|
+
@iam.attach_role_policy(fog_object.rolename, p[:arn])
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
59
159
|
|
60
160
|
alias_method :fog_object, :read
|
61
161
|
|
@@ -82,4 +182,3 @@ class BuildCloud::IAMRole
|
|
82
182
|
end
|
83
183
|
|
84
184
|
end
|
85
|
-
|
@@ -0,0 +1,191 @@
|
|
1
|
+
class BuildCloud::IAMUser
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
include ::BuildCloud::Component
|
6
|
+
|
7
|
+
@@objects = []
|
8
|
+
|
9
|
+
def initialize ( fog_interfaces, log, options = {} )
|
10
|
+
|
11
|
+
@iam = fog_interfaces[:iam]
|
12
|
+
@log = log
|
13
|
+
@options = options
|
14
|
+
|
15
|
+
@log.debug( options.inspect )
|
16
|
+
|
17
|
+
required_options(:id)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
|
23
|
+
policies = @options.delete(:policies)
|
24
|
+
groups = @options.delete(:groups)
|
25
|
+
|
26
|
+
unless exists?
|
27
|
+
|
28
|
+
@log.info( "Creating new IAM user #{@options[:id]}" )
|
29
|
+
|
30
|
+
user = @iam.users.new( @options )
|
31
|
+
user.save
|
32
|
+
|
33
|
+
@log.debug( user.inspect )
|
34
|
+
else
|
35
|
+
user = fog_object
|
36
|
+
end
|
37
|
+
|
38
|
+
@log.debug("User is : #{user.inspect}")
|
39
|
+
|
40
|
+
#if there are :policies: attach and remove any not listed
|
41
|
+
# if a policy is managed then it requires an arn, and to be created under :iam_managed_policies:
|
42
|
+
# or amazons policy arns
|
43
|
+
# if a policy is a user one, then it needs :name: and :document:
|
44
|
+
rationalise_policies( policies )
|
45
|
+
|
46
|
+
# Users are added to groups under :iam_groups:
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def rationalise_policies( policies )
|
51
|
+
|
52
|
+
policies = {} if policies.nil?
|
53
|
+
|
54
|
+
managed_policies_to_add = []
|
55
|
+
user_policies_to_add = []
|
56
|
+
current_managed_policies = []
|
57
|
+
current_user_policies = []
|
58
|
+
|
59
|
+
fog_object.attached_policies.each do |p|
|
60
|
+
current_managed_policies << { :arn => p.arn }
|
61
|
+
end
|
62
|
+
|
63
|
+
fog_object.policies.each do |p|
|
64
|
+
current_user_policies << { :document => p.document, :id => p.id }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build add lists
|
68
|
+
policies.each do |p|
|
69
|
+
@log.debug("Policy action on is #{p}")
|
70
|
+
if p[:arn]
|
71
|
+
@log.debug("For user #{fog_object.id} checking managed policy #{p[:arn]}")
|
72
|
+
# Assume adding policy
|
73
|
+
add_policy = true
|
74
|
+
current_managed_policies.each do |cmp|
|
75
|
+
add_policy = false if cmp[:arn] == p[:arn]
|
76
|
+
end
|
77
|
+
if add_policy
|
78
|
+
@log.debug("Adding #{p[:arn]} to list" )
|
79
|
+
managed_policies_to_add << { :arn => p[:arn] }
|
80
|
+
end
|
81
|
+
elsif p[:id]
|
82
|
+
@log.debug("For user #{fog_object.id} checking policy #{p[:id]}")
|
83
|
+
# Assume adding policy
|
84
|
+
pa = {
|
85
|
+
:document => JSON.parse(p[:document]),
|
86
|
+
:id => p[:id],
|
87
|
+
}
|
88
|
+
user_policies_to_add << pa
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
policies.each do |p|
|
93
|
+
# If we find a current policy that matches the desired policy, then
|
94
|
+
# remove that from the list of current policies - we will remove any
|
95
|
+
# remaining policies
|
96
|
+
if p[:arn]
|
97
|
+
current_managed_policies.delete_if do |c|
|
98
|
+
if c[:arn] == p[:arn]
|
99
|
+
@log.debug( "#{p[:arn]} already exists" )
|
100
|
+
true # so that delete_if removes the list item
|
101
|
+
else
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
elsif p[:id]
|
106
|
+
current_user_policies.delete_if do |c|
|
107
|
+
if c[:id] == p[:id]
|
108
|
+
@log.debug( "#{p[:id]} already exists" )
|
109
|
+
|
110
|
+
# Remove from the policies to add if the policy documents match
|
111
|
+
user_policies_to_add.delete_if do |a|
|
112
|
+
if (c[:id] == a[:id]) and
|
113
|
+
(c[:document] == a[:document])
|
114
|
+
@log.debug("#{p[:id]} is a match" )
|
115
|
+
true
|
116
|
+
else
|
117
|
+
false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
true # so that delete_if removes the list item
|
121
|
+
else
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# At the end of this loop, anything left in the user_current_policies list
|
129
|
+
# represents a policy that's present on the infra, but should be deleted
|
130
|
+
# (since there's no matching desired policy), so delete those.
|
131
|
+
# Changing a rule maps to "delete old rule, create new one".
|
132
|
+
|
133
|
+
current_user_policies.each do |p|
|
134
|
+
@log.debug( "Removing policy #{p.inspect}" )
|
135
|
+
@log.info( "For user #{fog_object.id} removing policy #{p[:id]}" )
|
136
|
+
@iam.delete_user_policy(fog_object.id, p[:id])
|
137
|
+
end
|
138
|
+
|
139
|
+
user_policies_to_add.each do |p|
|
140
|
+
@log.debug( "For user #{fog_object.id} adding/updating policy #{p}" )
|
141
|
+
@log.info( "For user #{fog_object.id} adding/updating policy #{p[:id]}" )
|
142
|
+
@iam.put_user_policy( fog_object.id, p[:id], p[:document] )
|
143
|
+
end
|
144
|
+
|
145
|
+
# And the same for managed policies, but we just detatch them:
|
146
|
+
current_managed_policies.each do |p|
|
147
|
+
@log.debug( "Detatching policy #{p.inspect}" )
|
148
|
+
@log.info( "For user #{fog_object.id} detatcing policy #{p[:arn]}" )
|
149
|
+
fog_object.detach(p[:arn])
|
150
|
+
end
|
151
|
+
|
152
|
+
managed_policies_to_add.each do |p|
|
153
|
+
@log.debug( "For user #{fog_object.id} attaching policy #{p}" )
|
154
|
+
@log.info( "For user #{fog_object.id} attaching policy #{p[:arn]}" )
|
155
|
+
mp = @iam.managed_policies.select { |r| r.arn == p[:arn] }.first
|
156
|
+
mp.attach(fog_object)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
def read
|
162
|
+
@iam.users.select { |r| r.id == @options[:id] }.first
|
163
|
+
end
|
164
|
+
|
165
|
+
alias_method :fog_object, :read
|
166
|
+
|
167
|
+
def delete
|
168
|
+
|
169
|
+
return unless exists?
|
170
|
+
@log.info( "Deleting IAM users for #{@options[:id]}" )
|
171
|
+
|
172
|
+
#detach all policies
|
173
|
+
#Manged Policies
|
174
|
+
fog_object.attached_policies.each do |p|
|
175
|
+
fog_object.detach(p)
|
176
|
+
end
|
177
|
+
|
178
|
+
fog_object.policies.each do |p|
|
179
|
+
@iam.delete_user_policy(@options[:id], p.id)
|
180
|
+
end
|
181
|
+
|
182
|
+
#remove from group
|
183
|
+
@iam.list_groups_for_user(@options[:id]).body['GroupsForUser'].each do |g|
|
184
|
+
@iam.remove_user_from_group(g['GroupName'], fog_object.id)
|
185
|
+
end
|
186
|
+
|
187
|
+
#remove all users
|
188
|
+
fog_object.destroy
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/lib/build-cloud/s3bucket.rb
CHANGED
@@ -18,14 +18,19 @@ class BuildCloud::S3Bucket
|
|
18
18
|
|
19
19
|
def create
|
20
20
|
|
21
|
-
|
21
|
+
policy = @options.delete(:policy)
|
22
|
+
|
23
|
+
unless exists?
|
22
24
|
|
23
|
-
|
25
|
+
@log.info( "Creating new S3 bucket #{@options[:key]}" )
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
bucket = @s3.directories.new( @options )
|
28
|
+
bucket.save
|
27
29
|
|
28
|
-
|
30
|
+
@log.debug( bucket.inspect )
|
31
|
+
end
|
32
|
+
|
33
|
+
rationalise_policies( policy )
|
29
34
|
|
30
35
|
end
|
31
36
|
|
@@ -44,6 +49,31 @@ class BuildCloud::S3Bucket
|
|
44
49
|
fog_object.destroy
|
45
50
|
|
46
51
|
end
|
52
|
+
|
53
|
+
def rationalise_policies( policy )
|
47
54
|
|
48
|
-
|
55
|
+
policy = JSON.parse(policy) unless policy.nil?
|
56
|
+
@log.debug("Policy inspect #{policy.inspect}")
|
57
|
+
|
58
|
+
begin
|
59
|
+
@log.debug("Inspect #{@s3.get_bucket_policy(fog_object.key)}")
|
60
|
+
current_policy = @s3.get_bucket_policy(fog_object.key)
|
61
|
+
rescue Excon::Errors::NotFound
|
62
|
+
current_policy = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
@log.debug("Current Policy inspect #{current_policy.inspect}")
|
66
|
+
|
67
|
+
if policy.nil? and current_policy.nil?
|
68
|
+
return
|
69
|
+
elsif policy.nil? and current_policy.any?
|
70
|
+
@log.info("Existing policy here, deleting it")
|
71
|
+
@s3.delete_bucket_policy(fog_object.key)
|
72
|
+
elsif policy != current_policy
|
73
|
+
@log.info( "For bucket #{fog_object.key} adding/updating policy #{p}" )
|
74
|
+
@s3.put_bucket_policy( fog_object.key, policy )
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
49
78
|
|
79
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: build-cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The Scale Factory
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -93,7 +93,10 @@ files:
|
|
93
93
|
- lib/build-cloud/dbsubnetgroup.rb
|
94
94
|
- lib/build-cloud/dhcpoptionsset.rb
|
95
95
|
- lib/build-cloud/ebsvolume.rb
|
96
|
+
- lib/build-cloud/iamgroup.rb
|
97
|
+
- lib/build-cloud/iammanagedpolicy.rb
|
96
98
|
- lib/build-cloud/iamrole.rb
|
99
|
+
- lib/build-cloud/iamuser.rb
|
97
100
|
- lib/build-cloud/instance.rb
|
98
101
|
- lib/build-cloud/internetgateway.rb
|
99
102
|
- lib/build-cloud/launchconfiguration.rb
|