Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions agent/imdscreds/refresher.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (r *IMDSCredentialsRefresher) refresh() {
return
}

creds, err := r.scanner.Scan(r.ctx)
result, err := r.scanner.Scan(r.ctx)
if err != nil {
logger.Error("IMDS credentials refresh: scan failed", logger.Fields{
field.Error: err,
Expand All @@ -106,7 +106,7 @@ func (r *IMDSCredentialsRefresher) refresh() {

// upsertedCredCount tallies credentials written to the credentials manager.
upsertedCredCount := 0
for _, cred := range creds {
for _, cred := range result.Credentials {
task, ok := nonTerminalTasks[cred.TaskID]
if !ok {
// Credential for a task that's either terminal or unknown
Expand All @@ -128,10 +128,11 @@ func (r *IMDSCredentialsRefresher) refresh() {
upsertedCredCount++
}

if len(creds) > 0 {
if len(result.Credentials) > 0 || len(result.AssumeRoleUnauthorizedAccessRoles) > 0 {
logger.Info("IMDS credentials refresh: scan complete", logger.Fields{
"retrievedCredentialCount": len(creds),
"upsertedCredentialCount": upsertedCredCount,
"retrievedCredentialCount": len(result.Credentials),
"upsertedCredentialCount": upsertedCredCount,
"assumeRoleUnauthorizedAccessRoleCount": len(result.AssumeRoleUnauthorizedAccessRoles),
})
}
}
Expand Down
3 changes: 3 additions & 0 deletions agent/imdscreds/refresher_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,18 @@ func TestIMDSCredentialsRefresh(t *testing.T) {
mockIMDS.AddCredential(
"iam-ecs-1", taskID1,
credentials.ApplicationRoleType, roleARN1, "AKID_IMDS_A_APP",
ecsagentimds.CredentialCodeSuccess,
)
// Namespace 2: taskB with application + execution roles.
mockIMDS.AddCredential(
"iam-ecs-2", taskID2,
credentials.ApplicationRoleType, roleARN2, "AKID_IMDS_B_APP",
ecsagentimds.CredentialCodeSuccess,
)
mockIMDS.AddCredential(
"iam-ecs-2", taskID2,
credentials.ExecutionRoleType, roleARN2, "AKID_IMDS_B_EXEC",
ecsagentimds.CredentialCodeSuccess,
)

// Wait for the refresher to pick up the new credentials from IMDS
Expand Down
73 changes: 59 additions & 14 deletions agent/imdscreds/refresher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ func newTestTask(

func TestRefresh(t *testing.T) {
tests := []struct {
name string
listTasksErr error
tasks []*apitask.Task
scanResult []imds.TaskCredential
scanErr error
expectedUpserts []*credentials.TaskIAMRoleCredentials
name string
listTasksErr error
tasks []*apitask.Task
scanCreds []imds.TaskCredential
scanAssumeRoleUnauthorizedAccess []imds.AssumeRoleUnauthorizedAccessIAMRole
scanErr error
expectedUpserts []*credentials.TaskIAMRoleCredentials
}{
{
name: "no tasks skips scan",
Expand Down Expand Up @@ -117,7 +118,7 @@ func TestRefresh(t *testing.T) {
execCredID: testCredID2, execRoleArn: testRoleARN2,
}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
Expand Down Expand Up @@ -151,7 +152,7 @@ func TestRefresh(t *testing.T) {
execCredID: testCredID2, execRoleArn: testRoleARN2,
}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ExecutionRoleType,
Expand Down Expand Up @@ -183,7 +184,7 @@ func TestRefresh(t *testing.T) {
newTestTask(testTaskARN1, status.TaskRunning,
testTaskOpts{credID: testCredID1, roleArn: testRoleARN1}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: "unknown00000000000000000000000000",
RoleType: credentials.ApplicationRoleType,
Expand All @@ -196,7 +197,7 @@ func TestRefresh(t *testing.T) {
tasks: []*apitask.Task{
newTestTask(testTaskARN1, status.TaskRunning, testTaskOpts{}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
Expand All @@ -210,7 +211,7 @@ func TestRefresh(t *testing.T) {
newTestTask(testTaskARN1, status.TaskRunning,
testTaskOpts{credID: testCredID1, roleArn: testRoleARN1}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
Expand All @@ -226,7 +227,7 @@ func TestRefresh(t *testing.T) {
newTestTask(testTaskARN2, status.TaskRunning,
testTaskOpts{credID: testCredID3, roleArn: testRoleARN3}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
Expand Down Expand Up @@ -281,7 +282,7 @@ func TestRefresh(t *testing.T) {
execCredID: testCredID2, execRoleArn: testRoleARN1,
}),
},
scanResult: []imds.TaskCredential{
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
Expand Down Expand Up @@ -328,6 +329,47 @@ func TestRefresh(t *testing.T) {
},
},
},
{
name: "unauthorized roles are not upserted",
tasks: []*apitask.Task{
newTestTask(testTaskARN1, status.TaskRunning, testTaskOpts{
credID: testCredID1, roleArn: testRoleARN1,
execCredID: testCredID2, execRoleArn: testRoleARN2,
}),
},
scanCreds: []imds.TaskCredential{
{
TaskID: testTaskID1,
RoleType: credentials.ApplicationRoleType,
RoleArn: testRoleARN1,
AccessKeyID: "AKID_TASK",
SecretAccessKey: "secret_task",
SessionToken: "token_task",
Expiration: "2026-05-05T12:00:00Z",
},
},
scanAssumeRoleUnauthorizedAccess: []imds.AssumeRoleUnauthorizedAccessIAMRole{
{
TaskID: testTaskID1,
RoleType: credentials.ExecutionRoleType,
RoleArn: testRoleARN2,
},
},
expectedUpserts: []*credentials.TaskIAMRoleCredentials{
{
ARN: testTaskARN1,
IAMRoleCredentials: credentials.IAMRoleCredentials{
CredentialsID: testCredID1,
RoleArn: testRoleARN1,
AccessKeyID: "AKID_TASK",
SecretAccessKey: "secret_task",
SessionToken: "token_task",
Expiration: "2026-05-05T12:00:00Z",
RoleType: credentials.ApplicationRoleType,
},
},
},
},
}

for _, tc := range tests {
Expand All @@ -344,7 +386,10 @@ func TestRefresh(t *testing.T) {
if tc.listTasksErr == nil && len(nonTerminalTasksByID(tc.tasks)) > 0 {
mockScanner.EXPECT().
Scan(gomock.Any()).
Return(tc.scanResult, tc.scanErr)
Return(imds.ScanResult{
Credentials: tc.scanCreds,
AssumeRoleUnauthorizedAccessRoles: tc.scanAssumeRoleUnauthorizedAccess,
}, tc.scanErr)
}

if len(tc.expectedUpserts) > 0 {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading