31
31
import software .amazon .awssdk .annotations .SdkPublicApi ;
32
32
import software .amazon .awssdk .annotations .SdkTestInternalApi ;
33
33
import software .amazon .awssdk .auth .credentials .internal .Ec2MetadataConfigProvider ;
34
+ import software .amazon .awssdk .auth .credentials .internal .Ec2MetadataDisableV1Resolver ;
34
35
import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader ;
35
36
import software .amazon .awssdk .auth .credentials .internal .HttpCredentialsLoader .LoadedCredentials ;
36
37
import software .amazon .awssdk .auth .credentials .internal .StaticResourcesEndpointProvider ;
40
41
import software .amazon .awssdk .profiles .ProfileFile ;
41
42
import software .amazon .awssdk .profiles .ProfileFileSupplier ;
42
43
import software .amazon .awssdk .profiles .ProfileFileSystemSetting ;
44
+ import software .amazon .awssdk .profiles .ProfileProperty ;
43
45
import software .amazon .awssdk .regions .util .HttpResourcesUtils ;
44
46
import software .amazon .awssdk .regions .util .ResourcesEndpointProvider ;
45
47
import software .amazon .awssdk .utils .Logger ;
53
55
54
56
/**
55
57
* Credentials provider implementation that loads credentials from the Amazon EC2 Instance Metadata Service.
56
- *
57
- * <P>
58
+ * <p>
58
59
* If {@link SdkSystemSetting#AWS_EC2_METADATA_DISABLED} is set to true, it will not try to load
59
60
* 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.
60
65
*/
61
66
@ SdkPublicApi
62
67
public final class InstanceProfileCredentialsProvider
@@ -73,6 +78,7 @@ public final class InstanceProfileCredentialsProvider
73
78
private final Clock clock ;
74
79
private final String endpoint ;
75
80
private final Ec2MetadataConfigProvider configProvider ;
81
+ private final Ec2MetadataDisableV1Resolver ec2MetadataDisableV1Resolver ;
76
82
private final HttpCredentialsLoader httpCredentialsLoader ;
77
83
private final CachedSupplier <AwsCredentials > credentialsCache ;
78
84
@@ -92,15 +98,18 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) {
92
98
this .endpoint = builder .endpoint ;
93
99
this .asyncCredentialUpdateEnabled = builder .asyncCredentialUpdateEnabled ;
94
100
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 );
97
105
98
106
this .httpCredentialsLoader = HttpCredentialsLoader .create ();
99
107
this .configProvider =
100
108
Ec2MetadataConfigProvider .builder ()
101
- .profileFile (builder . profileFile )
102
- .profileName (builder . profileName )
109
+ .profileFile (profileFile )
110
+ .profileName (profileName )
103
111
.build ();
112
+ this .ec2MetadataDisableV1Resolver = Ec2MetadataDisableV1Resolver .create (profileFile , profileName );
104
113
105
114
if (Boolean .TRUE .equals (builder .asyncCredentialUpdateEnabled )) {
106
115
Validate .paramNotBlank (builder .asyncThreadName , "asyncThreadName" );
@@ -135,7 +144,6 @@ public static InstanceProfileCredentialsProvider create() {
135
144
return builder ().build ();
136
145
}
137
146
138
-
139
147
@ Override
140
148
public AwsCredentials resolveCredentials () {
141
149
return credentialsCache .get ();
@@ -225,17 +233,15 @@ private String getToken(String imdsHostname) {
225
233
return HttpResourcesUtils .instance ().readResource (tokenEndpoint , "PUT" );
226
234
} catch (SdkServiceException e ) {
227
235
if (e .statusCode () == 400 ) {
236
+
228
237
throw SdkClientException .builder ()
229
238
.message ("Unable to fetch metadata token." )
230
239
.cause (e )
231
240
.build ();
232
241
}
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 );
236
243
} 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 );
239
245
}
240
246
}
241
247
@@ -247,6 +253,27 @@ private URI getTokenEndpoint(String imdsHostname) {
247
253
return URI .create (finalHost + TOKEN_RESOURCE );
248
254
}
249
255
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
+
250
277
private String [] getSecurityCredentials (String imdsHostname , String metadataToken ) {
251
278
ResourcesEndpointProvider securityCredentialsEndpoint =
252
279
new StaticResourcesEndpointProvider (URI .create (imdsHostname + SECURITY_CREDENTIALS_RESOURCE ),
0 commit comments