config.go 7.9 KB

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