Skip to content

Commit 844abaf

Browse files
committed
feat: update to IMDS credentials provider SEP v2.1.1
1 parent 11ea51a commit 844abaf

File tree

4 files changed

+157
-6
lines changed

4 files changed

+157
-6
lines changed

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/ImdsCredentialsProvider.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import aws.smithy.kotlin.runtime.util.asyncLazy
2323
import kotlin.coroutines.coroutineContext
2424

2525
private const val CODE_ASSUME_ROLE_UNAUTHORIZED_ACCESS: String = "AssumeRoleUnauthorizedAccess"
26+
private const val MAX_ATTEMPTS = 10
2627
private const val PROVIDER_NAME = "IMDSv2"
2728

2829
/**
@@ -105,11 +106,15 @@ public class ImdsCredentialsProvider(
105106

106107
override suspend fun resolve(attributes: Attributes): Credentials = sfg.singleFlight(::resolveSingleFlight)
107108

108-
private suspend fun resolveSingleFlight(): Credentials {
109+
private suspend fun resolveSingleFlight(attempts: Int = 0): Credentials {
109110
if (providerDisabled.get()) {
110111
throw CredentialsNotLoadedException("AWS EC2 metadata is explicitly disabled; credentials not loaded")
111112
}
112113

114+
if (attempts >= MAX_ATTEMPTS) {
115+
throw CredentialsNotLoadedException("Failed to retrieve profile credentials after $attempts attempts")
116+
}
117+
113118
val profileName = instanceProfileName.get() ?: resolvedProfileName ?: try {
114119
actualClient.get(urlBase).also {
115120
if (apiVersion == null) {
@@ -122,7 +127,7 @@ public class ImdsCredentialsProvider(
122127
apiVersion == null && ex.status == HttpStatusCode.NotFound -> {
123128
// Tried EXTENDED and that didn't work; fallback to LEGACY
124129
apiVersion = ApiVersion.LEGACY
125-
return resolveSingleFlight()
130+
return resolveSingleFlight(attempts) // one-time condition, do not increase `attempts`
126131
}
127132

128133
ex.status == HttpStatusCode.NotFound -> {
@@ -148,13 +153,13 @@ public class ImdsCredentialsProvider(
148153
apiVersion == null && ex.status == HttpStatusCode.NotFound -> {
149154
// Tried EXTENDED and that didn't work; fallback to LEGACY
150155
apiVersion = ApiVersion.LEGACY
151-
return resolveSingleFlight()
156+
return resolveSingleFlight() // one-time condition, do not increase `attempts`
152157
}
153158

154159
instanceProfileName.get() == null && ex.status == HttpStatusCode.NotFound -> {
155160
// A previously-resolved profile is now invalid; forget the resolved name and re-resolve
156161
resolvedProfileName = null
157-
return resolveSingleFlight()
162+
return resolveSingleFlight(attempts + 1) // potentially infinite recursion, increase `attempts`
158163
}
159164

160165
else -> return usePreviousCredentials()

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsSdkSetting.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
package aws.sdk.kotlin.runtime.config
77

88
import aws.sdk.kotlin.runtime.InternalSdkApi
9+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting.AwsAccessKeyId
10+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting.AwsContainerCredentialsRelativeUri
11+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting.AwsSecretAccessKey
912
import aws.sdk.kotlin.runtime.config.endpoints.AccountIdEndpointMode
1013
import aws.sdk.kotlin.runtime.http.AWS_APP_ID_ENV
1114
import aws.sdk.kotlin.runtime.http.AWS_APP_ID_PROP
@@ -88,7 +91,7 @@ public object AwsSdkSetting {
8891
* Whether to load information such as credentials, regions from EC2 Metadata instance service.
8992
*/
9093
public val AwsEc2MetadataDisabled: EnvironmentSetting<Boolean> =
91-
boolEnvSetting("aws.disableEc2Metadata", "AWS_EC2_METADATA_DISABLED").orElse(false)
94+
boolEnvSetting("aws.ec2MetadataDisabled", "AWS_EC2_METADATA_DISABLED").orElse(false)
9295

