environments-list-builder 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }