config.go raw

   1  package config
   2  
   3  import (
   4  	"context"
   5  	"os"
   6  
   7  	"github.com/aws/aws-sdk-go-v2/aws"
   8  )
   9  
  10  // defaultAWSConfigResolvers are a slice of functions that will resolve external
  11  // configuration values into AWS configuration values.
  12  //
  13  // This will setup the AWS configuration's Region,
  14  var defaultAWSConfigResolvers = []awsConfigResolver{
  15  	// Resolves the default configuration the SDK's aws.Config will be
  16  	// initialized with.
  17  	resolveDefaultAWSConfig,
  18  
  19  	// Sets the logger to be used. Could be user provided logger, and client
  20  	// logging mode.
  21  	resolveLogger,
  22  	resolveClientLogMode,
  23  
  24  	// Sets the HTTP client and configuration to use for making requests using
  25  	// the HTTP transport.
  26  	resolveHTTPClient,
  27  	resolveCustomCABundle,
  28  
  29  	// Sets the endpoint resolving behavior the API Clients will use for making
  30  	// requests to. Clients default to their own clients this allows overrides
  31  	// to be specified. The resolveEndpointResolver option is deprecated, but
  32  	// we still need to set it for backwards compatibility on config
  33  	// construction.
  34  	resolveEndpointResolver,
  35  	resolveEndpointResolverWithOptions,
  36  
  37  	// Sets the retry behavior API clients will use within their retry attempt
  38  	// middleware. Defaults to unset, allowing API clients to define their own
  39  	// retry behavior.
  40  	resolveRetryer,
  41  
  42  	// Sets the region the API Clients should use for making requests to.
  43  	resolveRegion,
  44  	resolveEC2IMDSRegion,
  45  	resolveDefaultRegion,
  46  
  47  	// Sets the additional set of middleware stack mutators that will custom
  48  	// API client request pipeline middleware.
  49  	resolveAPIOptions,
  50  
  51  	// Resolves the DefaultsMode that should be used by SDK clients. If this
  52  	// mode is set to DefaultsModeAuto.
  53  	//
  54  	// Comes after HTTPClient and CustomCABundle to ensure the HTTP client is
  55  	// configured if provided before invoking IMDS if mode is auto. Comes
  56  	// before resolving credentials so that those subsequent clients use the
  57  	// configured auto mode.
  58  	resolveDefaultsModeOptions,
  59  
  60  	// Sets the resolved credentials the API clients will use for
  61  	// authentication. Provides the SDK's default credential chain.
  62  	//
  63  	// Should probably be the last step in the resolve chain to ensure that all
  64  	// other configurations are resolved first in case downstream credentials
  65  	// implementations depend on or can be configured with earlier resolved
  66  	// configuration options.
  67  	resolveCredentials,
  68  
  69  	// Sets the resolved bearer authentication token API clients will use for
  70  	// httpBearerAuth authentication scheme.
  71  	resolveBearerAuthToken,
  72  
  73  	// Sets the sdk app ID if present in env var or shared config profile
  74  	resolveAppID,
  75  
  76  	resolveBaseEndpoint,
  77  
  78  	// Sets the DisableRequestCompression if present in env var or shared config profile
  79  	resolveDisableRequestCompression,
  80  
  81  	// Sets the RequestMinCompressSizeBytes if present in env var or shared config profile
  82  	resolveRequestMinCompressSizeBytes,
  83  
  84  	// Sets the AccountIDEndpointMode if present in env var or shared config profile
  85  	resolveAccountIDEndpointMode,
  86  
  87  	// Sets the RequestChecksumCalculation if present in env var or shared config profile
  88  	resolveRequestChecksumCalculation,
  89  
  90  	// Sets the ResponseChecksumValidation if present in env var or shared config profile
  91  	resolveResponseChecksumValidation,
  92  
  93  	resolveInterceptors,
  94  
  95  	resolveAuthSchemePreference,
  96  
  97  	// Sets the ServiceOptions if present in LoadOptions
  98  	resolveServiceOptions,
  99  }
 100  
 101  // A Config represents a generic configuration value or set of values. This type
 102  // will be used by the AWSConfigResolvers to extract
 103  //
 104  // General the Config type will use type assertion against the Provider interfaces
 105  // to extract specific data from the Config.
 106  type Config interface{}
 107  
 108  // A loader is used to load external configuration data and returns it as
 109  // a generic Config type.
 110  //
 111  // The loader should return an error if it fails to load the external configuration
 112  // or the configuration data is malformed, or required components missing.
 113  type loader func(context.Context, configs) (Config, error)
 114  
 115  // An awsConfigResolver will extract configuration data from the configs slice
 116  // using the provider interfaces to extract specific functionality. The extracted
 117  // configuration values will be written to the AWS Config value.
 118  //
 119  // The resolver should return an error if it it fails to extract the data, the
 120  // data is malformed, or incomplete.
 121  type awsConfigResolver func(ctx context.Context, cfg *aws.Config, configs configs) error
 122  
 123  // configs is a slice of Config values. These values will be used by the
 124  // AWSConfigResolvers to extract external configuration values to populate the
 125  // AWS Config type.
 126  //
 127  // Use AppendFromLoaders to add additional external Config values that are
 128  // loaded from external sources.
 129  //
 130  // Use ResolveAWSConfig after external Config values have been added or loaded
 131  // to extract the loaded configuration values into the AWS Config.
 132  type configs []Config
 133  
 134  // AppendFromLoaders iterates over the slice of loaders passed in calling each
 135  // loader function in order. The external config value returned by the loader
 136  // will be added to the returned configs slice.
 137  //
 138  // If a loader returns an error this method will stop iterating and return
 139  // that error.
 140  func (cs configs) AppendFromLoaders(ctx context.Context, loaders []loader) (configs, error) {
 141  	for _, fn := range loaders {
 142  		cfg, err := fn(ctx, cs)
 143  		if err != nil {
 144  			return nil, err
 145  		}
 146  
 147  		cs = append(cs, cfg)
 148  	}
 149  
 150  	return cs, nil
 151  }
 152  
 153  // ResolveAWSConfig returns a AWS configuration populated with values by calling
 154  // the resolvers slice passed in. Each resolver is called in order. Any resolver
 155  // may overwrite the AWS Configuration value of a previous resolver.
 156  //
 157  // If an resolver returns an error this method will return that error, and stop
 158  // iterating over the resolvers.
 159  func (cs configs) ResolveAWSConfig(ctx context.Context, resolvers []awsConfigResolver) (aws.Config, error) {
 160  	var cfg aws.Config
 161  
 162  	for _, fn := range resolvers {
 163  		if err := fn(ctx, &cfg, cs); err != nil {
 164  			return aws.Config{}, err
 165  		}
 166  	}
 167  
 168  	return cfg, nil
 169  }
 170  
 171  // ResolveConfig calls the provide function passing slice of configuration sources.
 172  // This implements the aws.ConfigResolver interface.
 173  func (cs configs) ResolveConfig(f func(configs []interface{}) error) error {
 174  	var cfgs []interface{}
 175  	for i := range cs {
 176  		cfgs = append(cfgs, cs[i])
 177  	}
 178  	return f(cfgs)
 179  }
 180  
 181  // LoadDefaultConfig reads the SDK's default external configurations, and
 182  // populates an AWS Config with the values from the external configurations.
 183  //
 184  // An optional variadic set of additional Config values can be provided as input
 185  // that will be prepended to the configs slice. Use this to add custom configuration.
 186  // The custom configurations must satisfy the respective providers for their data
 187  // or the custom data will be ignored by the resolvers and config loaders.
 188  //
 189  //	cfg, err := config.LoadDefaultConfig( context.TODO(),
 190  //	   config.WithSharedConfigProfile("test-profile"),
 191  //	)
 192  //	if err != nil {
 193  //	   panic(fmt.Sprintf("failed loading config, %v", err))
 194  //	}
 195  //
 196  // The default configuration sources are:
 197  // * Environment Variables
 198  // * Shared Configuration and Shared Credentials files.
 199  func LoadDefaultConfig(ctx context.Context, optFns ...func(*LoadOptions) error) (cfg aws.Config, err error) {
 200  	var options LoadOptions
 201  	for _, optFn := range optFns {
 202  		if err := optFn(&options); err != nil {
 203  			return aws.Config{}, err
 204  		}
 205  	}
 206  
 207  	// assign Load Options to configs
 208  	var cfgCpy = configs{options}
 209  
 210  	cfgCpy, err = cfgCpy.AppendFromLoaders(ctx, resolveConfigLoaders(&options))
 211  	if err != nil {
 212  		return aws.Config{}, err
 213  	}
 214  
 215  	cfg, err = cfgCpy.ResolveAWSConfig(ctx, defaultAWSConfigResolvers)
 216  	if err != nil {
 217  		return aws.Config{}, err
 218  	}
 219  
 220  	return cfg, nil
 221  }
 222  
 223  func resolveConfigLoaders(options *LoadOptions) []loader {
 224  	loaders := make([]loader, 2)
 225  	loaders[0] = loadEnvConfig
 226  
 227  	// specification of a profile should cause a load failure if it doesn't exist
 228  	if os.Getenv(awsProfileEnv) != "" || options.SharedConfigProfile != "" {
 229  		loaders[1] = loadSharedConfig
 230  	} else {
 231  		loaders[1] = loadSharedConfigIgnoreNotExist
 232  	}
 233  
 234  	return loaders
 235  }
 236