Skip to content

Commit aa4bab5

Browse files
committed
Add Ec2 metadata disabling support via profile configuration
1 parent 00d1c90 commit aa4bab5

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
/**
5656
* Credentials provider implementation that loads credentials from the Amazon EC2 Instance Metadata Service.
5757
* <p>
58-
* If {@link SdkSystemSetting#AWS_EC2_METADATA_DISABLED} is set to true, it will not try to load
58+
* If {@link SdkSystemSetting#AWS_EC2_METADATA_DISABLED} is set to true, or if the configuration file parameter
59+
* {@link ProfileProperty#EC2_METADATA_DISABLED} is set to true, it will not try to load
5960
* credentials from EC2 metadata service and will return null.
6061
* <p>
6162
* If {@link SdkSystemSetting#AWS_EC2_METADATA_V1_DISABLED} or {@link ProfileProperty#EC2_METADATA_V1_DISABLED}
@@ -152,7 +153,8 @@ public AwsCredentials resolveCredentials() {
152153

153154
private RefreshResult<AwsCredentials> refreshCredentials() {
154155
if (isLocalCredentialLoadingDisabled()) {
155-
throw SdkClientException.create("IMDS credentials have been disabled by environment variable or system property.");
156+
throw SdkClientException.create("IMDS credentials have been disabled by environment variable, system property, "
157+
+ "or configuration file profile setting.");
156158
}
157159

158160
try {
@@ -170,7 +172,7 @@ private RefreshResult<AwsCredentials> refreshCredentials() {
170172
}
171173

172174
private boolean isLocalCredentialLoadingDisabled() {
173-
return SdkSystemSetting.AWS_EC2_METADATA_DISABLED.getBooleanValueOrThrow();
175+
return SdkSystemSetting.AWS_EC2_METADATA_DISABLED.getBooleanValueOrThrow() || configProvider.isMetadataDisabled();
174176
}
175177

176178
private Instant staleTime(Instant expiration) {

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/Ec2MetadataConfigProvider.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@ public final class Ec2MetadataConfigProvider {
4545
private final String profileName;
4646

4747
private final Lazy<Boolean> metadataV1Disabled;
48+
private final Lazy<Boolean> metadataDisabled;
4849
private final Lazy<Long> serviceTimeout;
4950

5051
private Ec2MetadataConfigProvider(Builder builder) {
5152
this.profileFile = builder.profileFile;
5253
this.profileName = builder.profileName;
5354
this.metadataV1Disabled = new Lazy<>(this::resolveMetadataV1Disabled);
55+
this.metadataDisabled = new Lazy<>(this::resolveMetadataDisabled);
5456
this.serviceTimeout = new Lazy<>(this::resolveServiceTimeout);
5557
}
5658

@@ -120,6 +122,14 @@ public boolean isMetadataV1Disabled() {
120122
return metadataV1Disabled.getValue();
121123
}
122124

125+
/**
126+
* Resolves whether EC2 Metadata is disabled.
127+
* @return true if EC2 Metadata is disabled, false otherwise.
128+
*/
129+
public boolean isMetadataDisabled() {
130+
return metadataDisabled.getValue();
131+
}
132+
123133
/**
124134
* Resolves the EC2 Metadata Service Timeout in milliseconds.
125135
* @return the timeout value in milliseconds.
@@ -137,6 +147,12 @@ private boolean resolveMetadataV1Disabled() {
137147
.orElse(false);
138148
}
139149

150+
// Internal resolution logic for Metadata disabled
151+
private boolean resolveMetadataDisabled() {
152+
return fromProfileFileMetadataDisabled(profileFile, profileName)
153+
.orElse(false);
154+
}
155+
140156
// Internal resolution logic for Service Timeout
141157
private long resolveServiceTimeout() {
142158
return OptionalUtils.firstPresent(
@@ -158,6 +174,15 @@ private static Optional<Boolean> fromProfileFileMetadataV1Disabled(Supplier<Prof
158174
.flatMap(p -> p.booleanProperty(ProfileProperty.EC2_METADATA_V1_DISABLED));
159175
}
160176

177+
// Profile file resolution for Metadata disabled
178+
private static Optional<Boolean> fromProfileFileMetadataDisabled(Supplier<ProfileFile> profileFile, String profileName) {
179+
Optional<Profile> profile = profileFile.get().profile(profileName);
180+
if (profile.isPresent()) {
181+
return profile.get().booleanProperty(ProfileProperty.EC2_METADATA_DISABLED);
182+
}
183+
return Optional.empty();
184+
}
185+
161186
// System settings resolution for Service Timeout
162187
private static Optional<Long> fromSystemSettingsServiceTimeout() {
163188
return SdkSystemSetting.AWS_METADATA_SERVICE_TIMEOUT.getNonDefaultStringValue()

core/auth/src/test/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProviderTest.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,12 +319,49 @@ void resolveCredentials_metadataLookupDisabled_throws() {
319319
try {
320320
assertThatThrownBy(() -> InstanceProfileCredentialsProvider.builder().build().resolveCredentials())
321321
.isInstanceOf(SdkClientException.class)
322-
.hasMessage("IMDS credentials have been disabled by environment variable or system property.");
322+
.hasMessage("IMDS credentials have been disabled by environment variable, system property, or configuration file profile setting.");
323323
} finally {
324324
System.clearProperty(SdkSystemSetting.AWS_EC2_METADATA_DISABLED.property());
325325
}
326326
}
327327

328+
@Test
329+
void resolveCredentials_metadataDisabledThroughConfig_throwsException() {
330+
stubSecureCredentialsResponse(aResponse().withBody(STUB_CREDENTIALS));
331+
try {
332+
InstanceProfileCredentialsProvider.builder()
333+
.profileFile(configFile("profile test", Pair.of("disable_ec2_metadata", "true")))
334+
.profileName("test")
335+
.build()
336+
.resolveCredentials();
337+
ProfileFile config = configFile("profile test", Pair.of("disable_ec2_metadata", "true"));
338+
System.out.println("Test config file: " + config.toString());
339+
} catch (Exception e) {
340+
assertThat(e).isInstanceOf(SdkClientException.class);
341+
assertThat(e).hasMessage("IMDS credentials have been disabled by environment variable, system property, or configuration file profile setting.");
342+
}
343+
344+
// Verify that no calls were made to the IMDS endpoints
345+
WireMock.verify(0, putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)));
346+
WireMock.verify(0, getRequestedFor(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH)));
347+
}
348+
349+
@Test
350+
void resolveCredentials_metadataEnabledThroughConfig_returnsCredentials() {
351+
stubSecureCredentialsResponse(aResponse().withBody(STUB_CREDENTIALS));
352+
353+
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder()
354+
.profileFile(configFile("profile test", Pair.of("disable_ec2_metadata", "false")))
355+
.profileName("test")
356+
.build();
357+
358+
AwsCredentials credentials = provider.resolveCredentials();
359+
assertThat(credentials.accessKeyId()).isEqualTo("ACCESS_KEY_ID");
360+
assertThat(credentials.secretAccessKey()).isEqualTo("SECRET_ACCESS_KEY");
361+
362+
verifyImdsCallWithToken();
363+
}
364+
328365
@Test
329366
void resolveCredentials_customProfileFileAndName_usesCorrectEndpoint() {
330367
WireMockServer mockMetadataEndpoint_2 = new WireMockServer(WireMockConfiguration.options().dynamicPort());

core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileProperty.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ public final class ProfileProperty {
161161

162162
public static final String EC2_METADATA_V1_DISABLED = "ec2_metadata_v1_disabled";
163163

164+
/**
165+
* Disables the use of the Amazon EC2 instance metadata service (IMDS). When set to "true", SDK will not try to load
166+
* credentials from EC2 metadata service and will return null.
167+
*/
168+
public static final String EC2_METADATA_DISABLED = "disable_ec2_metadata";
169+
164170
public static final String METADATA_SERVICE_TIMEOUT = "metadata_service_timeout";
165171

166172
/**

0 commit comments

Comments
 (0)