Skip to content

Commit cd89b26

Browse files
authored
Merge pull request 1Password#299 from 1Password/andi_t/aws-source-profile-support
AWS: Support source_profile
2 parents a43a66d + 604c021 commit cd89b26

File tree

2 files changed

+228
-49
lines changed

2 files changed

+228
-49
lines changed

plugins/aws/access_key_test.go

Lines changed: 161 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,16 @@ func TestAccessKeyDefaultProvisioner(t *testing.T) {
252252
configPath := filepath.Join(t.TempDir(), "awsConfig")
253253
t.Setenv("AWS_CONFIG_FILE", configPath)
254254

255+
// setup profiles in config file
256+
file := ini.Empty()
257+
profileDefault, err := file.NewSection("default")
258+
require.NoError(t, err)
259+
_, err = profileDefault.NewKey("region", "us-central-1")
260+
require.NoError(t, err)
261+
262+
err = file.SaveTo(configPath)
263+
require.NoError(t, err)
264+
255265
plugintest.TestProvisioner(t, AccessKey().DefaultProvisioner, map[string]plugintest.ProvisionCase{
256266
"default": {
257267
ItemFields: map[sdk.FieldName]string{
@@ -282,22 +292,37 @@ func TestSTSProvisioner(t *testing.T) {
282292
require.NoError(t, err)
283293
_, err = profileDev.NewKey("role_arn", "aws:iam::123456789012:role/testRole2")
284294
require.NoError(t, err)
295+
285296
profileProd, err := file.NewSection("profile prod")
286297
require.NoError(t, err)
287298
_, err = profileProd.NewKey("mfa_serial", "arn:aws:iam::123456789012:mfa/user1")
288299
require.NoError(t, err)
300+
289301
profileDefault, err := file.NewSection("default")
290302
require.NoError(t, err)
291-
_, err = profileDefault.NewKey("role_arn", "aws:iam::123456789012:role/testRole")
292-
require.NoError(t, err)
293303
_, err = profileDefault.NewKey("region", "us-central-1")
294304
require.NoError(t, err)
305+
295306
profileTest, err := file.NewSection("profile test")
296307
require.NoError(t, err)
297308
_, err = profileTest.NewKey("mfa_serial", "arn:aws:iam::123456789012:mfa/user1")
298309
require.NoError(t, err)
299310
_, err = profileTest.NewKey("role_arn", "aws:iam::123456789012:role/testRole")
300311
require.NoError(t, err)
312+
313+
profileSourceComplex, err := file.NewSection("profile testSourceComplex")
314+
require.NoError(t, err)
315+
_, err = profileSourceComplex.NewKey("mfa_serial", "arn:aws:iam::123456789012:mfa/user1")
316+
require.NoError(t, err)
317+
_, err = profileSourceComplex.NewKey("role_arn", "aws:iam::123456789012:role/testRole")
318+
require.NoError(t, err)
319+
_, err = profileSourceComplex.NewKey("source_profile", "testSourceSimple")
320+
require.NoError(t, err)
321+
322+
profileSourceSimple, err := file.NewSection("profile testSourceSimple")
323+
require.NoError(t, err)
324+
_, err = profileSourceSimple.NewKey("source_profile", "default")
325+
require.NoError(t, err)
301326
err = file.SaveTo(configPath)
302327
require.NoError(t, err)
303328

@@ -392,6 +417,132 @@ func TestSTSProvisioner(t *testing.T) {
392417
},
393418
},
394419
})
420+
421+
plugintest.TestProvisioner(t, STSProvisioner{
422+
profileName: "testSourceSimple",
423+
newProviderFactory: func(cacheState sdk.CacheState, cacheOps sdk.CacheOperations, fields map[sdk.FieldName]string) STSProviderFactory {
424+
return &mockProviderManager{ItemFields: map[sdk.FieldName]string{
425+
fieldname.AccessKeyID: "AKIAHPIZFMD5EEXAMPLE",
426+
fieldname.SecretAccessKey: "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
427+
}}
428+
},
429+
}, map[string]plugintest.ProvisionCase{
430+
"WithSourceProfileSimple": {
431+
ItemFields: map[sdk.FieldName]string{
432+
fieldname.AccessKeyID: "AKIAHPIZFMD5EEXAMPLE",
433+
fieldname.SecretAccessKey: "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
434+
},
435+
ExpectedOutput: sdk.ProvisionOutput{
436+
Environment: map[string]string{
437+
"AWS_ACCESS_KEY_ID": "AKIAHPIZFMD5EEXAMPLE",
438+
"AWS_SECRET_ACCESS_KEY": "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
439+
"AWS_DEFAULT_REGION": "us-central-1",
440+
},
441+
},
442+
},
443+
})
444+
445+
plugintest.TestProvisioner(t, STSProvisioner{
446+
profileName: "testSourceComplex",
447+
newProviderFactory: func(cacheState sdk.CacheState, cacheOps sdk.CacheOperations, fields map[sdk.FieldName]string) STSProviderFactory {
448+
return &mockProviderManager{}
449+
},
450+
}, map[string]plugintest.ProvisionCase{
451+
"WithSourceProfileComplex": {
452+
ItemFields: map[sdk.FieldName]string{
453+
fieldname.AccessKeyID: "AKIAHPIZFMD5EEXAMPLE",
454+
fieldname.SecretAccessKey: "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
455+
fieldname.DefaultRegion: "us-central-1",
456+
fieldname.OneTimePassword: "908789",
457+
fieldname.MFASerial: "arn:aws:iam::123456789012:mfa/user1",
458+
},
459+
ExpectedOutput: sdk.ProvisionOutput{
460+
Environment: map[string]string{
461+
"AWS_ACCESS_KEY_ID": "AKIAHPIZFMD5EEXSTS",
462+
"AWS_SECRET_ACCESS_KEY": "stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY",
463+
"AWS_SESSION_TOKEN": "stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY///////stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY///////stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY",
464+
"AWS_DEFAULT_REGION": "us-central-1",
465+
},
466+
},
467+
},
468+
})
469+
}
470+
471+
func TestSourceProfileLoop(t *testing.T) {
472+
t.Setenv("AWS_PROFILE", "")
473+
t.Setenv("AWS_DEFAULT_REGION", "")
474+
configPath := filepath.Join(t.TempDir(), "awsConfig")
475+
t.Setenv("AWS_CONFIG_FILE", configPath)
476+
477+
// setup profiles in config file
478+
file := ini.Empty()
479+
profileDev, err := file.NewSection("profile dev")
480+
require.NoError(t, err)
481+
_, err = profileDev.NewKey("source_profile", "default")
482+
require.NoError(t, err)
483+
484+
profileDefault, err := file.NewSection("default")
485+
require.NoError(t, err)
486+
_, err = profileDefault.NewKey("source_profile", "prod")
487+
require.NoError(t, err)
488+
489+
profileProd, err := file.NewSection("profile prod")
490+
require.NoError(t, err)
491+
_, err = profileProd.NewKey("source_profile", "dev")
492+
require.NoError(t, err)
493+
494+
profileStaging, err := file.NewSection("profile staging")
495+
require.NoError(t, err)
496+
_, err = profileStaging.NewKey("source_profile", "staging")
497+
require.NoError(t, err)
498+
499+
err = file.SaveTo(configPath)
500+
require.NoError(t, err)
501+
502+
plugintest.TestProvisioner(t, STSProvisioner{
503+
profileName: "prod",
504+
newProviderFactory: func(cacheState sdk.CacheState, cacheOps sdk.CacheOperations, fields map[sdk.FieldName]string) STSProviderFactory {
505+
return &mockProviderManager{}
506+
},
507+
}, map[string]plugintest.ProvisionCase{
508+
"WithEndlessLoop": {
509+
ItemFields: map[sdk.FieldName]string{
510+
fieldname.AccessKeyID: "AKIAHPIZFMD5EEXAMPLE",
511+
fieldname.SecretAccessKey: "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
512+
fieldname.DefaultRegion: "us-central-1",
513+
fieldname.OneTimePassword: "908789",
514+
fieldname.MFASerial: "arn:aws:iam::123456789012:mfa/user1",
515+
},
516+
ExpectedOutput: sdk.ProvisionOutput{
517+
Diagnostics: sdk.Diagnostics{Errors: []sdk.Error{{Message: "infinite loop in credential configuration detected. Attempting to load from profile \"prod\" which has already been visited"}}},
518+
},
519+
},
520+
})
521+
522+
plugintest.TestProvisioner(t, STSProvisioner{
523+
profileName: "staging",
524+
newProviderFactory: func(cacheState sdk.CacheState, cacheOps sdk.CacheOperations, fields map[sdk.FieldName]string) STSProviderFactory {
525+
return &mockProviderManager{}
526+
},
527+
}, map[string]plugintest.ProvisionCase{
528+
"WithAcceptedLoop": {
529+
ItemFields: map[sdk.FieldName]string{
530+
fieldname.AccessKeyID: "AKIAHPIZFMD5EEXAMPLE",
531+
fieldname.SecretAccessKey: "lBfKB7P5ScmpxDeRoFLZvhJbqNGPoV0vIEXAMPLE",
532+
fieldname.DefaultRegion: "us-central-1",
533+
fieldname.OneTimePassword: "908789",
534+
fieldname.MFASerial: "arn:aws:iam::123456789012:mfa/user1",
535+
},
536+
ExpectedOutput: sdk.ProvisionOutput{
537+
Environment: map[string]string{
538+
"AWS_ACCESS_KEY_ID": "AKIAHPIZFMD5EEXSTS",
539+
"AWS_SECRET_ACCESS_KEY": "stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY",
540+
"AWS_SESSION_TOKEN": "stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY///////stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY///////stststststst/K7MDENG/bPxRfiCYEXAMPLEKEY",
541+
"AWS_DEFAULT_REGION": "us-central-1",
542+
},
543+
},
544+
},
545+
})
395546
}
396547

397548
func TestResolveLocalAnd1PasswordConfigurations(t *testing.T) {
@@ -469,17 +620,7 @@ func TestResolveLocalAnd1PasswordConfigurations(t *testing.T) {
469620
ProfileName: "dev",
470621
MfaSerial: "arn:aws:iam::123456789012:mfa/user",
471622
},
472-
err: fmt.Errorf("MFA failed: an MFA serial was found but no OTP has been set up in 1Password"),
473-
},
474-
{
475-
description: "has mfa token but no mfa serial",
476-
itemFields: map[sdk.FieldName]string{
477-
fieldname.OneTimePassword: "515467",
478-
},
479-
awsConfig: &confighelpers.Config{
480-
ProfileName: "dev",
481-
},
482-
err: fmt.Errorf("MFA failed: an OTP was found wihtout a corresponding MFA serial"),
623+
err: fmt.Errorf("MFA failed: MFA serial \"arn:aws:iam::123456789012:mfa/user\" was detected on the associated item or in the config file for the selected profile, but no 'One-Time Password' field was found.\nLearn how to add an OTP field to your item:\nhttps://developer.1password.com/docs/cli/shell-plugins/aws/#optional-set-up-multi-factor-authentication"),
483624
},
484625
{
485626
description: "has region only in 1Password",
@@ -653,13 +794,17 @@ func (p mockAwsProvider) Retrieve(ctx context.Context) (aws.Credentials, error)
653794
}
654795

655796
type mockProviderManager struct {
656-
CacheProviderFactory
797+
ItemFields map[sdk.FieldName]string
657798
}
658799

659-
func (m mockProviderManager) NewMFASessionTokenProvider(awsConfig *confighelpers.Config) aws.CredentialsProvider {
800+
func (m mockProviderManager) NewMFASessionTokenProvider(awsConfig *confighelpers.Config, srcCredProvider aws.CredentialsProvider) aws.CredentialsProvider {
660801
return mockAwsProvider{}
661802
}
662803

663-
func (m mockProviderManager) NewAssumeRoleProvider(awsConfig *confighelpers.Config) aws.CredentialsProvider {
804+
func (m mockProviderManager) NewAssumeRoleProvider(awsConfig *confighelpers.Config, srcCredProvider aws.CredentialsProvider) aws.CredentialsProvider {
664805
return mockAwsProvider{}
665806
}
807+
808+
func (m mockProviderManager) NewAccessKeysProvider() aws.CredentialsProvider {
809+
return accessKeysProvider{itemFields: m.ItemFields}
810+
}

0 commit comments

Comments
 (0)