9396
/**
9497
* The EC2 instance metadata service endpoint.

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/profile/AwsProfile.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public val AwsProfile.ec2InstanceProfileName: String?
189189
*/
190190
@InternalSdkApi
191191
public val AwsProfile.ec2MetadataDisabled: Boolean?
192-
get() = getBooleanOrNull("disable_ec2_metadata")
192+
get() = getBooleanOrNull("ec2_metadata_disabled")
193193

194194
/**
195195
* Parse a config value as a boolean, ignoring case.

aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/auth/credentials/ImdsCredentialsProviderTestResources.kt

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,149 @@ val imdsCredentialsTestSpec = """
653653
"result": "invalid profile"
654654
}
655655
]
656+
},
657+
{
658+
"summary": "Test IMDS credentials provider when profile never stabilizes returns no credentials",
659+
"config": {
660+
"ec2InstanceProfileName": null
661+
},
662+
"expectations": [
663+
{
664+
"get": "/latest/meta-data/iam/security-credentials-extended",
665+
"response": {
666+
"status": 200,
667+
"body": "my-profile-0013"
668+
}
669+
},
670+
{
671+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
672+
"response": {
673+
"status": 404
674+
}
675+
},
676+
{
677+
"get": "/latest/meta-data/iam/security-credentials-extended",
678+
"response": {
679+
"status": 200,
680+
"body": "my-profile-0013"
681+
}
682+
},
683+
{
684+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
685+
"response": {
686+
"status": 404
687+
}
688+
},
689+
{
690+
"get": "/latest/meta-data/iam/security-credentials-extended",
691+
"response": {
692+
"status": 200,
693+
"body": "my-profile-0013"
694+
}
695+
},
696+
{
697+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
698+
"response": {
699+
"status": 404
700+
}
701+
},
702+
{
703+
"get": "/latest/meta-data/iam/security-credentials-extended",
704+
"response": {
705+
"status": 200,
706+
"body": "my-profile-0013"
707+
}
708+
},
709+
{
710+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
711+
"response": {
712+
"status": 404
713+
}
714+
},
715+
{
716+
"get": "/latest/meta-data/iam/security-credentials-extended",
717+
"response": {
718+
"status": 200,
719+
"body": "my-profile-0013"
720+
}
721+
},
722+
{
723+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
724+
"response": {
725+
"status": 404
726+
}
727+
},
728+
{
729+
"get": "/latest/meta-data/iam/security-credentials-extended",
730+
"response": {
731+
"status": 200,
732+
"body": "my-profile-0013"
733+
}
734+
},
735+
{
736+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
737+
"response": {
738+
"status": 404
739+
}
740+
},
741+
{
742+
"get": "/latest/meta-data/iam/security-credentials-extended",
743+
"response": {
744+
"status": 200,
745+
"body": "my-profile-0013"
746+
}
747+
},
748+
{
749+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
750+
"response": {
751+
"status": 404
752+
}
753+
},
754+
{
755+
"get": "/latest/meta-data/iam/security-credentials-extended",
756+
"response": {
757+
"status": 200,
758+
"body": "my-profile-0013"
759+
}
760+
},
761+
{
762+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
763+
"response": {
764+
"status": 404
765+
}
766+
},
767+
{
768+
"get": "/latest/meta-data/iam/security-credentials-extended",
769+
"response": {
770+
"status": 200,
771+
"body": "my-profile-0013"
772+
}
773+
},
774+
{
775+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
776+
"response": {
777+
"status": 404
778+
}
779+
},
780+
{
781+
"get": "/latest/meta-data/iam/security-credentials-extended",
782+
"response": {
783+
"status": 200,
784+
"body": "my-profile-0013"
785+
}
786+
},
787+
{
788+
"get": "/latest/meta-data/iam/security-credentials-extended/my-profile-0013",
789+
"response": {
790+
"status": 404
791+
}
792+
}
793+
],
794+
"outcomes": [
795+
{
796+
"result": "no credentials"
797+
}
798+
]
656799
}
657800
]
658801
""".trimIndent()

0 commit comments

Comments
 (0)