]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / session / shared_config.go
1 package session
2
3 import (
4 "fmt"
5
6 "github.com/aws/aws-sdk-go/aws/awserr"
7 "github.com/aws/aws-sdk-go/aws/credentials"
8 "github.com/aws/aws-sdk-go/internal/ini"
9 )
10
11 const (
12 // Static Credentials group
13 accessKeyIDKey = `aws_access_key_id` // group required
14 secretAccessKey = `aws_secret_access_key` // group required
15 sessionTokenKey = `aws_session_token` // optional
16
17 // Assume Role Credentials group
18 roleArnKey = `role_arn` // group required
19 sourceProfileKey = `source_profile` // group required (or credential_source)
20 credentialSourceKey = `credential_source` // group required (or source_profile)
21 externalIDKey = `external_id` // optional
22 mfaSerialKey = `mfa_serial` // optional
23 roleSessionNameKey = `role_session_name` // optional
24
25 // Additional Config fields
26 regionKey = `region`
27
28 // endpoint discovery group
29 enableEndpointDiscoveryKey = `endpoint_discovery_enabled` // optional
30
31 // External Credential Process
32 credentialProcessKey = `credential_process` // optional
33
34 // Web Identity Token File
35 webIdentityTokenFileKey = `web_identity_token_file` // optional
36
37 // DefaultSharedConfigProfile is the default profile to be used when
38 // loading configuration from the config files if another profile name
39 // is not provided.
40 DefaultSharedConfigProfile = `default`
41 )
42
43 // sharedConfig represents the configuration fields of the SDK config files.
44 type sharedConfig struct {
45 // Credentials values from the config file. Both aws_access_key_id and
46 // aws_secret_access_key must be provided together in the same file to be
47 // considered valid. The values will be ignored if not a complete group.
48 // aws_session_token is an optional field that can be provided if both of
49 // the other two fields are also provided.
50 //
51 // aws_access_key_id
52 // aws_secret_access_key
53 // aws_session_token
54 Creds credentials.Value
55
56 CredentialSource string
57 CredentialProcess string
58 WebIdentityTokenFile string
59
60 RoleARN string
61 RoleSessionName string
62 ExternalID string
63 MFASerial string
64
65 SourceProfileName string
66 SourceProfile *sharedConfig
67
68 // Region is the region the SDK should use for looking up AWS service
69 // endpoints and signing requests.
70 //
71 // region
72 Region string
73
74 // EnableEndpointDiscovery can be enabled in the shared config by setting
75 // endpoint_discovery_enabled to true
76 //
77 // endpoint_discovery_enabled = true
78 EnableEndpointDiscovery *bool
79 }
80
81 type sharedConfigFile struct {
82 Filename string
83 IniData ini.Sections
84 }
85
86 // loadSharedConfig retrieves the configuration from the list of files using
87 // the profile provided. The order the files are listed will determine
88 // precedence. Values in subsequent files will overwrite values defined in
89 // earlier files.
90 //
91 // For example, given two files A and B. Both define credentials. If the order
92 // of the files are A then B, B's credential values will be used instead of
93 // A's.
94 //
95 // See sharedConfig.setFromFile for information how the config files
96 // will be loaded.
97 func loadSharedConfig(profile string, filenames []string, exOpts bool) (sharedConfig, error) {
98 if len(profile) == 0 {
99 profile = DefaultSharedConfigProfile
100 }
101
102 files, err := loadSharedConfigIniFiles(filenames)
103 if err != nil {
104 return sharedConfig{}, err
105 }
106
107 cfg := sharedConfig{}
108 profiles := map[string]struct{}{}
109 if err = cfg.setFromIniFiles(profiles, profile, files, exOpts); err != nil {
110 return sharedConfig{}, err
111 }
112
113 return cfg, nil
114 }
115
116 func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
117 files := make([]sharedConfigFile, 0, len(filenames))
118
119 for _, filename := range filenames {
120 sections, err := ini.OpenFile(filename)
121 if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ini.ErrCodeUnableToReadFile {
122 // Skip files which can't be opened and read for whatever reason
123 continue
124 } else if err != nil {
125 return nil, SharedConfigLoadError{Filename: filename, Err: err}
126 }
127
128 files = append(files, sharedConfigFile{
129 Filename: filename, IniData: sections,
130 })
131 }
132
133 return files, nil
134 }
135
136 func (cfg *sharedConfig) setFromIniFiles(profiles map[string]struct{}, profile string, files []sharedConfigFile, exOpts bool) error {
137 // Trim files from the list that don't exist.
138 var skippedFiles int
139 var profileNotFoundErr error
140 for _, f := range files {
141 if err := cfg.setFromIniFile(profile, f, exOpts); err != nil {
142 if _, ok := err.(SharedConfigProfileNotExistsError); ok {
143 // Ignore profiles not defined in individual files.
144 profileNotFoundErr = err
145 skippedFiles++
146 continue
147 }
148 return err
149 }
150 }
151 if skippedFiles == len(files) {
152 // If all files were skipped because the profile is not found, return
153 // the original profile not found error.
154 return profileNotFoundErr
155 }
156
157 if _, ok := profiles[profile]; ok {
158 // if this is the second instance of the profile the Assume Role
159 // options must be cleared because they are only valid for the
160 // first reference of a profile. The self linked instance of the
161 // profile only have credential provider options.
162 cfg.clearAssumeRoleOptions()
163 } else {
164 // First time a profile has been seen, It must either be a assume role
165 // or credentials. Assert if the credential type requires a role ARN,
166 // the ARN is also set.
167 if err := cfg.validateCredentialsRequireARN(profile); err != nil {
168 return err
169 }
170 }
171 profiles[profile] = struct{}{}
172
173 if err := cfg.validateCredentialType(); err != nil {
174 return err
175 }
176
177 // Link source profiles for assume roles
178 if len(cfg.SourceProfileName) != 0 {
179 // Linked profile via source_profile ignore credential provider
180 // options, the source profile must provide the credentials.
181 cfg.clearCredentialOptions()
182
183 srcCfg := &sharedConfig{}
184 err := srcCfg.setFromIniFiles(profiles, cfg.SourceProfileName, files, exOpts)
185 if err != nil {
186 // SourceProfile that doesn't exist is an error in configuration.
187 if _, ok := err.(SharedConfigProfileNotExistsError); ok {
188 err = SharedConfigAssumeRoleError{
189 RoleARN: cfg.RoleARN,
190 SourceProfile: cfg.SourceProfileName,
191 }
192 }
193 return err
194 }
195
196 if !srcCfg.hasCredentials() {
197 return SharedConfigAssumeRoleError{
198 RoleARN: cfg.RoleARN,
199 SourceProfile: cfg.SourceProfileName,
200 }
201 }
202
203 cfg.SourceProfile = srcCfg
204 }
205
206 return nil
207 }
208
209 // setFromFile loads the configuration from the file using the profile
210 // provided. A sharedConfig pointer type value is used so that multiple config
211 // file loadings can be chained.
212 //
213 // Only loads complete logically grouped values, and will not set fields in cfg
214 // for incomplete grouped values in the config. Such as credentials. For
215 // example if a config file only includes aws_access_key_id but no
216 // aws_secret_access_key the aws_access_key_id will be ignored.
217 func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, exOpts bool) error {
218 section, ok := file.IniData.GetSection(profile)
219 if !ok {
220 // Fallback to to alternate profile name: profile <name>
221 section, ok = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
222 if !ok {
223 return SharedConfigProfileNotExistsError{Profile: profile, Err: nil}
224 }
225 }
226
227 if exOpts {
228 // Assume Role Parameters
229 updateString(&cfg.RoleARN, section, roleArnKey)
230 updateString(&cfg.ExternalID, section, externalIDKey)
231 updateString(&cfg.MFASerial, section, mfaSerialKey)
232 updateString(&cfg.RoleSessionName, section, roleSessionNameKey)
233 updateString(&cfg.SourceProfileName, section, sourceProfileKey)
234 updateString(&cfg.CredentialSource, section, credentialSourceKey)
235
236 updateString(&cfg.Region, section, regionKey)
237 }
238
239 updateString(&cfg.CredentialProcess, section, credentialProcessKey)
240 updateString(&cfg.WebIdentityTokenFile, section, webIdentityTokenFileKey)
241
242 // Shared Credentials
243 creds := credentials.Value{
244 AccessKeyID: section.String(accessKeyIDKey),
245 SecretAccessKey: section.String(secretAccessKey),
246 SessionToken: section.String(sessionTokenKey),
247 ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
248 }
249 if creds.HasKeys() {
250 cfg.Creds = creds
251 }
252
253 // Endpoint discovery
254 if section.Has(enableEndpointDiscoveryKey) {
255 v := section.Bool(enableEndpointDiscoveryKey)
256 cfg.EnableEndpointDiscovery = &v
257 }
258
259 return nil
260 }
261
262 func (cfg *sharedConfig) validateCredentialsRequireARN(profile string) error {
263 var credSource string
264
265 switch {
266 case len(cfg.SourceProfileName) != 0:
267 credSource = sourceProfileKey
268 case len(cfg.CredentialSource) != 0:
269 credSource = credentialSourceKey
270 case len(cfg.WebIdentityTokenFile) != 0:
271 credSource = webIdentityTokenFileKey
272 }
273
274 if len(credSource) != 0 && len(cfg.RoleARN) == 0 {
275 return CredentialRequiresARNError{
276 Type: credSource,
277 Profile: profile,
278 }
279 }
280
281 return nil
282 }
283
284 func (cfg *sharedConfig) validateCredentialType() error {
285 // Only one or no credential type can be defined.
286 if !oneOrNone(
287 len(cfg.SourceProfileName) != 0,
288 len(cfg.CredentialSource) != 0,
289 len(cfg.CredentialProcess) != 0,
290 len(cfg.WebIdentityTokenFile) != 0,
291 ) {
292 return ErrSharedConfigSourceCollision
293 }
294
295 return nil
296 }
297
298 func (cfg *sharedConfig) hasCredentials() bool {
299 switch {
300 case len(cfg.SourceProfileName) != 0:
301 case len(cfg.CredentialSource) != 0:
302 case len(cfg.CredentialProcess) != 0:
303 case len(cfg.WebIdentityTokenFile) != 0:
304 case cfg.Creds.HasKeys():
305 default:
306 return false
307 }
308
309 return true
310 }
311
312 func (cfg *sharedConfig) clearCredentialOptions() {
313 cfg.CredentialSource = ""
314 cfg.CredentialProcess = ""
315 cfg.WebIdentityTokenFile = ""
316 cfg.Creds = credentials.Value{}
317 }
318
319 func (cfg *sharedConfig) clearAssumeRoleOptions() {
320 cfg.RoleARN = ""
321 cfg.ExternalID = ""
322 cfg.MFASerial = ""
323 cfg.RoleSessionName = ""
324 cfg.SourceProfileName = ""
325 }
326
327 func oneOrNone(bs ...bool) bool {
328 var count int
329
330 for _, b := range bs {
331 if b {
332 count++
333 if count > 1 {
334 return false
335 }
336 }
337 }
338
339 return true
340 }
341
342 // updateString will only update the dst with the value in the section key, key
343 // is present in the section.
344 func updateString(dst *string, section ini.Section, key string) {
345 if !section.Has(key) {
346 return
347 }
348 *dst = section.String(key)
349 }
350
351 // SharedConfigLoadError is an error for the shared config file failed to load.
352 type SharedConfigLoadError struct {
353 Filename string
354 Err error
355 }
356
357 // Code is the short id of the error.
358 func (e SharedConfigLoadError) Code() string {
359 return "SharedConfigLoadError"
360 }
361
362 // Message is the description of the error
363 func (e SharedConfigLoadError) Message() string {
364 return fmt.Sprintf("failed to load config file, %s", e.Filename)
365 }
366
367 // OrigErr is the underlying error that caused the failure.
368 func (e SharedConfigLoadError) OrigErr() error {
369 return e.Err
370 }
371
372 // Error satisfies the error interface.
373 func (e SharedConfigLoadError) Error() string {
374 return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
375 }
376
377 // SharedConfigProfileNotExistsError is an error for the shared config when
378 // the profile was not find in the config file.
379 type SharedConfigProfileNotExistsError struct {
380 Profile string
381 Err error
382 }
383
384 // Code is the short id of the error.
385 func (e SharedConfigProfileNotExistsError) Code() string {
386 return "SharedConfigProfileNotExistsError"
387 }
388
389 // Message is the description of the error
390 func (e SharedConfigProfileNotExistsError) Message() string {
391 return fmt.Sprintf("failed to get profile, %s", e.Profile)
392 }
393
394 // OrigErr is the underlying error that caused the failure.
395 func (e SharedConfigProfileNotExistsError) OrigErr() error {
396 return e.Err
397 }
398
399 // Error satisfies the error interface.
400 func (e SharedConfigProfileNotExistsError) Error() string {
401 return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
402 }
403
404 // SharedConfigAssumeRoleError is an error for the shared config when the
405 // profile contains assume role information, but that information is invalid
406 // or not complete.
407 type SharedConfigAssumeRoleError struct {
408 RoleARN string
409 SourceProfile string
410 }
411
412 // Code is the short id of the error.
413 func (e SharedConfigAssumeRoleError) Code() string {
414 return "SharedConfigAssumeRoleError"
415 }
416
417 // Message is the description of the error
418 func (e SharedConfigAssumeRoleError) Message() string {
419 return fmt.Sprintf(
420 "failed to load assume role for %s, source profile %s has no shared credentials",
421 e.RoleARN, e.SourceProfile,
422 )
423 }
424
425 // OrigErr is the underlying error that caused the failure.
426 func (e SharedConfigAssumeRoleError) OrigErr() error {
427 return nil
428 }
429
430 // Error satisfies the error interface.
431 func (e SharedConfigAssumeRoleError) Error() string {
432 return awserr.SprintError(e.Code(), e.Message(), "", nil)
433 }
434
435 // CredentialRequiresARNError provides the error for shared config credentials
436 // that are incorrectly configured in the shared config or credentials file.
437 type CredentialRequiresARNError struct {
438 // type of credentials that were configured.
439 Type string
440
441 // Profile name the credentials were in.
442 Profile string
443 }
444
445 // Code is the short id of the error.
446 func (e CredentialRequiresARNError) Code() string {
447 return "CredentialRequiresARNError"
448 }
449
450 // Message is the description of the error
451 func (e CredentialRequiresARNError) Message() string {
452 return fmt.Sprintf(
453 "credential type %s requires role_arn, profile %s",
454 e.Type, e.Profile,
455 )
456 }
457
458 // OrigErr is the underlying error that caused the failure.
459 func (e CredentialRequiresARNError) OrigErr() error {
460 return nil
461 }
462
463 // Error satisfies the error interface.
464 func (e CredentialRequiresARNError) Error() string {
465 return awserr.SprintError(e.Code(), e.Message(), "", nil)
466 }