environments-list-builder 0.1.8 → 0.1.9

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.
@@ -0,0 +1,309 @@
1
+ require 'thor'
2
+ require 'awesome_print'
3
+ require 'inifile'
4
+
5
+ module Amplify
6
+ module AWS
7
+ LOG_LEVELS = [:trace, :debug, :info, :step, :warn, :error, :fatal, :todo]
8
+
9
+ class CredentialsHash < Hash
10
+ def initialize
11
+ super()
12
+ end
13
+ end
14
+
15
+ class IniFileCredentials < CredentialsHash
16
+ def initialize(inifile)
17
+ super()
18
+ self.[]=(:inifile, inifile)
19
+ end
20
+ def get_options
21
+ {
22
+ :inifile => self.[](:inifile),
23
+ :account => File.basename(self.[](:inifile)),
24
+ }
25
+ end
26
+ end
27
+
28
+ class ProfileCredentials < CredentialsHash
29
+ def initialize(profile)
30
+ super()
31
+ self.[]=(:profile, profile)
32
+ end
33
+ def get_options
34
+ {
35
+ :profile => self.[](:profile),
36
+ :account => self.[](:profile),
37
+ }
38
+ end
39
+ end
40
+
41
+ module MixIns
42
+ module NoCommands
43
+ require 'dldinternet/mixlib/logging'
44
+ include DLDInternet::Mixlib::Logging
45
+
46
+ def validate_options
47
+ @config = @options.dup
48
+ if @config[:log_level]
49
+ log_level = @config[:log_level].to_sym
50
+ raise "Invalid log-level: #{log_level}" unless LOG_LEVELS.include?(log_level)
51
+ @config[:log_level] = log_level
52
+ end
53
+ @config[:log_level] ||= :info
54
+ end
55
+
56
+ def parse_options
57
+ validate_options
58
+
59
+ colormap = {
60
+ :trace => :blue,
61
+ :debug => :cyan,
62
+ :info => :green,
63
+ :step => :green,
64
+ :warn => :yellow,
65
+ :error => :red,
66
+ :fatal => :red,
67
+ :todo => :purple,
68
+ }
69
+ unless options[:color]
70
+ LOG_LEVELS.each do |l,_|
71
+ colormap[l] = :clear
72
+ end
73
+ end
74
+ lcs = ::Logging::ColorScheme.new( 'compiler', :levels => colormap)
75
+ scheme = lcs.scheme
76
+ if options[:color]
77
+ scheme['trace'] = "\e[38;5;33m"
78
+ scheme['fatal'] = "\e[38;5;89m"
79
+ scheme['todo'] = "\e[38;5;55m"
80
+ end
81
+ lcs.scheme scheme
82
+ @config[:log_opts] = lambda{|mlll| {
83
+ :pattern => "%#{mlll}l: %m %g\n",
84
+ :date_pattern => '%Y-%m-%d %H:%M:%S',
85
+ :color_scheme => 'compiler',
86
+ :trace => (@config[:trace].nil? ? false : @config[:trace]),
87
+ # [2014-06-30 Christo] DO NOT do this ... it needs to be a FixNum!!!!
88
+ # If you want to do ::Logging.init first then fine ... go ahead :)
89
+ # :level => @config[:log_level],
90
+ }
91
+ }
92
+ @logger = getLogger(@config)
93
+
94
+ if @options[:inifile]
95
+ load_credentials_inifile(@options[:inifile], 'global')
96
+ elsif @options[:profile]
97
+ unless File.directory?(File.expand_path('~/.aws'))
98
+ msg = 'Cannot load profile. ~/.aws does not exist!?'
99
+ @logger.error msg
100
+ raise msg
101
+ end
102
+ unless File.exists?(File.expand_path('~/.aws/config'))
103
+ msg = 'Cannot load profile. ~/.aws/config does not exist!?'
104
+ @logger.error msg
105
+ raise msg
106
+ end
107
+ unless File.exists?(File.expand_path('~/.aws/credentials'))
108
+ msg = 'Cannot load profile. ~/.aws/credentials does not exist!?'
109
+ @logger.error msg
110
+ raise msg
111
+ end
112
+ @logger.debug "Profile: #{@options[:profile]}"
113
+ load_credentials_profile(@options[:profile], {
114
+ 'output' => 'AWS_DEFAULT_OUTPUT',
115
+ 'region' => 'AWS_DEFAULT_REGION',
116
+ 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
117
+ 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY',
118
+ })
119
+ end
120
+
121
+ if options[:debug]
122
+ @logger.info "Options:\n#{options.ai}"
123
+ end
124
+
125
+ end
126
+
127
+ def expand_options()
128
+ def _expand(opts,k,v,regex,rerun)
129
+ matches = v.match(regex)
130
+ if matches
131
+ var = matches[1]
132
+ if opts[var]
133
+ opts[k]=v.gsub(/\%\(#{var}\)/,opts[var]).gsub(/\%#{var}/,opts[var])
134
+ else
135
+ rerun[var] = 1
136
+ end
137
+ end
138
+ end
139
+
140
+ pending = nil
141
+ rerun = {}
142
+ begin
143
+ pending = rerun
144
+ rerun = {}
145
+ @options.to_hash.each{|k,v|
146
+ if v.to_s.match(/\%/)
147
+ _expand(@options,k,v,%r'[^\\]\%\((\w+)\)', rerun)
148
+ _expand(@options,k,v,%r'[^\\]\%(\w+)', rerun)
149
+ end
150
+ }
151
+ # Should break out the first time that we make no progress!
152
+ end while pending != rerun
153
+ end
154
+
155
+ def load_credentials_profile(profile, map=nil)
156
+ begin
157
+ if @saved_env and @saved_env.size > 0
158
+ @saved_env.each do |k,v|
159
+ ENV[k] = v
160
+ end
161
+ ENV.to_hash.each do |k,v|
162
+ unless @saved_env.has_key?(k)
163
+ ENV.delete(k)
164
+ end
165
+ end
166
+ else
167
+ @saved_env = ENV.to_hash.dup
168
+ end
169
+ ini = load_inifile('~/.aws/config')
170
+ ini['default'].each{ |key,value|
171
+ k = if map[key.to_s]
172
+ map[key.to_s]
173
+ else
174
+ key.to_s
175
+ end
176
+ ENV[k]=value
177
+ }
178
+ ini["profile #{profile}"].each{ |key,value|
179
+ k = if map[key.to_s]
180
+ map[key.to_s]
181
+ else
182
+ key.to_s
183
+ end
184
+ ENV[k]=value
185
+ }
186
+ ini = load_inifile('~/.aws/credentials')
187
+ unless ini.sections.include?(profile)
188
+ logger.error "No credentials found for profile #{profile}"
189
+ exit 11
190
+ end
191
+ ini[profile].each{ |key,value|
192
+ k = if map[key.to_s]
193
+ map[key.to_s]
194
+ else
195
+ key.to_s
196
+ end
197
+ ENV[k]=value
198
+ }
199
+ expand_options()
200
+ rescue ::IniFile::Error => e
201
+ # noop
202
+ rescue SystemExit => e
203
+ raise e
204
+ rescue ::Exception => e
205
+ @logger.error "#{e.class.name} #{e.message}"
206
+ raise e
207
+ end
208
+ end
209
+
210
+ def load_inifile(inifile)
211
+ inifile = File.expand_path(inifile)
212
+ unless File.exist?(inifile)
213
+ raise "#{inifile} not found!"
214
+ end
215
+ begin
216
+ ini = ::IniFile.load(inifile)
217
+ rescue ::Exception => e
218
+ @logger.error "#{e.class.name} #{e.message}"
219
+ raise e
220
+ end
221
+ end
222
+
223
+ def load_credentials_inifile(inifile, section='global', map=nil)
224
+ begin
225
+ ini = load_inifile(inifile)
226
+ ini[section].each{ |key,value|
227
+ #@options[key.to_s]=value
228
+ @logger.debug "#{key} '#{value}'"
229
+ ENV[key.to_s]=value.to_s
230
+ }
231
+ expand_options()
232
+ rescue ::IniFile::Error => e
233
+ # noop
234
+ rescue ::Exception => e
235
+ @logger.error "#{e.class.name} #{e.message}"
236
+ raise e
237
+ end
238
+ end
239
+
240
+ def check_missing_options(method,optionset)
241
+ parse_options
242
+ missing = []
243
+ optionset.each do |req|
244
+ case req.class.name
245
+ when /String|Symbol/
246
+ missing << req unless @options[req]
247
+ when /Array/
248
+ flag = false
249
+ req.each do |o|
250
+ if @options[o]
251
+ flag = true
252
+ break
253
+ end
254
+ end
255
+ missing << req.join('|') unless flag
256
+ else
257
+ logger.fatal "Internal: #{method}: Unsupported missing option type: #{req.class}"
258
+ exit 99
259
+ end
260
+ end
261
+
262
+ if missing.size > 0
263
+ logger.error "#{method}: Missing required options: #{missing.join(', ')}"
264
+ exit 1
265
+ end
266
+ end
267
+
268
+ def print_error(err)
269
+
270
+ logger.error err.to_s
271
+
272
+ end
273
+
274
+ def prepare_accounts
275
+ @accounts = []
276
+ if @options[:iniglob]
277
+ iniglob = File.expand_path(@options[:iniglob])
278
+ Dir.glob( iniglob) {| filename |
279
+ @accounts << IniFileCredentials.new(filename)
280
+ }
281
+ elsif @options[:inifile]
282
+ @accounts << IniFileCredentials.new(@options[:inifile]) unless (@options[:inifile].nil? or @options[:inifile].empty?)
283
+ end
284
+
285
+ if @options[:profile]
286
+ if @options[:profiles]
287
+ @options[:profiles] << @options[:profile]
288
+ else
289
+ @options[:profiles] = [@options[:profile]]
290
+ end
291
+ end
292
+ if @options[:profiles]
293
+ @options[:profiles].each {| profile |
294
+ @accounts << ProfileCredentials.new(profile)
295
+ }
296
+ end
297
+ unless @accounts.size > 0
298
+ parse_options
299
+ logger.fatal 'No options allow for account identification'
300
+ end
301
+ # Make the options mutable
302
+ unless @options.is_a?(Hash) or @options.is_a?(Hashie::Mash)
303
+ @options = Hashie::Mash.new(@options.to_hash)
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,452 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'awesome_print'
5
+ require 'inifile'
6
+ require 'rubygems'
7
+ require 'aws-sdk-core'
8
+ require 'json'
9
+
10
+ # =====================================================================================================================
11
+ # A little include path tom-foolery ...
12
+ path = File.dirname(__FILE__)
13
+ # Borrowing from "whiches" gem ...
14
+ cmd = File.basename(__FILE__, '.rb')
15
+ exes = []
16
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
17
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |pth|
18
+ exts.each { |ext|
19
+ exe = File.join(pth, "#{cmd}#{ext}")
20
+ exes << exe if File.executable? exe
21
+ }
22
+ end
23
+ if exes.size > 0
24
+ path = File.dirname(exes[0])
25
+ end
26
+
27
+ # add_path = File.expand_path(File.join(path, '../../lib'))
28
+ # $:.unshift(add_path)
29
+ # add_path = File.expand_path(File.join(path, 'lib'))
30
+ add_path = path
31
+ $:.unshift(add_path)
32
+
33
+ # =====================================================================================================================
34
+ class UpdateBucketPolicy < Thor
35
+ KNOWN = %w(38.117.159.162/32 70.151.98.131/32 )
36
+ class_option :verbose, :type => :boolean
37
+ class_option :debug, :type => :boolean
38
+ class_option :log_level, :type => :string, :banner => 'Log level ([:trace, :debug, :info, :step, :warn, :error, :fatal, :todo])', :default => :step
39
+ class_option :bucket, :type => :string, :default => 'wgen-sto-artifacts'
40
+ class_option :bucketini, :type => :string
41
+ class_option :bucketprofile,:type => :string
42
+ class_option :basepolicy, :type => :string
43
+ class_option :policy, :type => :string
44
+ class_option :iniglob, :type => :string
45
+ class_option :inifile, :type => :string
46
+ class_option :profiles, :type => :array
47
+ class_option :color, :type => :boolean, :default => false
48
+ class_option :yes, :type => :boolean
49
+ attr_reader :accounts, :environments
50
+ attr_accessor :logger
51
+
52
+ no_commands do
53
+
54
+ require 'mixins/no_commands'
55
+ include Amplify::AWS::MixIns::NoCommands
56
+
57
+ def get_environments
58
+ logger.step 'Get environments ...'
59
+
60
+ @environments = {}
61
+ @nats = {}
62
+ @accounts.each do |acc|
63
+ @options.merge!(acc.get_options())
64
+ parse_options
65
+ get_environments_for_account
66
+ end
67
+ logger.info "Environments:\n"+@environments.ai
68
+ logger.info "NATs:\n"+@nats.ai
69
+
70
+ end
71
+
72
+ def get_environments_for_account
73
+ logger.step "Get environments for #{@options[:account]} ..."
74
+
75
+ config = @options
76
+
77
+ # noinspection RubyArgCount
78
+ cfn = Aws::CloudFormation::Client.new(retry_limit: 10)
79
+
80
+ stacks = []
81
+ resp = cfn.list_stacks()
82
+
83
+ stacks << resp[:stack_summaries]
84
+ while resp[:next_token]
85
+ resp = cfn.list_stacks(next_token: resp[:next_token])
86
+ logger.debug resp.size
87
+ stacks << resp[:stack_summaries]
88
+ end
89
+ stacks.flatten!
90
+ stacks = stacks.select{ |stack| stack[:stack_status].match(%r'^(UPDATE|CREATE).*?_COMPLETE$')}
91
+ logger.debug stacks.ai
92
+
93
+ stacks.each do |stack|
94
+ env = nil
95
+ resp = cfn.describe_stacks(stack_name: stack[:stack_id])
96
+ stck = resp[:stacks].shift
97
+ tags = stck[:tags]
98
+ tags.each do |tag|
99
+ if tag[:key] == 'EnvironmentName'
100
+ env = tag[:value]
101
+ break
102
+ end
103
+ end
104
+ unless env
105
+ env = stack[:stack_name]
106
+ end
107
+ @environments[env] ||= []
108
+ @environments[env] << stack[:stack_name]
109
+
110
+ resources = []
111
+ resp = cfn.describe_stack_resources(stack_name: stack[:stack_id], logical_resource_id: 'NATIPAddress')
112
+ resources << resp[:stack_resources]
113
+ resp = cfn.describe_stack_resources(stack_name: stack[:stack_id], logical_resource_id: 'BastionIPAddress')
114
+ resources << resp[:stack_resources]
115
+ resources.flatten!
116
+ logger.debug resources.ai
117
+
118
+ _nats = resources.map{ |r|
119
+ r.to_h[:physical_resource_id]
120
+ }
121
+
122
+ @nats[env] = @nats[env] ? [ @nats[env], _nats ].flatten : _nats
123
+ end
124
+
125
+ end
126
+
127
+ def get_eips_for_account
128
+ logger.step "Get EIPs for #{@options[:inifile]} ..."
129
+
130
+ # noinspection RubyArgCount
131
+ ec2 = Aws::EC2::Client.new(retry_limit: 10)
132
+
133
+ resp = ec2.describe_addresses()
134
+
135
+ @eips << resp[:addresses].map{ |a| a[:public_ip] }
136
+ @eips.flatten!
137
+ logger.debug @eips.ai
138
+
139
+ end
140
+
141
+ def get_eips
142
+ logger.step 'Get EIPs ...'
143
+
144
+ @eips = []
145
+ @accounts.each do |acc|
146
+ @options.merge!(acc.get_options())
147
+ parse_options
148
+ get_eips_for_account
149
+ end
150
+ @eips.uniq!
151
+ logger.info "EIPs:\n"+@eips.sort_by { |ip| ip.split(%r'[\./]').map{ |octet| octet.to_i} }.ai
152
+
153
+ end
154
+
155
+ def read_bucket_policy
156
+
157
+ parse_bucket_options(__method__, [ :policy, [:bucketini, :bucketprofile], :bucket ])
158
+
159
+ logger.step "Read the current policy for #{@options[:bucket]} ..."
160
+
161
+ # noinspection RubyArgCount
162
+ s3 = Aws::S3::Client.new()
163
+
164
+ resp = s3.get_bucket_policy(bucket: options[:bucket])
165
+ logger.debug resp.size
166
+ @policies = []
167
+ resp.each do |item|
168
+ json = item.policy.read
169
+ @policies << JSON.load(json)
170
+
171
+ logger.debug JSON.pretty_generate(@policies[-1], { indent: "\t", space: ' '})
172
+ end
173
+
174
+ logger.debug @policies.ai
175
+
176
+ json = ''
177
+ @policies.each do |pol|
178
+ json += JSON.pretty_generate(pol, { indent: "\t", space: ' '})
179
+ end
180
+ IO.write("#{options[:policy]}", json)
181
+
182
+ end
183
+
184
+ def inspect_bucket_policy
185
+
186
+ parse_bucket_options(__method__, [ :policy, [:bucketini, :bucketprofile], :bucket ])
187
+
188
+ logger.step "Inspect the policy for #{@options[:bucket]} ..."
189
+
190
+ config = @options.dup
191
+ tempfile =
192
+ @options[:policy] = Tempfile.new('policy').path+'.json'
193
+ read_bucket_policy()
194
+ @options = config
195
+
196
+ get_eips()
197
+
198
+ get_environments()
199
+
200
+ ips = [ @nats.values, @eips ].flatten.map{ |ip| "#{ip}/32"}
201
+ ips = [ ips, KNOWN ].flatten.uniq.select{ |ip| not ip.nil? }
202
+ ips = ips.sort_by { |ip| ip.split(%r'[\./]').map{ |octet| octet.to_i} }.uniq
203
+ logger.info "Valid IPs: \n"+ips.ai
204
+
205
+ json = ''
206
+ @policies.each do |pol|
207
+ unknown = 0
208
+ missing = 0
209
+ unadded = 0
210
+ if pol['Statement']
211
+ pol['Statement'].each do |smt|
212
+ logger.debug smt.ai
213
+ if smt['Condition'] and smt['Condition']['IpAddress'] and smt['Condition']['IpAddress']['aws:SourceIp']
214
+ smt['Condition']['IpAddress']['aws:SourceIp'].sort_by { |ip| ip.split(%r'[\./]').map{ |octet| octet.to_i} }.each do |entry|
215
+ unless ips.include?(entry)
216
+ logger.warn "#{entry} unknown"
217
+ unknown += 1
218
+ end
219
+ end
220
+ ips.each do |entry|
221
+ unless smt['Condition']['IpAddress']['aws:SourceIp'].include?(entry)
222
+ logger.info "#{entry} missing"
223
+ missing += 1
224
+ smt['Condition']['IpAddress']['aws:SourceIp'] << entry
225
+ end
226
+ end
227
+ if missing > 0
228
+ ips.each do |entry|
229
+ unless smt['Condition']['IpAddress']['aws:SourceIp'].include?(entry)
230
+ logger.warn "#{entry} missing"
231
+ unadded += 1
232
+ end
233
+ end
234
+ end
235
+ smt['Condition']['IpAddress']['aws:SourceIp'] = smt['Condition']['IpAddress']['aws:SourceIp'].sort_by { |ip| ip.split(%r'[\./]').map{ |octet| octet.to_i} }
236
+ end
237
+ end
238
+ else
239
+ logger.warn "Policy has no Statement: #{pol.ai}"
240
+ end
241
+ if missing+unknown > 0
242
+ logger.warn "Policy needs to be updated for #{unknown} unknown IPs, #{missing} missing and #{unadded} IPs which failed to add"
243
+ end
244
+ # require 'date_time'
245
+ logger.debug JSON.pretty_generate(pol, { indent: "\t", space: ' '})
246
+ pol['Id'] = "Policy-#{DateTime.now.strftime('%Y%m%dT%H%M%S')}"
247
+ json += JSON.pretty_generate(pol, { indent: "\t", space: ' '})
248
+ end
249
+ IO.write(options[:policy], json)
250
+
251
+ end
252
+
253
+ def update_bucket_policy
254
+
255
+ parse_bucket_options(__method__, [ :policy, [:bucketini, :bucketprofile], :bucket ])
256
+
257
+ logger.step "Update the current policy for #{@options[:bucket]} ..."
258
+
259
+ inspect_bucket_policy
260
+
261
+ write_bucket_policy
262
+
263
+ end
264
+
265
+ def write_bucket_policy
266
+
267
+ parse_bucket_options(__method__, [ :policy, [:bucketini, :bucketprofile], :bucket ])
268
+
269
+ logger.step "Write the new policy for #{@options[:bucket]} ..."
270
+
271
+ @options[:inifile] = @options[:bucketini]
272
+ parse_options
273
+ @logger.info options.ai
274
+
275
+ json = IO.read(options[:policy])
276
+
277
+ # noinspection RubyArgCount
278
+ s3 = Aws::S3::Client.new()
279
+
280
+ resp = s3.put_bucket_policy(
281
+ bucket: options[:bucket],
282
+ policy: json
283
+ )
284
+ logger.debug resp.ai
285
+ if resp.error
286
+ logger.error resp.error
287
+ end
288
+ end
289
+
290
+ def parse_bucket_options(method,optionset)
291
+ check_missing_options(method, optionset)
292
+
293
+ if @options[:bucketini]
294
+ @options[:inifile] = @options[:bucketini]
295
+ else
296
+ @options[:profile] = @options[:bucketprofile]
297
+ end
298
+ parse_options
299
+ @logger.info options.ai
300
+ end
301
+ end
302
+
303
+ def initialize(args = [], local_options = {}, config = {})
304
+ super(args,local_options,config)
305
+ end
306
+
307
+ desc 'read', 'read the policy for BUCKET'
308
+ def read()
309
+ prepare_accounts
310
+
311
+ read_bucket_policy
312
+
313
+ n = 1
314
+ @policies.each do |pol|
315
+ logger.step "#{n+=1}\n"+JSON.pretty_generate(pol, { indent: "\t", space: ' '})
316
+ end
317
+
318
+ 0
319
+ end
320
+
321
+ desc 'inspect', 'inspect the policy for BUCKET'
322
+ def inspect()
323
+ prepare_accounts()
324
+
325
+ inspect_bucket_policy()
326
+
327
+ @policies.each do |pol|
328
+ logger.debug JSON.pretty_generate(pol, { indent: "\t", space: ' '})
329
+ end
330
+ 0
331
+ end
332
+
333
+ desc 'update', 'update the policy for BUCKET'
334
+ def update()
335
+ prepare_accounts()
336
+
337
+ update_bucket_policy()
338
+
339
+ 0
340
+ end
341
+
342
+ desc 'write', 'write the new POLICY to BUCKET'
343
+ def write()
344
+ prepare_accounts
345
+ @options[:inifile] = @options[:bucketini]
346
+ parse_options
347
+ @logger.info options.ai
348
+
349
+ write_bucket_policy
350
+
351
+ 0
352
+ end
353
+
354
+ end
355
+
356
+ # =====================================================================================================================
357
+ # UpdateBucketPolicy.start(ARGV)
358
+
359
+
360
+ __END__
361
+ "aws:SourceIp": [
362
+ "54.84.38.255/32",
363
+ "54.86.79.230/32",
364
+ "54.84.206.23/32",
365
+ "54.172.63.6/32",
366
+ "54.86.33.222/32",
367
+ "38.117.159.162/32",
368
+ "70.151.98.131/32",
369
+ "54.208.252.192/32",
370
+ "54.86.6.21/32",
371
+ "54.86.156.100/32",
372
+ "54.209.155.115/32",
373
+ "107.23.90.79/32",
374
+ "54.172.109.59/32",
375
+ "54.209.93.210/32",
376
+ "54.88.205.140/32",
377
+ "54.209.196.100/32",
378
+ "54.84.6.106/32",
379
+ "54.165.122.109/32",
380
+ "107.21.36.141/32",
381
+ "54.86.150.196/32",
382
+ "54.209.17.121/32",
383
+ "54.84.31.228/32",
384
+ "54.88.2.227/32",
385
+ "54.85.80.166/32",
386
+ "54.86.31.209/32",
387
+ "50.19.114.108/32",
388
+ "54.85.159.92/32",
389
+ "54.85.129.109/32",
390
+ "54.165.86.129/32",
391
+ "54.165.114.103/32",
392
+ "54.172.8.125/32",
393
+ "54.86.144.175/32",
394
+ "107.23.57.237/32",
395
+ "54.165.231.248/32",
396
+ "54.165.228.106/32"
397
+ ]
398
+
399
+ {
400
+ "Version": "2008-10-17",
401
+ "Id": "Policy13947375644752",
402
+ "Statement": [
403
+ {
404
+ "Sid": "Stmt13947375624982",
405
+ "Effect": "Allow",
406
+ "Principal": {
407
+ "AWS": "*"
408
+ },
409
+ "Action": "s3:*",
410
+ "Resource": "arn:aws:s3:::wgen-sto-artifacts/*",
411
+ "Condition": {
412
+ "IpAddress": {
413
+ "aws:SourceIp": [
414
+ "54.86.79.230/32",
415
+ "54.84.206.23/32",
416
+ "54.86.33.222/32",
417
+ "38.117.159.162/32",
418
+ "70.151.98.131/32",
419
+ "54.209.155.115/32",
420
+ "107.23.90.79/32",
421
+ "54.209.93.210/32",
422
+ "54.88.205.140/32",
423
+ "54.84.6.106/32",
424
+ "107.21.36.141/32",
425
+ "54.86.150.196/32",
426
+ "54.209.17.121/32",
427
+ "54.84.31.228/32",
428
+ "54.86.31.209/32",
429
+ "50.19.114.108/32",
430
+ "54.85.129.109/32",
431
+ "54.165.86.129/32",
432
+ "54.165.114.103/32",
433
+ "54.172.8.125/32",
434
+ "54.86.144.175/32",
435
+ "107.23.57.237/32",
436
+ "54.165.231.248/32",
437
+ "54.165.228.106/32"
438
+ ]
439
+ }
440
+ }
441
+ },
442
+ {
443
+ "Sid": "2",
444
+ "Effect": "Allow",
445
+ "Principal": {
446
+ "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EXU2IEU8NKUSP"
447
+ },
448
+ "Action": "s3:GetObject",
449
+ "Resource": "arn:aws:s3:::wgen-sto-artifacts/*"
450
+ }
451
+ ]
452
+ }