]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | // Package defaults is a collection of helpers to retrieve the SDK's default |
2 | // configuration and handlers. | |
3 | // | |
4 | // Generally this package shouldn't be used directly, but session.Session | |
5 | // instead. This package is useful when you need to reset the defaults | |
6 | // of a session or service client to the SDK defaults before setting | |
7 | // additional parameters. | |
8 | package defaults | |
9 | ||
10 | import ( | |
11 | "fmt" | |
15c0b25d | 12 | "net" |
bae9f6d2 JC |
13 | "net/http" |
14 | "net/url" | |
15 | "os" | |
16 | "time" | |
17 | ||
18 | "github.com/aws/aws-sdk-go/aws" | |
19 | "github.com/aws/aws-sdk-go/aws/awserr" | |
20 | "github.com/aws/aws-sdk-go/aws/corehandlers" | |
21 | "github.com/aws/aws-sdk-go/aws/credentials" | |
22 | "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" | |
23 | "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" | |
24 | "github.com/aws/aws-sdk-go/aws/ec2metadata" | |
25 | "github.com/aws/aws-sdk-go/aws/endpoints" | |
26 | "github.com/aws/aws-sdk-go/aws/request" | |
107c1cdb | 27 | "github.com/aws/aws-sdk-go/internal/shareddefaults" |
bae9f6d2 JC |
28 | ) |
29 | ||
30 | // A Defaults provides a collection of default values for SDK clients. | |
31 | type Defaults struct { | |
32 | Config *aws.Config | |
33 | Handlers request.Handlers | |
34 | } | |
35 | ||
36 | // Get returns the SDK's default values with Config and handlers pre-configured. | |
37 | func Get() Defaults { | |
38 | cfg := Config() | |
39 | handlers := Handlers() | |
40 | cfg.Credentials = CredChain(cfg, handlers) | |
41 | ||
42 | return Defaults{ | |
43 | Config: cfg, | |
44 | Handlers: handlers, | |
45 | } | |
46 | } | |
47 | ||
48 | // Config returns the default configuration without credentials. | |
49 | // To retrieve a config with credentials also included use | |
50 | // `defaults.Get().Config` instead. | |
51 | // | |
52 | // Generally you shouldn't need to use this method directly, but | |
53 | // is available if you need to reset the configuration of an | |
54 | // existing service client or session. | |
55 | func Config() *aws.Config { | |
56 | return aws.NewConfig(). | |
57 | WithCredentials(credentials.AnonymousCredentials). | |
58 | WithRegion(os.Getenv("AWS_REGION")). | |
59 | WithHTTPClient(http.DefaultClient). | |
60 | WithMaxRetries(aws.UseServiceDefaultRetries). | |
61 | WithLogger(aws.NewDefaultLogger()). | |
62 | WithLogLevel(aws.LogOff). | |
63 | WithEndpointResolver(endpoints.DefaultResolver()) | |
64 | } | |
65 | ||
66 | // Handlers returns the default request handlers. | |
67 | // | |
68 | // Generally you shouldn't need to use this method directly, but | |
69 | // is available if you need to reset the request handlers of an | |
70 | // existing service client or session. | |
71 | func Handlers() request.Handlers { | |
72 | var handlers request.Handlers | |
73 | ||
74 | handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) | |
75 | handlers.Validate.AfterEachFn = request.HandlerListStopOnError | |
76 | handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) | |
15c0b25d | 77 | handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHander) |
bae9f6d2 JC |
78 | handlers.Build.AfterEachFn = request.HandlerListStopOnError |
79 | handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) | |
80 | handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler) | |
81 | handlers.Send.PushBackNamed(corehandlers.SendHandler) | |
82 | handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) | |
83 | handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler) | |
84 | ||
85 | return handlers | |
86 | } | |
87 | ||
88 | // CredChain returns the default credential chain. | |
89 | // | |
90 | // Generally you shouldn't need to use this method directly, but | |
91 | // is available if you need to reset the credentials of an | |
92 | // existing service client or session's Config. | |
93 | func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials { | |
94 | return credentials.NewCredentials(&credentials.ChainProvider{ | |
95 | VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), | |
15c0b25d | 96 | Providers: CredProviders(cfg, handlers), |
bae9f6d2 JC |
97 | }) |
98 | } | |
99 | ||
15c0b25d AP |
100 | // CredProviders returns the slice of providers used in |
101 | // the default credential chain. | |
102 | // | |
103 | // For applications that need to use some other provider (for example use | |
104 | // different environment variables for legacy reasons) but still fall back | |
105 | // on the default chain of providers. This allows that default chaint to be | |
106 | // automatically updated | |
107 | func CredProviders(cfg *aws.Config, handlers request.Handlers) []credentials.Provider { | |
108 | return []credentials.Provider{ | |
109 | &credentials.EnvProvider{}, | |
110 | &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, | |
111 | RemoteCredProvider(*cfg, handlers), | |
112 | } | |
113 | } | |
114 | ||
bae9f6d2 | 115 | const ( |
107c1cdb ND |
116 | httpProviderAuthorizationEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN" |
117 | httpProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI" | |
bae9f6d2 JC |
118 | ) |
119 | ||
120 | // RemoteCredProvider returns a credentials provider for the default remote | |
121 | // endpoints such as EC2 or ECS Roles. | |
122 | func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { | |
123 | if u := os.Getenv(httpProviderEnvVar); len(u) > 0 { | |
124 | return localHTTPCredProvider(cfg, handlers, u) | |
125 | } | |
126 | ||
107c1cdb ND |
127 | if uri := os.Getenv(shareddefaults.ECSCredsProviderEnvVar); len(uri) > 0 { |
128 | u := fmt.Sprintf("%s%s", shareddefaults.ECSContainerCredentialsURI, uri) | |
bae9f6d2 JC |
129 | return httpCredProvider(cfg, handlers, u) |
130 | } | |
131 | ||
132 | return ec2RoleProvider(cfg, handlers) | |
133 | } | |
134 | ||
15c0b25d AP |
135 | var lookupHostFn = net.LookupHost |
136 | ||
137 | func isLoopbackHost(host string) (bool, error) { | |
138 | ip := net.ParseIP(host) | |
139 | if ip != nil { | |
140 | return ip.IsLoopback(), nil | |
141 | } | |
142 | ||
143 | // Host is not an ip, perform lookup | |
144 | addrs, err := lookupHostFn(host) | |
145 | if err != nil { | |
146 | return false, err | |
147 | } | |
148 | for _, addr := range addrs { | |
149 | if !net.ParseIP(addr).IsLoopback() { | |
150 | return false, nil | |
151 | } | |
152 | } | |
153 | ||
154 | return true, nil | |
155 | } | |
156 | ||
bae9f6d2 JC |
157 | func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { |
158 | var errMsg string | |
159 | ||
160 | parsed, err := url.Parse(u) | |
161 | if err != nil { | |
162 | errMsg = fmt.Sprintf("invalid URL, %v", err) | |
15c0b25d AP |
163 | } else { |
164 | host := aws.URLHostname(parsed) | |
165 | if len(host) == 0 { | |
166 | errMsg = "unable to parse host from local HTTP cred provider URL" | |
167 | } else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil { | |
168 | errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr) | |
169 | } else if !isLoopback { | |
170 | errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host) | |
171 | } | |
bae9f6d2 JC |
172 | } |
173 | ||
174 | if len(errMsg) > 0 { | |
175 | if cfg.Logger != nil { | |
176 | cfg.Logger.Log("Ignoring, HTTP credential provider", errMsg, err) | |
177 | } | |
178 | return credentials.ErrorProvider{ | |
179 | Err: awserr.New("CredentialsEndpointError", errMsg, err), | |
180 | ProviderName: endpointcreds.ProviderName, | |
181 | } | |
182 | } | |
183 | ||
184 | return httpCredProvider(cfg, handlers, u) | |
185 | } | |
186 | ||
187 | func httpCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { | |
188 | return endpointcreds.NewProviderClient(cfg, handlers, u, | |
189 | func(p *endpointcreds.Provider) { | |
190 | p.ExpiryWindow = 5 * time.Minute | |
107c1cdb | 191 | p.AuthorizationToken = os.Getenv(httpProviderAuthorizationEnvVar) |
bae9f6d2 JC |
192 | }, |
193 | ) | |
194 | } | |
195 | ||
196 | func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { | |
197 | resolver := cfg.EndpointResolver | |
198 | if resolver == nil { | |
199 | resolver = endpoints.DefaultResolver() | |
200 | } | |
201 | ||
202 | e, _ := resolver.EndpointFor(endpoints.Ec2metadataServiceID, "") | |
203 | return &ec2rolecreds.EC2RoleProvider{ | |
204 | Client: ec2metadata.NewClient(cfg, handlers, e.URL, e.SigningRegion), | |
205 | ExpiryWindow: 5 * time.Minute, | |
206 | } | |
207 | } |