Skip to content

Commit 9e1ce1b

Browse files
committed
Fixed an issue where we were refreshing IMDS too aggressively.
1 parent 5a14498 commit 9e1ce1b

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package software.amazon.awssdk.auth.credentials;
1717

1818
import static java.time.temporal.ChronoUnit.MINUTES;
19-
import static software.amazon.awssdk.utils.ComparableUtils.minimum;
19+
import static software.amazon.awssdk.utils.ComparableUtils.maximum;
2020

2121
import java.io.IOException;
2222
import java.net.URI;
@@ -191,7 +191,7 @@ private Instant prefetchTime(Instant expiration) {
191191
return now.plus(5, MINUTES);
192192
}
193193

194-
return now.plus(minimum(timeUntilExpiration.abs().dividedBy(2), Duration.ofMinutes(5)));
194+
return now.plus(maximum(timeUntilExpiration.abs().dividedBy(2), Duration.ofMinutes(5)));
195195
}
196196

197197
@Override

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.time.Instant;
4242
import java.time.ZoneId;
4343
import java.time.ZoneOffset;
44+
import java.time.temporal.ChronoUnit;
4445
import org.junit.AfterClass;
4546
import org.junit.Before;
4647
import org.junit.Rule;
@@ -377,6 +378,42 @@ public void resolveCredentials_callsImdsIfCredentialsWithin5MinutesOfExpiration(
377378
assertThat(credentials10SecondsAgo.secretAccessKey()).isEqualTo("SECRET_ACCESS_KEY2");
378379
}
379380

381+
@Test
382+
public void imdsCallFrequencyIsLimited() {
383+
// Requires running the test multiple times to account for refresh jitter
384+
for (int i = 0; i < 10; i++) {
385+
AdjustableClock clock = new AdjustableClock();
386+
AwsCredentialsProvider credentialsProvider = credentialsProviderWithClock(clock);
387+
Instant now = Instant.now();
388+
String successfulCredentialsResponse1 =
389+
"{"
390+
+ "\"AccessKeyId\":\"ACCESS_KEY_ID\","
391+
+ "\"SecretAccessKey\":\"SECRET_ACCESS_KEY\","
392+
+ "\"Expiration\":\"" + DateUtils.formatIso8601Date(now) + '"'
393+
+ "}";
394+
395+
String successfulCredentialsResponse2 =
396+
"{"
397+
+ "\"AccessKeyId\":\"ACCESS_KEY_ID2\","
398+
+ "\"SecretAccessKey\":\"SECRET_ACCESS_KEY2\","
399+
+ "\"Expiration\":\"" + DateUtils.formatIso8601Date(now.plus(6, HOURS)) + '"'
400+
+ "}";
401+
402+
// Set the time to 5 minutes before expiration and call IMDS
403+
clock.time = now.minus(5, MINUTES);
404+
stubCredentialsResponse(aResponse().withBody(successfulCredentialsResponse1));
405+
AwsCredentials credentials5MinutesAgo = credentialsProvider.resolveCredentials();
406+
407+
// Set the time to 1 second before expiration, and verify that do not call IMDS because it hasn't been 5 minutes yet
408+
clock.time = now.minus(1, SECONDS);
409+
stubCredentialsResponse(aResponse().withBody(successfulCredentialsResponse2));
410+
AwsCredentials credentials1SecondsAgo = credentialsProvider.resolveCredentials();
411+
412+
assertThat(credentials5MinutesAgo).isEqualTo(credentials1SecondsAgo);
413+
assertThat(credentials5MinutesAgo.secretAccessKey()).isEqualTo("SECRET_ACCESS_KEY");
414+
}
415+
}
416+
380417
private AwsCredentialsProvider credentialsProviderWithClock(Clock clock) {
381418
InstanceProfileCredentialsProvider.BuilderImpl builder =
382419
(InstanceProfileCredentialsProvider.BuilderImpl) InstanceProfileCredentialsProvider.builder();

utils/src/main/java/software/amazon/awssdk/utils/ComparableUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,15 @@ public static <T extends Comparable<T>> T minimum(T... values) {
5757
return values == null ? null : Stream.of(values).min(Comparable::compareTo).orElse(null);
5858
}
5959

60+
/**
61+
* Get the maximum value from a list of comparable vales.
62+
*
63+
* @param values The values from which the maximum should be extracted.
64+
* @return The maximum value in the list.
65+
*/
66+
@SafeVarargs
67+
public static <T extends Comparable<T>> T maximum(T... values) {
68+
return values == null ? null : Stream.of(values).max(Comparable::compareTo).orElse(null);
69+
}
70+
6071
}

0 commit comments

Comments
 (0)