resolve.go

  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}