3131import software .amazon .awssdk .annotations .SdkPublicApi ;
3232import software .amazon .awssdk .annotations .SdkTestInternalApi ;
3333import software .amazon .awssdk .auth .credentials .internal .Ec2MetadataConfigProvider ;
34+ import software .amazon .awssdk .auth .credentials .internal .Ec2MetadataDisableV1Resolver ;
3435import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader ;
3536import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader .LoadedCredentials ;
3637import software .amazon .awssdk .auth .credentials .internal .StaticResourcesEndpointProvider ;
4041import software .amazon .awssdk .profiles .ProfileFile ;
4142import software .amazon .awssdk .profiles .ProfileFileSupplier ;
4243import software .amazon .awssdk .profiles .ProfileFileSystemSetting ;
44+ import software .amazon .awssdk .profiles .ProfileProperty ;
4345import software .amazon .awssdk .regions .util .HttpResourcesUtils ;
4446import software .amazon .awssdk .regions .util .ResourcesEndpointProvider ;
4547import software .amazon .awssdk .utils .Logger ;
5355
5456/**
5557 * Credentials provider implementation that loads credentials from the Amazon EC2 Instance Metadata Service.
56- *
57- * <P>
58+ * <p>
5859 * If {@link SdkSystemSetting#AWS_EC2_METADATA_DISABLED} is set to true, it will not try to load
5960 * credentials from EC2 metadata service and will return null.
61+ * <p>
62+ * If {@link SdkSystemSetting#AWS_EC2_METADATA_V1_DISABLED} or {@link ProfileProperty#EC2_METADATA_V1_DISABLED}
63+ * is set to true, credentials will only be loaded from EC2 metadata service if a token is successfully retrieved -
64+ * fallback to load credentials without a token will be disabled.
6065 */
6166@ SdkPublicApi
6267public final class InstanceProfileCredentialsProvider
@@ -73,6 +78,7 @@ public final class InstanceProfileCredentialsProvider
7378 private final Clock clock ;
7479 private final String endpoint ;
7580 private final Ec2MetadataConfigProvider configProvider ;
81+ private final Ec2MetadataDisableV1Resolver ec2MetadataDisableV1Resolver ;
7682 private final HttpCredentialsLoader httpCredentialsLoader ;
7783 private final CachedSupplier <AwsCredentials > credentialsCache ;
7884
@@ -92,15 +98,18 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) {
9298 this .endpoint = builder .endpoint ;
9399 this .asyncCredentialUpdateEnabled = builder .asyncCredentialUpdateEnabled ;
94100 this .asyncThreadName = builder .asyncThreadName ;
95- this .profileFile = builder .profileFile ;
96- this .profileName = builder .profileName ;
101+ this .profileFile = Optional .ofNullable (builder .profileFile )
102+ .orElseGet (() -> ProfileFileSupplier .fixedProfileFile (ProfileFile .defaultProfileFile ()));
103+ this .profileName = Optional .ofNullable (builder .profileName )
104+ .orElseGet (ProfileFileSystemSetting .AWS_PROFILE ::getStringValueOrThrow );
97105
98106 this .httpCredentialsLoader = HttpCredentialsLoader .create ();
99107 this .configProvider =
100108 Ec2MetadataConfigProvider .builder ()
101- .profileFile (builder . profileFile )
102- .profileName (builder . profileName )
109+ .profileFile (profileFile )
110+ .profileName (profileName )
103111 .build ();
112+ this .ec2MetadataDisableV1Resolver = Ec2MetadataDisableV1Resolver .create (profileFile , profileName );
104113
105114 if (Boolean .TRUE .equals (builder .asyncCredentialUpdateEnabled )) {
106115 Validate .paramNotBlank (builder .asyncThreadName , "asyncThreadName" );
@@ -135,7 +144,6 @@ public static InstanceProfileCredentialsProvider create() {
135144 return builder ().build ();
136145 }
137146
138-
139147 @ Override
140148 public AwsCredentials resolveCredentials () {
141149 return credentialsCache .get ();
@@ -225,17 +233,15 @@ private String getToken(String imdsHostname) {
225233 return HttpResourcesUtils .instance ().readResource (tokenEndpoint , "PUT" );
226234 } catch (SdkServiceException e ) {
227235 if (e .statusCode () == 400 ) {
236+
228237 throw SdkClientException .builder ()
229238 .message ("Unable to fetch metadata token." )
230239 .cause (e )
231240 .build ();
232241 }
233-
234- log .debug (() -> "Ignoring non-fatal exception while attempting to load metadata token from instance profile." , e );
235- return null ;
242+ return handleTokenErrorResponse (e );
236243 } catch (Exception e ) {
237- log .debug (() -> "Ignoring non-fatal exception while attempting to load metadata token from instance profile." , e );
238- return null ;
244+ return handleTokenErrorResponse (e );
239245 }
240246 }
241247
@@ -247,6 +253,27 @@ private URI getTokenEndpoint(String imdsHostname) {
247253 return URI .create (finalHost + TOKEN_RESOURCE );
248254 }
249255
256+ private String handleTokenErrorResponse (Exception e ) {
257+ if (isInsecureFallbackDisabled ()) {
258+ String message = String .format ("Failed to retrieve IMDS token, and fallback to IMDS v1 is disabled via the "
259+ + "%s system property, %s environment variable, or %s configuration file profile"
260+ + " setting." ,
261+ SdkSystemSetting .AWS_EC2_METADATA_V1_DISABLED .environmentVariable (),
262+ SdkSystemSetting .AWS_EC2_METADATA_V1_DISABLED .property (),
263+ ProfileProperty .EC2_METADATA_V1_DISABLED );
264+ throw SdkClientException .builder ()
265+ .message (message )
266+ .cause (e )
267+ .build ();
268+ }
269+ log .debug (() -> "Ignoring non-fatal exception while attempting to load metadata token from instance profile." , e );
270+ return null ;
271+ }
272+
273+ private boolean isInsecureFallbackDisabled () {
274+ return ec2MetadataDisableV1Resolver .resolve ();
275+ }
276+
250277 private String [] getSecurityCredentials (String imdsHostname , String metadataToken ) {
251278 ResourcesEndpointProvider securityCredentialsEndpoint =
252279 new StaticResourcesEndpointProvider (URI .create (imdsHostname + SECURITY_CREDENTIALS_RESOURCE ),
0 commit comments