1package config
2
3import (
4 "context"
5 "crypto/tls"
6 "crypto/x509"
7 "fmt"
8 "io/ioutil"
9 "net/http"
10 "os"
11
12 "github.com/aws/aws-sdk-go-v2/aws"
13 awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
14 "github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
15 "github.com/aws/smithy-go/logging"
16)
17
18// resolveDefaultAWSConfig will write default configuration values into the cfg
19// value. It will write the default values, overwriting any previous value.
20//
21// This should be used as the first resolver in the slice of resolvers when
22// resolving external configuration.
23func resolveDefaultAWSConfig(ctx context.Context, cfg *aws.Config, cfgs configs) error {
24 var sources []interface{}
25 for _, s := range cfgs {
26 sources = append(sources, s)
27 }
28
29 *cfg = aws.Config{
30 Logger: logging.NewStandardLogger(os.Stderr),
31 ConfigSources: sources,
32 }
33 return nil
34}
35
36// resolveCustomCABundle extracts the first instance of a custom CA bundle filename
37// from the external configurations. It will update the HTTP Client's builder
38// to be configured with the custom CA bundle.
39//
40// Config provider used:
41// * customCABundleProvider
42func resolveCustomCABundle(ctx context.Context, cfg *aws.Config, cfgs configs) error {
43 pemCerts, found, err := getCustomCABundle(ctx, cfgs)
44 if err != nil {
45 // TODO error handling, What is the best way to handle this?
46 // capture previous errors continue. error out if all errors
47 return err
48 }
49 if !found {
50 return nil
51 }
52
53 if cfg.HTTPClient == nil {
54 cfg.HTTPClient = awshttp.NewBuildableClient()
55 }
56
57 trOpts, ok := cfg.HTTPClient.(*awshttp.BuildableClient)
58 if !ok {
59 return fmt.Errorf("unable to add custom RootCAs HTTPClient, "+
60 "has no WithTransportOptions, %T", cfg.HTTPClient)
61 }
62
63 var appendErr error
64 client := trOpts.WithTransportOptions(func(tr *http.Transport) {
65 if tr.TLSClientConfig == nil {
66 tr.TLSClientConfig = &tls.Config{}
67 }
68 if tr.TLSClientConfig.RootCAs == nil {
69 tr.TLSClientConfig.RootCAs = x509.NewCertPool()
70 }
71
72 b, err := ioutil.ReadAll(pemCerts)
73 if err != nil {
74 appendErr = fmt.Errorf("failed to read custom CA bundle PEM file")
75 }
76
77 if !tr.TLSClientConfig.RootCAs.AppendCertsFromPEM(b) {
78 appendErr = fmt.Errorf("failed to load custom CA bundle PEM file")
79 }
80 })
81 if appendErr != nil {
82 return appendErr
83 }
84
85 cfg.HTTPClient = client
86 return err
87}
88
89// resolveRegion extracts the first instance of a Region from the configs slice.
90//
91// Config providers used:
92// * regionProvider
93func resolveRegion(ctx context.Context, cfg *aws.Config, configs configs) error {
94 v, found, err := getRegion(ctx, configs)
95 if err != nil {
96 // TODO error handling, What is the best way to handle this?
97 // capture previous errors continue. error out if all errors
98 return err
99 }
100 if !found {
101 return nil
102 }
103
104 cfg.Region = v
105 return nil
106}
107
108func resolveBaseEndpoint(ctx context.Context, cfg *aws.Config, configs configs) error {
109 var downcastCfgSources []interface{}
110 for _, cs := range configs {
111 downcastCfgSources = append(downcastCfgSources, interface{}(cs))
112 }
113
114 if val, found, err := GetIgnoreConfiguredEndpoints(ctx, downcastCfgSources); found && val && err == nil {
115 cfg.BaseEndpoint = nil
116 return nil
117 }
118
119 v, found, err := getBaseEndpoint(ctx, configs)
120 if err != nil {
121 return err
122 }
123
124 if !found {
125 return nil
126 }
127 cfg.BaseEndpoint = aws.String(v)
128 return nil
129}
130
131// resolveAppID extracts the sdk app ID from the configs slice's SharedConfig or env var
132func resolveAppID(ctx context.Context, cfg *aws.Config, configs configs) error {
133 ID, _, err := getAppID(ctx, configs)
134 if err != nil {
135 return err
136 }
137
138 cfg.AppID = ID
139 return nil
140}
141
142// resolveDisableRequestCompression extracts the DisableRequestCompression from the configs slice's
143// SharedConfig or EnvConfig
144func resolveDisableRequestCompression(ctx context.Context, cfg *aws.Config, configs configs) error {
145 disable, _, err := getDisableRequestCompression(ctx, configs)
146 if err != nil {
147 return err
148 }
149
150 cfg.DisableRequestCompression = disable
151 return nil
152}
153
154// resolveRequestMinCompressSizeBytes extracts the RequestMinCompressSizeBytes from the configs slice's
155// SharedConfig or EnvConfig
156func resolveRequestMinCompressSizeBytes(ctx context.Context, cfg *aws.Config, configs configs) error {
157 minBytes, found, err := getRequestMinCompressSizeBytes(ctx, configs)
158 if err != nil {
159 return err
160 }
161 // must set a default min size 10240 if not configured
162 if !found {
163 minBytes = 10240
164 }
165 cfg.RequestMinCompressSizeBytes = minBytes
166 return nil
167}
168
169// resolveAccountIDEndpointMode extracts the AccountIDEndpointMode from the configs slice's
170// SharedConfig or EnvConfig
171func resolveAccountIDEndpointMode(ctx context.Context, cfg *aws.Config, configs configs) error {
172 m, found, err := getAccountIDEndpointMode(ctx, configs)
173 if err != nil {
174 return err
175 }
176
177 if !found {
178 m = aws.AccountIDEndpointModePreferred
179 }
180
181 cfg.AccountIDEndpointMode = m
182 return nil
183}
184
185// resolveDefaultRegion extracts the first instance of a default region and sets `aws.Config.Region` to the default
186// region if region had not been resolved from other sources.
187func resolveDefaultRegion(ctx context.Context, cfg *aws.Config, configs configs) error {
188 if len(cfg.Region) > 0 {
189 return nil
190 }
191
192 v, found, err := getDefaultRegion(ctx, configs)
193 if err != nil {
194 return err
195 }
196 if !found {
197 return nil
198 }
199
200 cfg.Region = v
201
202 return nil
203}
204
205// resolveHTTPClient extracts the first instance of a HTTPClient and sets `aws.Config.HTTPClient` to the HTTPClient instance
206// if one has not been resolved from other sources.
207func resolveHTTPClient(ctx context.Context, cfg *aws.Config, configs configs) error {
208 c, found, err := getHTTPClient(ctx, configs)
209 if err != nil {
210 return err
211 }
212 if !found {
213 return nil
214 }
215
216 cfg.HTTPClient = c
217 return nil
218}
219
220// resolveAPIOptions extracts the first instance of APIOptions and sets `aws.Config.APIOptions` to the resolved API options
221// if one has not been resolved from other sources.
222func resolveAPIOptions(ctx context.Context, cfg *aws.Config, configs configs) error {
223 o, found, err := getAPIOptions(ctx, configs)
224 if err != nil {
225 return err
226 }
227 if !found {
228 return nil
229 }
230
231 cfg.APIOptions = o
232
233 return nil
234}
235
236// resolveEndpointResolver extracts the first instance of a EndpointResolverFunc from the config slice
237// and sets the functions result on the aws.Config.EndpointResolver
238func resolveEndpointResolver(ctx context.Context, cfg *aws.Config, configs configs) error {
239 endpointResolver, found, err := getEndpointResolver(ctx, configs)
240 if err != nil {
241 return err
242 }
243 if !found {
244 return nil
245 }
246
247 cfg.EndpointResolver = endpointResolver
248
249 return nil
250}
251
252// resolveEndpointResolver extracts the first instance of a EndpointResolverFunc from the config slice
253// and sets the functions result on the aws.Config.EndpointResolver
254func resolveEndpointResolverWithOptions(ctx context.Context, cfg *aws.Config, configs configs) error {
255 endpointResolver, found, err := getEndpointResolverWithOptions(ctx, configs)
256 if err != nil {
257 return err
258 }
259 if !found {
260 return nil
261 }
262
263 cfg.EndpointResolverWithOptions = endpointResolver
264
265 return nil
266}
267
268func resolveLogger(ctx context.Context, cfg *aws.Config, configs configs) error {
269 logger, found, err := getLogger(ctx, configs)
270 if err != nil {
271 return err
272 }
273 if !found {
274 return nil
275 }
276
277 cfg.Logger = logger
278
279 return nil
280}
281
282func resolveClientLogMode(ctx context.Context, cfg *aws.Config, configs configs) error {
283 mode, found, err := getClientLogMode(ctx, configs)
284 if err != nil {
285 return err
286 }
287 if !found {
288 return nil
289 }
290
291 cfg.ClientLogMode = mode
292
293 return nil
294}
295
296func resolveRetryer(ctx context.Context, cfg *aws.Config, configs configs) error {
297 retryer, found, err := getRetryer(ctx, configs)
298 if err != nil {
299 return err
300 }
301
302 if found {
303 cfg.Retryer = retryer
304 return nil
305 }
306
307 // Only load the retry options if a custom retryer has not be specified.
308 if err = resolveRetryMaxAttempts(ctx, cfg, configs); err != nil {
309 return err
310 }
311 return resolveRetryMode(ctx, cfg, configs)
312}
313
314func resolveEC2IMDSRegion(ctx context.Context, cfg *aws.Config, configs configs) error {
315 if len(cfg.Region) > 0 {
316 return nil
317 }
318
319 region, found, err := getEC2IMDSRegion(ctx, configs)
320 if err != nil {
321 return err
322 }
323 if !found {
324 return nil
325 }
326
327 cfg.Region = region
328
329 return nil
330}
331
332func resolveDefaultsModeOptions(ctx context.Context, cfg *aws.Config, configs configs) error {
333 defaultsMode, found, err := getDefaultsMode(ctx, configs)
334 if err != nil {
335 return err
336 }
337 if !found {
338 defaultsMode = aws.DefaultsModeLegacy
339 }
340
341 var environment aws.RuntimeEnvironment
342 if defaultsMode == aws.DefaultsModeAuto {
343 envConfig, _, _ := getAWSConfigSources(configs)
344
345 client, found, err := getDefaultsModeIMDSClient(ctx, configs)
346 if err != nil {
347 return err
348 }
349 if !found {
350 client = imds.NewFromConfig(*cfg)
351 }
352
353 environment, err = resolveDefaultsModeRuntimeEnvironment(ctx, envConfig, client)
354 if err != nil {
355 return err
356 }
357 }
358
359 cfg.DefaultsMode = defaultsMode
360 cfg.RuntimeEnvironment = environment
361
362 return nil
363}
364
365func resolveRetryMaxAttempts(ctx context.Context, cfg *aws.Config, configs configs) error {
366 maxAttempts, found, err := getRetryMaxAttempts(ctx, configs)
367 if err != nil || !found {
368 return err
369 }
370 cfg.RetryMaxAttempts = maxAttempts
371
372 return nil
373}
374
375func resolveRetryMode(ctx context.Context, cfg *aws.Config, configs configs) error {
376 retryMode, found, err := getRetryMode(ctx, configs)
377 if err != nil || !found {
378 return err
379 }
380 cfg.RetryMode = retryMode
381
382 return nil
383}