config.go (8072B)
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 }