cloud-mu 3.1.2 → 3.2.0

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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +10 -13
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +2 -3
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +135 -37
  23. data/cloud-mu.gemspec +22 -20
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +165 -111
  45. data/modules/mu/adoption.rb +401 -68
  46. data/modules/mu/cleanup.rb +199 -306
  47. data/modules/mu/cloud.rb +100 -1632
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +46 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +920 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +165 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +4 -4
  61. data/modules/mu/config/cache_cluster.rb +1 -1
  62. data/modules/mu/config/collection.rb +4 -4
  63. data/modules/mu/config/container_cluster.rb +9 -4
  64. data/modules/mu/config/database.rb +83 -104
  65. data/modules/mu/config/database.yml +1 -2
  66. data/modules/mu/config/dnszone.rb +6 -6
  67. data/modules/mu/config/doc_helpers.rb +516 -0
  68. data/modules/mu/config/endpoint.rb +4 -4
  69. data/modules/mu/config/firewall_rule.rb +103 -4
  70. data/modules/mu/config/folder.rb +4 -4
  71. data/modules/mu/config/function.rb +3 -3
  72. data/modules/mu/config/group.rb +4 -4
  73. data/modules/mu/config/habitat.rb +4 -4
  74. data/modules/mu/config/loadbalancer.rb +60 -14
  75. data/modules/mu/config/log.rb +4 -4
  76. data/modules/mu/config/msg_queue.rb +4 -4
  77. data/modules/mu/config/nosqldb.rb +4 -4
  78. data/modules/mu/config/notifier.rb +3 -3
  79. data/modules/mu/config/ref.rb +365 -0
  80. data/modules/mu/config/role.rb +4 -4
  81. data/modules/mu/config/schema_helpers.rb +509 -0
  82. data/modules/mu/config/search_domain.rb +4 -4
  83. data/modules/mu/config/server.rb +97 -70
  84. data/modules/mu/config/server.yml +1 -0
  85. data/modules/mu/config/server_pool.rb +5 -9
  86. data/modules/mu/config/storage_pool.rb +1 -1
  87. data/modules/mu/config/tail.rb +200 -0
  88. data/modules/mu/config/user.rb +4 -4
  89. data/modules/mu/config/vpc.rb +70 -27
  90. data/modules/mu/config/vpc.yml +0 -1
  91. data/modules/mu/defaults/AWS.yaml +83 -60
  92. data/modules/mu/defaults/Azure.yaml +1 -0
  93. data/modules/mu/defaults/Google.yaml +3 -2
  94. data/modules/mu/deploy.rb +30 -26
  95. data/modules/mu/groomer.rb +17 -2
  96. data/modules/mu/groomers/ansible.rb +188 -41
  97. data/modules/mu/groomers/chef.rb +116 -55
  98. data/modules/mu/logger.rb +127 -148
  99. data/modules/mu/master.rb +389 -2
  100. data/modules/mu/master/chef.rb +3 -4
  101. data/modules/mu/master/ldap.rb +3 -3
  102. data/modules/mu/master/ssl.rb +12 -3
  103. data/modules/mu/mommacat.rb +217 -2612
  104. data/modules/mu/mommacat/daemon.rb +397 -0
  105. data/modules/mu/mommacat/naming.rb +473 -0
  106. data/modules/mu/mommacat/search.rb +495 -0
  107. data/modules/mu/mommacat/storage.rb +722 -0
  108. data/modules/mu/{clouds → providers}/README.md +1 -1
  109. data/modules/mu/{clouds → providers}/aws.rb +271 -112
  110. data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
  111. data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
  112. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
  113. data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
  114. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
  115. data/modules/mu/providers/aws/database.rb +1744 -0
  116. data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
  117. data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
  118. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
  119. data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
  120. data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
  121. data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
  122. data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
  123. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
  124. data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
  125. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
  126. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
  127. data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
  128. data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
  129. data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
  130. data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
  131. data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
  132. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
  133. data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
  134. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  135. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  136. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  137. data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
  138. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  139. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  140. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  141. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  142. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  143. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  144. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  145. data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
  146. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  147. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  148. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  149. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  150. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  151. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  152. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  153. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  156. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  160. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  161. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  162. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  163. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  164. data/modules/mu/{clouds → providers}/google.rb +67 -30
  165. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  166. data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
  167. data/modules/mu/{clouds → providers}/google/database.rb +10 -20
  168. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  169. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  170. data/modules/mu/{clouds → providers}/google/function.rb +139 -167
  171. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  172. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  173. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
  174. data/modules/mu/{clouds → providers}/google/role.rb +92 -58
  175. data/modules/mu/{clouds → providers}/google/server.rb +242 -155
  176. data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
  177. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  178. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  179. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  180. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  181. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  182. data/modules/tests/bucket.yml +4 -0
  183. data/modules/tests/centos6.yaml +11 -0
  184. data/modules/tests/centos7.yaml +11 -0
  185. data/modules/tests/centos8.yaml +12 -0
  186. data/modules/tests/ecs.yaml +23 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/rds.yaml +108 -0
  189. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  190. data/modules/tests/regrooms/bucket.yml +19 -0
  191. data/modules/tests/regrooms/rds.yaml +123 -0
  192. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  193. data/modules/tests/super_simple_bok.yml +1 -3
  194. data/modules/tests/win2k12.yaml +17 -5
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +232 -154
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -203,6 +203,9 @@ module MU
203
203
  # @param region [String]: The cloud provider region
