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