Skip to content

Commit c24cdae

Browse files
authored
Implement credentials chain for aws-sdk-go-v2 (#4424)
1 parent d674aa2 commit c24cdae

File tree

743 files changed

+124840
-115
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

743 files changed

+124840
-115
lines changed

agent/app/agent.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import (
5959
apierrors "github.com/aws/amazon-ecs-agent/ecs-agent/api/errors"
6060
"github.com/aws/amazon-ecs-agent/ecs-agent/credentials"
6161
"github.com/aws/amazon-ecs-agent/ecs-agent/credentials/instancecreds"
62+
"github.com/aws/amazon-ecs-agent/ecs-agent/credentials/providers"
6263
"github.com/aws/amazon-ecs-agent/ecs-agent/doctor"
6364
"github.com/aws/amazon-ecs-agent/ecs-agent/ec2"
6465
"github.com/aws/amazon-ecs-agent/ecs-agent/eventstream"
@@ -68,6 +69,7 @@ import (
6869
"github.com/aws/amazon-ecs-agent/ecs-agent/tcs/model/ecstcs"
6970
"github.com/aws/amazon-ecs-agent/ecs-agent/utils/retry"
7071
"github.com/aws/amazon-ecs-agent/ecs-agent/wsclient"
72+
awsv2 "github.com/aws/aws-sdk-go-v2/aws"
7173
"github.com/aws/aws-sdk-go/aws"
7274
"github.com/aws/aws-sdk-go/aws/awserr"
7375
aws_credentials "github.com/aws/aws-sdk-go/aws/credentials"
@@ -146,6 +148,7 @@ type ecsAgent struct {
146148
dockerClient dockerapi.DockerClient
147149
containerInstanceARN string
148150
credentialProvider *aws_credentials.Credentials
151+
credentialsCache awsv2.CredentialsProvider
149152
stateManagerFactory factory.StateManager
150153
saveableOptionFactory factory.SaveableOption
151154
pauseLoader loader.Loader
@@ -231,6 +234,13 @@ func newAgent(blackholeEC2Metadata bool, acceptInsecureCert *bool) (agent, error
231234
metadataManager = containermetadata.NewManager(dockerClient, cfg)
232235
}
233236

237+
credentialsCache := awsv2.NewCredentialsCache(
238+
providers.NewInstanceCredentialsCache(
239+
cfg.External.Enabled(),
240+
providers.NewRotatingSharedCredentialsProviderV2(),
241+
nil,
242+
),
243+
)
234244
initialSeqNumber := int64(-1)
235245
return &ecsAgent{
236246
ctx: ctx,
@@ -244,6 +254,7 @@ func newAgent(blackholeEC2Metadata bool, acceptInsecureCert *bool) (agent, error
244254
// to mimic roughly the way it's instantiated by the SDK for a default
245255
// session.
246256
credentialProvider: instancecreds.GetCredentials(cfg.External.Enabled()),
257+
credentialsCache: credentialsCache,
247258
stateManagerFactory: factory.NewStateManager(),
248259
saveableOptionFactory: factory.NewSaveableOption(),
249260
pauseLoader: pause.New(),
@@ -781,7 +792,7 @@ func (agent *ecsAgent) registerContainerInstance(
781792
client ecs.ECSClient,
782793
additionalAttributes []*ecsmodel.Attribute) error {
783794
// Preflight request to make sure they're good
784-
if preflightCreds, err := agent.credentialProvider.Get(); err != nil || preflightCreds.AccessKeyID == "" {
795+
if preflightCreds, err := agent.credentialsCache.Retrieve(context.TODO()); err != nil || !preflightCreds.HasKeys() {
785796
seelog.Errorf("Error getting valid credentials: %s", err)
786797
}
787798

agent/app/agent_test.go

+62-62
Large diffs are not rendered by default.

agent/app/agent_unix_test.go

+46-52
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ import (
4747
"github.com/aws/amazon-ecs-agent/ecs-agent/eventstream"
4848
md "github.com/aws/amazon-ecs-agent/ecs-agent/manageddaemon"
4949

50+
awsv2 "github.com/aws/aws-sdk-go-v2/aws"
5051
"github.com/aws/aws-sdk-go/aws"
5152
"github.com/aws/aws-sdk-go/aws/awserr"
52-
"github.com/aws/aws-sdk-go/aws/credentials"
5353
"github.com/golang/mock/gomock"
5454
"github.com/stretchr/testify/assert"
5555
)
@@ -74,7 +74,7 @@ func TestDoStartTaskENIHappyPath(t *testing.T) {
7474
monitoShutdownEvents := make(chan bool)
7575

7676
cniClient := mock_ecscni.NewMockCNIClient(ctrl)
77-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
77+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
7878
mockPauseLoader := mock_loader.NewMockLoader(ctrl)
7979
mockUdevMonitor := mock_udev.NewMockUdev(ctrl)
8080
mockMetadata := mock_ec2.NewMockEC2MetadataClient(ctrl)
@@ -88,7 +88,6 @@ func TestDoStartTaskENIHappyPath(t *testing.T) {
8888

8989
// These calls are expected to happen, but cannot be ordered as they are
9090
// invoked via go routines, which will lead to occasional test failues
91-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
9291
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
9392
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
9493
dockerClient.EXPECT().ListContainers(gomock.Any(), gomock.Any(), gomock.Any()).Return(
@@ -135,7 +134,7 @@ func TestDoStartTaskENIHappyPath(t *testing.T) {
135134
cniClient.EXPECT().Capabilities(ecscni.ECSIPAMPluginName).Return(cniCapabilities, nil),
136135
cniClient.EXPECT().Capabilities(ecscni.ECSAppMeshPluginName).Return(cniCapabilities, nil),
137136
cniClient.EXPECT().Capabilities(ecscni.ECSBranchENIPluginName).Return(cniCapabilities, nil),
138-
mockCredentialsProvider.EXPECT().Retrieve().Return(credentials.Value{}, nil),
137+
mockCredentialsProvider.EXPECT().Retrieve(gomock.Any()).Return(awsv2.Credentials{}, nil),
139138
cniClient.EXPECT().Version(ecscni.VPCENIPluginName).Return("v1", nil),
140139
cniClient.EXPECT().Version(ecscni.ECSBranchENIPluginName).Return("v2", nil),
141140
mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil),
@@ -170,15 +169,15 @@ func TestDoStartTaskENIHappyPath(t *testing.T) {
170169
ctx, cancel := context.WithCancel(context.TODO())
171170
// Cancel the context to cancel async routines
172171
agent := &ecsAgent{
173-
ctx: ctx,
174-
cfg: &cfg,
175-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
176-
dataClient: data.NewNoopClient(),
177-
dockerClient: dockerClient,
178-
pauseLoader: mockPauseLoader,
179-
eniWatcher: eniWatcher,
180-
cniClient: cniClient,
181-
ec2MetadataClient: mockMetadata,
172+
ctx: ctx,
173+
cfg: &cfg,
174+
credentialsCache: mockCredentialsProvider,
175+
dataClient: data.NewNoopClient(),
176+
dockerClient: dockerClient,
177+
pauseLoader: mockPauseLoader,
178+
eniWatcher: eniWatcher,
179+
cniClient: cniClient,
180+
ec2MetadataClient: mockMetadata,
182181
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
183182
},
184183
mobyPlugins: mockMobyPlugins,
@@ -441,7 +440,7 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) {
441440
ctrl, credentialsManager, state, imageManager, client,
442441
dockerClient, _, _, execCmdMgr, _ := setup(t)
443442
defer ctrl.Finish()
444-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
443+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
445444
mockControl := mock_control.NewMockControl(ctrl)
446445
mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl)
447446
mockPauseLoader := mock_loader.NewMockLoader(ctrl)
@@ -453,7 +452,6 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) {
453452
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
454453
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
455454
imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1)
456-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
457455
ec2MetadataClient.EXPECT().PrimaryENIMAC().Return("mac", nil)
458456
ec2MetadataClient.EXPECT().VPCID(gomock.Eq("mac")).Return("vpc-id", nil)
459457
ec2MetadataClient.EXPECT().SubnetID(gomock.Eq("mac")).Return("subnet-id", nil)
@@ -479,7 +477,7 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) {
479477

480478
gomock.InOrder(
481479
mockControl.EXPECT().Init().Return(nil),
482-
mockCredentialsProvider.EXPECT().Retrieve().Return(credentials.Value{}, nil),
480+
mockCredentialsProvider.EXPECT().Retrieve(gomock.Any()).Return(awsv2.Credentials{}, nil),
483481
mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil),
484482
dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
485483
gomock.Any()).Return([]string{}, nil),
@@ -510,11 +508,11 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) {
510508
ctx, cancel := context.WithCancel(context.TODO())
511509
// Cancel the context to cancel async routines
512510
agent := &ecsAgent{
513-
ctx: ctx,
514-
cfg: &cfg,
515-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
516-
pauseLoader: mockPauseLoader,
517-
dockerClient: dockerClient,
511+
ctx: ctx,
512+
cfg: &cfg,
513+
credentialsCache: mockCredentialsProvider,
514+
pauseLoader: mockPauseLoader,
515+
dockerClient: dockerClient,
518516
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
519517
},
520518
mobyPlugins: mockMobyPlugins,
@@ -547,7 +545,7 @@ func TestDoStartCgroupInitErrorPath(t *testing.T) {
547545
dockerClient, _, _, execCmdMgr, _ := setup(t)
548546
defer ctrl.Finish()
549547

550-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
548+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
551549
mockControl := mock_control.NewMockControl(ctrl)
552550
mockPauseLoader := mock_loader.NewMockLoader(ctrl)
553551
var discoverEndpointsInvoked sync.WaitGroup
@@ -556,7 +554,6 @@ func TestDoStartCgroupInitErrorPath(t *testing.T) {
556554
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
557555
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
558556
imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1)
559-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
560557
mockPauseLoader.EXPECT().LoadImage(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
561558
mockPauseLoader.EXPECT().IsLoaded(gomock.Any()).Return(true, nil).AnyTimes()
562559
mockServiceConnectManager := mock_serviceconnect.NewMockManager(ctrl)
@@ -580,11 +577,11 @@ func TestDoStartCgroupInitErrorPath(t *testing.T) {
580577
// Cancel the context to cancel async routines
581578
defer cancel()
582579
agent := &ecsAgent{
583-
ctx: ctx,
584-
cfg: &cfg,
585-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
586-
dockerClient: dockerClient,
587-
pauseLoader: mockPauseLoader,
580+
ctx: ctx,
581+
cfg: &cfg,
582+
credentialsCache: mockCredentialsProvider,
583+
dockerClient: dockerClient,
584+
pauseLoader: mockPauseLoader,
588585
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
589586
},
590587
resourceFields: &taskresource.ResourceFields{
@@ -603,7 +600,7 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) {
603600
ctrl, credentialsManager, state, imageManager, client,
604601
dockerClient, _, _, execCmdMgr, _ := setup(t)
605602
defer ctrl.Finish()
606-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
603+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
607604
mockGPUManager := mock_gpu.NewMockGPUManager(ctrl)
608605
mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl)
609606
ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl)
@@ -630,7 +627,6 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) {
630627
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
631628
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
632629
imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1)
633-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
634630
ec2MetadataClient.EXPECT().PrimaryENIMAC().Return("mac", nil)
635631
ec2MetadataClient.EXPECT().VPCID(gomock.Eq("mac")).Return("vpc-id", nil)
636632
ec2MetadataClient.EXPECT().SubnetID(gomock.Eq("mac")).Return("subnet-id", nil)
@@ -657,7 +653,7 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) {
657653

658654
gomock.InOrder(
659655
mockGPUManager.EXPECT().Initialize().Return(nil),
660-
mockCredentialsProvider.EXPECT().Retrieve().Return(credentials.Value{}, nil),
656+
mockCredentialsProvider.EXPECT().Retrieve(gomock.Any()).Return(awsv2.Credentials{}, nil),
661657
mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil),
662658
dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
663659
gomock.Any()).Return([]string{}, nil),
@@ -691,11 +687,11 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) {
691687
ctx, cancel := context.WithCancel(context.TODO())
692688
// Cancel the context to cancel async routines
693689
agent := &ecsAgent{
694-
ctx: ctx,
695-
cfg: &cfg,
696-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
697-
dockerClient: dockerClient,
698-
pauseLoader: mockPauseLoader,
690+
ctx: ctx,
691+
cfg: &cfg,
692+
credentialsCache: mockCredentialsProvider,
693+
dockerClient: dockerClient,
694+
pauseLoader: mockPauseLoader,
699695
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
700696
},
701697
mobyPlugins: mockMobyPlugins,
@@ -728,7 +724,7 @@ func TestDoStartGPUManagerInitError(t *testing.T) {
728724
dockerClient, _, _, execCmdMgr, _ := setup(t)
729725
defer ctrl.Finish()
730726

731-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
727+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
732728
mockGPUManager := mock_gpu.NewMockGPUManager(ctrl)
733729
mockPauseLoader := mock_loader.NewMockLoader(ctrl)
734730
var discoverEndpointsInvoked sync.WaitGroup
@@ -737,7 +733,6 @@ func TestDoStartGPUManagerInitError(t *testing.T) {
737733
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
738734
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
739735
imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1)
740-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
741736
mockGPUManager.EXPECT().Initialize().Return(errors.New("init error"))
742737
mockPauseLoader.EXPECT().LoadImage(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
743738
mockPauseLoader.EXPECT().IsLoaded(gomock.Any()).Return(true, nil).AnyTimes()
@@ -754,11 +749,11 @@ func TestDoStartGPUManagerInitError(t *testing.T) {
754749
// Cancel the context to cancel async routines
755750
defer cancel()
756751
agent := &ecsAgent{
757-
ctx: ctx,
758-
cfg: &cfg,
759-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
760-
dockerClient: dockerClient,
761-
pauseLoader: mockPauseLoader,
752+
ctx: ctx,
753+
cfg: &cfg,
754+
credentialsCache: mockCredentialsProvider,
755+
dockerClient: dockerClient,
756+
pauseLoader: mockPauseLoader,
762757
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
763758
},
764759
resourceFields: &taskresource.ResourceFields{
@@ -779,7 +774,7 @@ func TestDoStartTaskENIPauseError(t *testing.T) {
779774
defer ctrl.Finish()
780775

781776
cniClient := mock_ecscni.NewMockCNIClient(ctrl)
782-
mockCredentialsProvider := app_mocks.NewMockProvider(ctrl)
777+
mockCredentialsProvider := app_mocks.NewMockCredentialsProvider(ctrl)
783778
mockPauseLoader := mock_loader.NewMockLoader(ctrl)
784779
mockMetadata := mock_ec2.NewMockEC2MetadataClient(ctrl)
785780
mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl)
@@ -789,7 +784,6 @@ func TestDoStartTaskENIPauseError(t *testing.T) {
789784

790785
// These calls are expected to happen, but cannot be ordered as they are
791786
// invoked via go routines, which will lead to occasional test failures
792-
mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes()
793787
dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes()
794788
dockerClient.EXPECT().SupportedVersions().Return(apiVersions).AnyTimes()
795789
dockerClient.EXPECT().ListContainers(gomock.Any(), gomock.Any(), gomock.Any()).Return(
@@ -803,13 +797,13 @@ func TestDoStartTaskENIPauseError(t *testing.T) {
803797
cfg.ENITrunkingEnabled = config.BooleanDefaultTrue{Value: config.ExplicitlyEnabled}
804798
ctx, _ := context.WithCancel(context.TODO())
805799
agent := &ecsAgent{
806-
ctx: ctx,
807-
cfg: &cfg,
808-
credentialProvider: credentials.NewCredentials(mockCredentialsProvider),
809-
dockerClient: dockerClient,
810-
pauseLoader: mockPauseLoader,
811-
cniClient: cniClient,
812-
ec2MetadataClient: mockMetadata,
800+
ctx: ctx,
801+
cfg: &cfg,
802+
credentialsCache: mockCredentialsProvider,
803+
dockerClient: dockerClient,
804+
pauseLoader: mockPauseLoader,
805+
cniClient: cniClient,
806+
ec2MetadataClient: mockMetadata,
813807
terminationHandler: func(state dockerstate.TaskEngineState, dataClient data.Client, taskEngine engine.TaskEngine, cancel context.CancelFunc) {
814808
},
815809
mobyPlugins: mockMobyPlugins,

agent/app/generate_mocks.go

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
package app
1515

1616
//go:generate mockgen -destination=mocks/credentials_mocks.go -copyright_file=../../scripts/copyright_file github.com/aws/aws-sdk-go/aws/credentials Provider
17+
//go:generate mockgen -destination=mocks/credentials_provider_mocks.go -package mock_credentials -copyright_file=../../scripts/copyright_file github.com/aws/aws-sdk-go-v2/aws CredentialsProvider

agent/app/mocks/credentials_provider_mocks.go

+65
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)