204
204
  # @return [void]
205
205
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
206
+ MU.log "AWS::Log.cleanup: need to support flags['known']", MU::DEBUG, details: flags
207
+ MU.log "Placeholder: AWS Log artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
208
+
206
209
  log_groups = self.find(credentials: credentials, region: region).values
207
210
  if !log_groups.empty?
208
211
  log_groups.each{ |lg|
@@ -227,13 +230,13 @@ module MU
227
230
  }
228
231
  end
229
232
 
230
- unless noop
231
- MU::Cloud::AWS.iam(credentials: credentials).list_roles.roles.each{ |role|
232
- match_string = "#{MU.deploy_id}.*CloudTrail"
233
- # Maybe we should have a more generic way to delete IAM profiles and policies. The call itself should be moved from MU::Cloud::AWS::Server.
234
- # MU::Cloud::AWS::Server.removeIAMProfile(role.role_name) if role.role_name.match(match_string)
235
- }
236
- end
233
+ # unless noop
234
+ # MU::Cloud::AWS.iam(credentials: credentials).list_roles.roles.each{ |role|
235
+ # match_string = "#{MU.deploy_id}.*CloudTrail"
236
+ # Maybe we should have a more generic way to delete IAM profiles and policies. The call itself should be moved from MU::Cloud.resourceClass("AWS", "Server").
237
+ # MU::Cloud.resourceClass("AWS", "Server").removeIAMProfile(role.role_name) if role.role_name.match(match_string)
238
+ # }
239
+ # end
237
240
  end
238
241
 
239
242
  # Locate an existing log group.
@@ -264,7 +267,7 @@ module MU
264
267
  # Reverse-map our cloud description into a runnable config hash.
265
268
  # We assume that any values we have in +@config+ are placeholders, and
266
269
  # calculate our own accordingly based on what's live in the cloud.
267
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
270
+ def toKitten(**_args)
268
271
  bok = {
269
272
  "cloud" => "AWS",
270
273
  "credentials" => @config['credentials'],
@@ -304,9 +307,9 @@ module MU
304
307
 
305
308
 
306
309
  # Cloud-specific configuration properties.
307
- # @param config [MU::Config]: The calling MU::Config object
310
+ # @param _config [MU::Config]: The calling MU::Config object
308
311
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
309
- def self.schema(config)
312
+ def self.schema(_config)
310
313
  toplevel_required = []
311
314
  schema = {
312
315
  "retention_period" => {
@@ -357,9 +360,9 @@ module MU
357
360
 
358
361
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::logs}, bare and unvalidated.
359
362
  # @param log [Hash]: The resource to process and validate
360
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
363
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
361
364
  # @return [Boolean]: True if validation succeeded, False otherwise
362
- def self.validateConfig(log, configurator)
365
+ def self.validateConfig(log, _configurator)
363
366
  ok = true
364
367
 
365
368
  if log["filters"] && !log["filters"].empty?
@@ -53,14 +53,14 @@ module MU
53
53
  new_attrs = genQueueAttrs
54
54
 
55
55
  changed = false
56
- new_attrs.each_pair { |k, v|
56
+ new_attrs.each_pair { |k, _v|
57
57
  if !cur_attrs.has_key?(k) or cur_attrs[k] != new_attrs[k]
58
58
  changed = true
59
59
  end
60
60
  }
61
61
  if changed
62
62
  MU.log "Updating SQS queue #{@mu_name}", MU::NOTICE, details: new_attrs
63
- resp = MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).set_queue_attributes(
63
+ MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).set_queue_attributes(
64
64
  queue_url: @cloud_id,
65
65
  attributes: new_attrs
66
66
  )
@@ -74,10 +74,13 @@ module MU
74
74
  "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":sqs:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":"+@cloud_id
75
75
  end
76
76
 
77
+ @cloud_desc_cache = nil
77
78
  # Retrieve the AWS descriptor for this SQS queue. AWS doesn't exactly
78
79
  # provide one; if you want real information for SQS ask notify()
79
80
  # @return [Hash]: AWS doesn't return anything but the SQS URL, so supplement with attributes
80
- def cloud_desc
81
+ def cloud_desc(use_cache: true)
82
+ return @cloud_desc_cache if @cloud_desc_cache and use_cache
83
+
81
84
  if !@cloud_id
82
85
  resp = MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).list_queues(
83
86
  queue_name_prefix: @mu_name
@@ -92,11 +95,12 @@ module MU
92
95
  end
93
96
 
94
97
  return nil if !@cloud_id
95
- MU::Cloud::AWS::MsgQueue.find(
98
+ @cloud_desc_cache = MU::Cloud::AWS::MsgQueue.find(
96
99
  cloud_id: @cloud_id.dup,
97
100
  region: @config['region'],
98
101
  credentials: @config['credentials']
99
102
  )
103
+ @cloud_desc_cache
100
104
  end
101
105
 
102
106
  # Return the metadata for this MsgQueue rule
@@ -130,6 +134,9 @@ module MU
130
134
  # @param region [String]: The cloud provider region
131
135
  # @return [void]
132
136
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
137
+ MU.log "AWS::MsgQueue.cleanup: need to support flags['known']", MU::DEBUG, details: flags
138
+ MU.log "Placeholder: AWS MsgQueue artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
139
+
133
140
  resp = MU::Cloud::AWS.sqs(credentials: credentials, region: region).list_queues(
134
141
  queue_name_prefix: MU.deploy_id
135
142
  )
@@ -182,7 +189,7 @@ module MU
182
189
  args[:cloud_id] = resp.queue_url if resp and resp.queue_url
183
190
  end
184
191
  end
185
- rescue ::Aws::SQS::Errors::NonExistentQueue => e
192
+ rescue ::Aws::SQS::Errors::NonExistentQueue
186
193
  end
187
194
 
188
195
  # Go fetch its attributes
@@ -211,9 +218,9 @@ module MU
211
218
  end
212
219
 
213
220
  # Cloud-specific configuration properties.
214
- # @param config [MU::Config]: The calling MU::Config object
221
+ # @param _config [MU::Config]: The calling MU::Config object
215
222
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
216
- def self.schema(config)
223
+ def self.schema(_config)
217
224
  toplevel_required = []
218
225
  schema = {
219
226
  "max_msg_size" => {
@@ -320,16 +327,10 @@ module MU
320
327
  failq.delete("failqueue")
321
328
  ok = false if !configurator.insertKitten(failq, "msg_queues")
322
329
  queue['failqueue']['name'] = failq['name']
323
- queue['dependencies'] << {
324
- "name" => failq['name'],
325
- "type" => "msg_queue"
326
- }
330
+ MU::Config.addDependency(queue, failq["name"], "msg_queue")
327
331
  else
328
332
  if configurator.haveLitterMate?(queue['failqueue']['name'], "msg_queue")
329
- queue['dependencies'] << {
330
- "name" => queue['failqueue']['name'],
331
- "type" => "msg_queue"
332
- }
333
+ MU::Config.addDependency(queue, queue['failqueue']['name'], "msg_queue")
333
334
  else
334
335
  failq = MU::Cloud::AWS::MsgQueue.find(cloud_id: queue['failqueue']['name'])
335
336
  if !failq
@@ -382,7 +383,7 @@ module MU
382
383
  end
383
384
  begin
384
385
  MU::Cloud::AWS.kms(region: queue['region']).describe_key(key_id: queue['kms']['key_id'])
385
- rescue Aws::KMS::Errors::NotFoundException => e
386
+ rescue Aws::KMS::Errors::NotFoundException
386
387
  MU.log "KMS key '#{queue['kms']['key_id']}' specified in Queue '#{queue['name']}' was not found.", MU::ERR, details: "Key IDs are of the form bf64a093-2c3d-46fa-0d4f-8232fa7ed53. Keys can be created at https://console.aws.amazon.com/iam/home#/encryptionKeys/#{queue['region']}"
387
388
  ok = false
388
389
  end
@@ -164,6 +164,8 @@ module MU
164
164
  # @param region [String]: The cloud provider region
165
165
  # @return [void]
166
166
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
167
+ MU.log "AWS::NoSQLDb.cleanup: need to support flags['known']", MU::DEBUG, details: flags
168
+
167
169
  resp = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).list_tables
168
170
  if resp and resp.table_names
169
171
  resp.table_names.each { |table|
@@ -178,16 +180,23 @@ module MU
178
180
  begin
179
181
  tags = MU::Cloud::AWS.dynamo(credentials: credentials, region: region).list_tags_of_resource(resource_arn: desc.table_arn)
180
182
  if tags and tags.tags
183
+ deploy_match = false
184
+ master_match = false
181
185
  tags.tags.each { |tag|
182
186
  if tag.key == "MU-ID" and tag.value == MU.deploy_id
183
- MU.log "Deleting DynamoDB table #{desc.table_name}"
184
- if !noop
185
- MU::Cloud::AWS.dynamo(credentials: credentials, region: region).delete_table(table_name: desc.table_name)
186
- end
187
+ deploy_match = true
188
+ elsif tag.key == "MU-MASTER-IP" and tag.value == MU.mu_public_ip
189
+ master_match = true
187
190
  end
188
191
  }
192
+ if deploy_match and (master_match or ignoremaster)
193
+ MU.log "Deleting DynamoDB table #{desc.table_name}"
194
+ if !noop
195
+ MU::Cloud::AWS.dynamo(credentials: credentials, region: region).delete_table(table_name: desc.table_name)
196
+ end
197
+ end
189
198
  end
190
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException => e
199
+ rescue Aws::DynamoDB::Errors::ResourceNotFoundException
191
200
  end
192
201
 
193
202
  }
@@ -236,9 +245,9 @@ module MU
236
245
  end
237
246
 
238
247
  # Cloud-specific configuration properties.
239
- # @param config [MU::Config]: The calling MU::Config object
248
+ # @param _config [MU::Config]: The calling MU::Config object
240
249
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
241
- def self.schema(config)
250
+ def self.schema(_config)
242
251
  toplevel_required = ["attributes"]
243
252
 
244
253
 
@@ -360,9 +369,9 @@ module MU
360
369
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::nosqldbs}, bare and unvalidated.
361
370
 
362
371
  # @param db [Hash]: The resource to process and validate
363
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
372
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
364
373
  # @return [Boolean]: True if validation succeeded, False otherwise
365
- def self.validateConfig(db, configurator)
374
+ def self.validateConfig(db, _configurator)
366
375
  ok = true
367
376
 
368
377
  partition = nil
@@ -399,8 +408,6 @@ module MU
399
408
  ok
400
409
  end
401
410
 
402
- private
403
-
404
411
  end
405
412
  end
406
413
  end
@@ -66,12 +66,17 @@ module MU
66
66
  # @param region [String]: The cloud provider region
67
67
  # @return [void]
68
68
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
69
+ MU.log "AWS::Notifier.cleanup: need to support flags['known']", MU::DEBUG, details: flags
70
+ MU.log "Placeholder: AWS Notifier artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
71
+
69
72
  MU::Cloud::AWS.sns(region: region, credentials: credentials).list_topics.topics.each { |topic|
70
73
  if topic.topic_arn.match(MU.deploy_id)
71
74
  # We don't have a way to tag our SNS topics, so we will delete any topic that has the MU-ID in its ARN.
72
75
  # This may fail to find notifier groups in some cases (eg. cache_cluster) so we might want to delete from each API as well.
73
- MU::Cloud::AWS.sns(region: region, credentials: credentials).delete_topic(topic_arn: topic.topic_arn)
74
- MU.log "Deleted SNS topic: #{topic.topic_arn}"
76
+ MU.log "Deleting SNS topic: #{topic.topic_arn}"
77
+ if !noop
78
+ MU::Cloud::AWS.sns(region: region, credentials: credentials).delete_topic(topic_arn: topic.topic_arn)
79
+ end
75
80
  end
76
81
  }
77
82
  end
@@ -116,9 +121,9 @@ module MU
116
121
  end
117
122
 
118
123
  # Cloud-specific configuration properties.
119
- # @param config [MU::Config]: The calling MU::Config object
124
+ # @param _config [MU::Config]: The calling MU::Config object
120
125
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
121
- def self.schema(config)
126
+ def self.schema(_config)
122
127
  toplevel_required = []
123
128
  schema = {
124
129
  "subscriptions" => {
@@ -143,9 +148,9 @@ module MU
143
148
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::notifier}, bare and unvalidated.
144
149
 
145
150
  # @param notifier [Hash]: The resource to process and validate
146
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
151
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
147
152
  # @return [Boolean]: True if validation succeeded, False otherwise
148
- def self.validateConfig(notifier, configurator)
153
+ def self.validateConfig(notifier, _configurator)
149
154
  ok = true
150
155
 
151
156
  if notifier['subscriptions']
@@ -43,7 +43,7 @@ module MU
43
43
 
44
44
  policy_name = @mu_name+"-"+policy.keys.first.upcase
45
45
  MU.log "Creating IAM policy #{policy_name}"
46
- resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).create_policy(
46
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).create_policy(
47
47
  policy_name: policy_name,
48
48
  path: "/"+@deploy.deploy_id+"/",
49
49
  policy_document: JSON.generate(policy.values.first),
@@ -56,8 +56,8 @@ module MU
56
56
  MU.log "Creating IAM role #{@mu_name}"
57
57
  @cloud_id = @mu_name
58
58
  path = @config['strip_path'] ? nil : "/"+@deploy.deploy_id+"/"
59
- resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).create_role(
60
- path: nil,
59
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).create_role(
60
+ path: path,
61
61
  role_name: @mu_name,
62
62
  description: "Generated by Mu",
63
63
  assume_role_policy_document: gen_assume_role_policy_doc,
@@ -89,7 +89,6 @@ module MU
89
89
  end
90
90
 
91
91
  if @config['raw_policies'] or @config['attachable_policies']
92
- attached_policies = []
93
92
  configured_policies = []
94
93
 
95
94
  if @config['raw_policies']
@@ -128,7 +127,7 @@ module MU
128
127
 
129
128
  # XXX not sure we're binding these sanely, validate that
130
129
  if @config['raw_policies']
131
- pol_arns = MU::Cloud::AWS::Role.manageRawPolicies(
130
+ MU::Cloud::AWS::Role.manageRawPolicies(
132
131
  @config['raw_policies'],
133
132
  basename: @deploy.getResourceName(@config['name']),
134
133
  credentials: @credentials
@@ -183,7 +182,7 @@ module MU
183
182
  desc
184
183
  end
185
184
 
186
- rescue Aws::IAM::Errors::NoSuchEntity => e
185
+ rescue Aws::IAM::Errors::NoSuchEntity
187
186
  MU.log "Creating IAM policy #{policy_name}", details: policy.values.first
188
187
  MU::Cloud::AWS.iam(credentials: credentials).create_policy(
189
188
  policy_name: policy_name,
@@ -202,65 +201,72 @@ module MU
202
201
  def arn
203
202
  desc = cloud_desc
204
203
  if desc["role"]
205
- desc["role"].arn
204
+ if desc['role'].is_a?(Hash)
205
+ desc["role"][:arn] # why though
206
+ else
207
+ desc["role"].arn
208
+ end
206
209
  else
207
210
  nil
208
211
  end
209
212
  end
210
213
 
214
+ @cloud_desc_cache = nil
211
215
  # Return a hash containing a +role+ element and a +policies+ element,
212
216
  # populated with one or both depending on what this resource has
213
217
  # defined.
214
- def cloud_desc
215
- desc = {}
218
+ def cloud_desc(use_cache: true)
219
+ return @cloud_desc_cache if @cloud_desc_cache and use_cache
220
+
221
+ @cloud_desc_cache = {}
216
222
  if @config['bare_policies']
217
223
  if @cloud_id
218
224
  pol_desc = MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @cloud_id).values.first
219
225
  if pol_desc
220
- desc['policies'] = [pol_desc]
221
- return desc
226
+ @cloud_desc_cache['policies'] = [pol_desc]
227
+ return @cloud_desc_cache
222
228
  end
223
229
  end
224
230
 
225
231
  if @deploy and @deploy.deploy_id
226
- desc["policies"] = MU::Cloud::AWS.iam(credentials: @credentials).list_policies(
232
+ @cloud_desc_cache["policies"] = MU::Cloud::AWS.iam(credentials: @credentials).list_policies(
227
233
  path_prefix: "/"+@deploy.deploy_id+"/"
228
234
  ).policies
229
- desc["policies"].reject! { |p|
235
+ @cloud_desc_cache["policies"].reject! { |p|
230
236
  !p.policy_name.match(/^#{Regexp.quote(@mu_name)}-/)
231
237
  }
232
238
  # this is quasi-wrong because we can be mulitple cloud is, but
233
239
  # we can't really set this type to has_multiples because that's
234
240
  # just how managed policies work not anything else, goddammit
235
241
  # AWS why can't you just bundle everything in roles
236
- if desc["policies"] and desc["policies"].size > 0
237
- @cloud_id ||= desc["policies"].first.arn
242
+ if @cloud_desc_cache["policies"] and @cloud_desc_cache["policies"].size > 0
243
+ @cloud_id ||= @cloud_desc_cache["policies"].first.arn
238
244
  end
239
245
  end
240
246
  else
241
247
  if @cloud_id.match(/^arn:aws(:?-us-gov)?:[^:]*:[^:]*:\d*:policy\//)
242
248
  pol_desc = MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @cloud_id).values.first
243
249
  if pol_desc
244
- desc['policies'] = [pol_desc]
245
- return desc
250
+ @cloud_desc_cache['policies'] = [pol_desc]
251
+ return @cloud_desc_cache
246
252
  end
247
253
  end
248
254
  begin
249
- desc['role'] = MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @cloud_id).values.first
250
- desc['role'] ||= MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @mu_name).values.first
255
+ @cloud_desc_cache['role'] = MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @cloud_id).values.first
256
+ @cloud_desc_cache['role'] ||= MU::Cloud::AWS::Role.find(credentials: @credentials, cloud_id: @mu_name).values.first
251
257
  MU::Cloud::AWS.iam(credentials: @credentials).list_attached_role_policies(
252
258
  role_name: @mu_name
253
259
  ).attached_policies.each { |p|
254
- desc["policies"] ||= []
255
- desc["policies"] << MU::Cloud::AWS.iam(credentials: @credentials).get_policy(
260
+ @cloud_desc_cache["policies"] ||= []
261
+ @cloud_desc_cache["policies"] << MU::Cloud::AWS.iam(credentials: @credentials).get_policy(
256
262
  policy_arn: p.policy_arn
257
263
  ).policy
258
264
  }
259
265
 
260
266
  inline = MU::Cloud::AWS.iam(credentials: @credentials).list_role_policies(role_name: @mu_name).policy_names
261
267
  inline.each { |pol_name|
262
- desc["policies"] ||= []
263
- desc["policies"] << MU::Cloud::AWS.iam(credentials: @credentials).get_role_policy(
268
+ @cloud_desc_cache["policies"] ||= []
269
+ @cloud_desc_cache["policies"] << MU::Cloud::AWS.iam(credentials: @credentials).get_role_policy(
264
270
  role_name: @mu_name,
265
271
  policy_name: pol_name
266
272
  )
@@ -270,9 +276,9 @@ rescue ::Aws::IAM::Errors::ValidationError => e
270
276
  MU.log @cloud_id+" "+@mu_name, MU::WARN, details: e.inspect
271
277
  end
272
278
  end
273
- desc['cloud_id'] ||= @cloud_id
279
+ @cloud_desc_cache['cloud_id'] ||= @cloud_id
274
280
 
275
- desc
281
+ @cloud_desc_cache
276
282
  end
277
283
 
278
284
  # Return the metadata for this user cofiguration
@@ -284,26 +290,25 @@ end
284
290
  # Insert a new target entity into an existing policy.
285
291
  # @param policy [String]: The name of the policy to which we're appending, which must already exist as part of this role resource
286
292
  # @param targets [Array<String>]: The target resource. If +target_type+ isn't specified, this should be a fully-resolved ARN.
287
- # @param mu_type [String]: A valid Mu resource type
288
- def injectPolicyTargets(policy, targets, mu_type = nil)
293
+ def injectPolicyTargets(policy, targets)
289
294
  if !policy.match(/^#{@deploy.deploy_id}/)
290
295
  policy = @mu_name+"-"+policy.upcase
291
296
  end
292
-
293
- my_policies = cloud_desc["policies"]
297
+ my_policies = cloud_desc(use_cache: false)["policies"]
294
298
  my_policies ||= []
295
-
299
+
300
+ seen_policy = false
296
301
  my_policies.each { |p|
297
302
  if p.policy_name == policy
303
+ seen_policy = true
298
304
  old = MU::Cloud::AWS.iam(credentials: @config['credentials']).get_policy_version(
299
305
  policy_arn: p.arn,
300
306
  version_id: p.default_version_id
301
307
  ).policy_version
302
308
 
303
309
  doc = JSON.parse URI.decode_www_form_component old.document
304
-
305
310
  need_update = false
306
-
311
+
307
312
  doc["Statement"].each { |s|
308
313
  targets.each { |target|
309
314
  target_string = target
@@ -332,6 +337,10 @@ end
332
337
  end
333
338
  end
334
339
  }
340
+
341
+ if !seen_policy
342
+ MU.log "Was given new targets for policy #{policy}, but I don't see any such policy attached to role #{@cloud_id}", MU::WARN, details: targets
343
+ end
335
344
  end
336
345
 
337
346
  # Delete an IAM policy, along with attendant versions and attachments.
@@ -409,9 +418,8 @@ end
409
418
  # Remove all roles associated with the currently loaded deployment.
410
419
  # @param noop [Boolean]: If true, will only print what would be done
411
420
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
412
- # @param region [String]: The cloud provider region
413
421
  # @return [void]
414
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
422
+ def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
415
423
 
416
424
  resp = MU::Cloud::AWS.iam(credentials: credentials).list_policies(
417
425
  path_prefix: "/"+MU.deploy_id+"/"
@@ -438,12 +446,18 @@ end
438
446
  # check tags. Hardly seems efficient.
439
447
  desc = MU::Cloud::AWS.iam(credentials: credentials).get_role(role_name: r.role_name)
440
448
  if desc.role and desc.role.tags and desc.role.tags
449
+ master_match = false
450
+ deploy_match = false
441
451
  desc.role.tags.each { |t|
442
452
  if t.key == "MU-ID" and t.value == MU.deploy_id
443
- deleteme << r
444
- break
453
+ deploy_match = true
454
+ elsif t.key == "MU-MASTER-IP" and t.value == MU.mu_public_ip
455
+ master_match = true
445
456
  end
446
457
  }
458
+ if deploy_match and (master_match or ignoremaster)
459
+ deleteme << r
460
+ end
447
461
  end
448
462
  }
449
463
 
@@ -481,7 +495,7 @@ end
481
495
  MU::Cloud::AWS.iam(credentials: credentials).delete_instance_profile(instance_profile_name: r.role_name)
482
496
  rescue Aws::IAM::Errors::ValidationError => e
483
497
  MU.log "Cleaning up IAM role #{r.role_name}: #{e.inspect}", MU::WARN
484
- rescue Aws::IAM::Errors::NoSuchEntity => e
498
+ rescue Aws::IAM::Errors::NoSuchEntity
485
499
  end
486
500
 
487
501
  MU::Cloud::AWS.iam(credentials: credentials).delete_role(
@@ -519,7 +533,7 @@ end
519
533
  end
520
534
  rescue ::Aws::IAM::Errors::NoSuchEntity
521
535
  end
522
-
536
+
523
537
  else
524
538
  marker = nil
525
539
  begin
@@ -552,7 +566,7 @@ end
552
566
  # Reverse-map our cloud description into a runnable config hash.
553
567
  # We assume that any values we have in +@config+ are placeholders, and
554
568
  # calculate our own accordingly based on what's live in the cloud.
555
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
569
+ def toKitten(**_args)
556
570
  bok = {
557
571
  "cloud" => "AWS",
558
572
  "credentials" => @config['credentials'],
@@ -601,14 +615,13 @@ end
601
615
  )
602
616
  JSON.parse(URI.decode(version.policy_version.document))
603
617
  end
604
-
605
618
  bok["policies"] = MU::Cloud::AWS::Role.doc2MuPolicies(pol.policy_name, doc, bok["policies"])
606
619
  end
607
620
  }
608
621
 
609
622
  return bok if @config['bare_policies']
610
623
  end
611
-
624
+
612
625
  if desc.tags and desc.tags.size > 0
613
626
  bok["tags"] = MU.structToHash(desc.tags, stringify_keys: true)
614
627
  end
@@ -681,6 +694,7 @@ end
681
694
  end
682
695
 
683
696
  bok["attachable_policies"].uniq! if bok["attachable_policies"]
697
+ bok["name"].gsub!(/[^a-zA-Z0-9_\-]/, "_")
684
698
 
685
699
  bok
686
700
  end
@@ -693,6 +707,10 @@ end
693
707
  def self.doc2MuPolicies(basename, doc, policies = [])
694
708
  policies ||= []
695
709
 
710
+ if !doc["Statement"].is_a?(Array)
711
+ doc["Statement"] = [doc["Statement"]]
712
+ end
713
+
696
714
  doc["Statement"].each { |s|
697
715
  if !s["Action"]
698
716
  MU.log "Statement in policy document for #{basename} didn't have an Action field", MU::WARN, details: doc
@@ -721,7 +739,7 @@ end
721
739
  "targets" => s["Resource"].map { |r|
722
740
  if r.match(/^arn:aws(-us-gov)?:([^:]+):.*?:([^:]*)$/)
723
741
  # XXX which cases even count for blind references to sibling resources?
724
- type = if Regexp.last_match[1] == "s3"
742
+ if Regexp.last_match[1] == "s3"
725
743
  "bucket"
726
744
  elsif Regexp.last_match[1]
727
745
  MU.log "Service #{Regexp.last_match[1]} to type...", MU::WARN, details: r
@@ -741,7 +759,7 @@ end
741
759
 
742
760
  # Attach this role or group of loose policies to the specified entity.
743
761
  # @param entitytype [String]: The type of entity (user, group or role for policies; instance_profile for roles)
744
- def bindTo(entitytype, entityname, policies = [])
762
+ def bindTo(entitytype, entityname)
745
763
  if entitytype == "instance_profile"
746
764
  begin
747
765
  resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).get_instance_profile(
@@ -754,7 +772,7 @@ end
754
772
  role_name: @mu_name
755
773
  )
756
774
  end
757
- rescue Exception => e
775
+ rescue StandardError => e
758
776
  MU.log "Error binding role #{@mu_name} to instance profile #{entityname}: #{e.message}", MU::ERR
759
777
  raise e
760
778
  end
@@ -783,7 +801,6 @@ end
783
801
  rescue Aws::IAM::Errors::NoSuchEntity => e
784
802
  if subpaths.size > 0
785
803
  p_arn = "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":iam::aws:policy/#{subpaths.shift}/"+policy
786
- retried = true
787
804
  retry
788
805
  end
789
806
  raise e
@@ -833,6 +850,7 @@ end
833
850
  else
834
851
  raise MuError, "Invalid entitytype '#{entitytype}' passed to MU::Cloud::AWS::Role.bindTo. Must be be one of: user, group, role, instance_profile"
835
852
  end
853
+ cloud_desc(use_cache: false)
836
854
  end
837
855
 
838
856
  # Create an instance profile for EC2 instances, named identically and
@@ -847,7 +865,7 @@ end
847
865
  MU::Cloud::AWS.iam(credentials: @config['credentials']).create_instance_profile(
848
866
  instance_profile_name: @mu_name
849
867
  )
850
- rescue Aws::IAM::Errors::EntityAlreadyExists => e
868
+ rescue Aws::IAM::Errors::EntityAlreadyExists
851
869
  MU::Cloud::AWS.iam(credentials: @config['credentials']).get_instance_profile(
852
870
  instance_profile_name: @mu_name
853
871
  )
@@ -905,13 +923,13 @@ end
905
923
  end
906
924
 
907
925
  # Cloud-specific configuration properties.
908
- # @param config [MU::Config]: The calling MU::Config object
926
+ # @param _config [MU::Config]: The calling MU::Config object
909
927
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
910
- def self.schema(config)
928
+ def self.schema(_config)
911
929
  toplevel_required = []
912
930
  aws_resource_types = MU::Cloud.resource_types.keys.reject { |t|
913
931
  begin
914
- MU::Cloud.loadCloudType("AWS", t)
932
+ MU::Cloud.resourceClass("AWS", t)
915
933
  false
916
934
  rescue MuCloudResourceNotImplemented
917
935
  true
@@ -1012,10 +1030,9 @@ end
1012
1030
  subpaths = ["service-role", "aws-service-role", "job-function"]
1013
1031
  begin
1014
1032
  MU::Cloud::AWS.iam(credentials: credentials).get_policy(policy_arn: arn)
1015
- rescue Aws::IAM::Errors::NoSuchEntity => e
1033
+ rescue Aws::IAM::Errors::NoSuchEntity
1016
1034
  if subpaths.size > 0
1017
1035
  arn = "arn:"+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+":iam::aws:policy/#{subpaths.shift}/"+ref["id"]
1018
- retried = true
1019
1036
  retry
1020
1037
  end
1021
1038
  MU.log "No such canned AWS IAM policy '#{arn}'", MU::ERR
@@ -1029,9 +1046,9 @@ end
1029
1046
 
1030
1047
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::roles}, bare and unvalidated.
1031
1048
  # @param role [Hash]: The resource to process and validate
1032
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
1049
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
1033
1050
  # @return [Boolean]: True if validation succeeded, False otherwise
1034
- def self.validateConfig(role, configurator)
1051
+ def self.validateConfig(role, _configurator)
1035
1052
  ok = true
1036
1053
 
1037
1054
  # munge things declared with the deprecated import keyword into
@@ -1074,11 +1091,7 @@ end
1074
1091
  role['policies'].each { |policy|
1075
1092
  policy['targets'].each { |target|
1076
1093
  if target['type']
1077
- role['dependencies'] ||= []
1078
- role['dependencies'] << {
1079
- "name" => target['identifier'],
1080
- "type" => target['type']
1081
- }
1094
+ MU::Config.addDependency(role, target['identifier'], target['type'])
1082
1095
  end
1083
1096
  }
1084
1097
  }
@@ -1094,9 +1107,7 @@ end
1094
1107
  # @param policies [Array<Hash>]: One or more policy chunks
1095
1108
  # @param deploy_obj [MU::MommaCat]: Deployment object to use when looking up sibling Mu resources
1096
1109
  # @return [Array<Hash>]
1097
- def self.genPolicyDocument(policies, deploy_obj: nil)
1098
- iam_policies = []
1099
-
1110
+ def self.genPolicyDocument(policies, deploy_obj: nil, bucket_style: false)
1100
1111
  if policies
1101
1112
  name = nil
1102
1113
  doc = {
@@ -1134,12 +1145,21 @@ end
1134
1145
  )
1135
1146
  if sibling
1136
1147
  id = sibling.cloudobj.arn
1137
- statement["Principal"] << id
1148
+ if bucket_style
1149
+ statement["Principal"] << { "AWS" => id }
1150
+ else
1151
+ statement["Principal"] << id
1152
+ end
1138
1153
  else
1139
1154
  raise MuError, "Couldn't find a #{grantee["type"]} named #{grantee["identifier"]} when generating IAM policy"
1140
1155
  end
1141
1156
  else
1142
- statement["Principal"] << grantee["identifier"]
1157
+ bucket_prefix = grantee["identifier"].match(/^[^\.]+\.amazonaws\.com$/) ? "Service" : "AWS"
1158
+ if bucket_style
1159
+ statement["Principal"] << { bucket_prefix => grantee["identifier"] }
1160
+ else
1161
+ statement["Principal"] << grantee["identifier"]
1162
+ end
1143
1163
  end
1144
1164
  }
1145
1165
  if policy["grant_to"].size == 1
@@ -1162,9 +1182,11 @@ end
1162
1182
  stream_id = id.sub(/:([^:]+)$/, ":log-stream:*")
1163
1183
  # "arn:aws:logs:us-east-2:accountID:log-group:log_group_name:log-stream:CloudTrail_log_stream_name_prefix*"
1164
1184
  statement["Resource"] << stream_id
1185
+ elsif id.match(/:s3:/)
1186
+ statement["Resource"] << id+"/*"
1165
1187
  end
1166
1188
  else
1167
- raise MuError, "Couldn't find a #{target["entity_type"]} named #{target["identifier"]} when generating IAM policy"
1189
+ raise MuError, "Couldn't find a #{target["type"]} named #{target["identifier"]} when generating IAM policy"
1168
1190
  end
1169
1191
  else
1170
1192
  target["identifier"] += target["path"] if target["path"]
@@ -1180,6 +1202,32 @@ end
1180
1202
  []
1181
1203
  end
1182
1204
 
1205
+ # Update a policy, handling deletion of old versions as needed
1206
+ # @param arn [String]:
1207
+ # @param doc [Hash]:
1208
+ # @param credentials [String]:
1209
+ def self.update_policy(arn, doc, credentials: nil)
1210
+ # XXX this is just blindly replacing identical versions, when it should check
1211
+ # and guard
1212
+ begin
1213
+ MU::Cloud::AWS.iam(credentials: credentials).create_policy_version(
1214
+ policy_arn: arn,
1215
+ set_as_default: true,
1216
+ policy_document: JSON.generate(doc)
1217
+ )
1218
+ rescue Aws::IAM::Errors::LimitExceeded
1219
+ delete_version = MU::Cloud::AWS.iam(credentials: credentials).list_policy_versions(
1220
+ policy_arn: arn,
1221
+ ).versions.last.version_id
1222
+ MU.log "Purging oldest version (#{delete_version}) of IAM policy #{arn}", MU::NOTICE
1223
+ MU::Cloud::AWS.iam(credentials: credentials).delete_policy_version(
1224
+ policy_arn: arn,
1225
+ version_id: delete_version
1226
+ )
1227
+ retry
1228
+ end
1229
+ end
1230
+
1183
1231
  private
1184
1232
 
1185
1233
  # Convert entries from the cloud-neutral @config['policies'] list into
@@ -1261,28 +1309,6 @@ end
1261
1309
  MU::Cloud::AWS::Role.update_policy(arn, doc, credentials: @credentials)
1262
1310
  end
1263
1311
 
1264
- # Update a policy, handling deletion of old versions as needed
1265
- def self.update_policy(arn, doc, credentials: nil)
1266
- # XXX this is just blindly replacing identical versions, when it should check
1267
- # and guard
1268
- begin
1269
- MU::Cloud::AWS.iam(credentials: credentials).create_policy_version(
1270
- policy_arn: arn,
1271
- set_as_default: true,
1272
- policy_document: JSON.generate(doc)
1273
- )
1274
- rescue Aws::IAM::Errors::LimitExceeded => e
1275
- delete_version = MU::Cloud::AWS.iam(credentials: credentials).list_policy_versions(
1276
- policy_arn: arn,
1277
- ).versions.last.version_id
1278
- MU.log "Purging oldest version (#{delete_version}) of IAM policy #{arn}", MU::NOTICE
1279
- MU::Cloud::AWS.iam(credentials: credentials).delete_policy_version(
1280
- policy_arn: arn,
1281
- version_id: delete_version
1282
- )
1283
- retry
1284
- end
1285
- end
1286
1312
 
1287
1313
  end
1288
1314
  end