Skip to content

Commit c2caf31

Browse files
HADOOP-19181. S3A: IAMCredentialsProvider throttling results in auth failures (#8118)
Hard-code a 15 minute advance time for credential renewal, so even if a large number of processes simultaneously trying to renew their tokens through IAM requests may trigger throttling, the asynchronous refresh thread has minutes of backoff and retry before the existing credentials become invalid. + Add a test case to explicitly instantiate the class and ask for credentials doesn't care about whether credentials are returned (EC2 runs) or if NoAwsCredentialsException is returned -any other exception is raised as a failure. + Make test suite subclass of HadoopTestBase to avoid instantiating s3a fs. Contains HADOOP-19748: S3A: ITestAssumeRole tests failing now STS returns detailed error messages Contributed by Steve Loughran
1 parent 8602fe7 commit c2caf31

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/auth/IAMInstanceCredentialsProvider.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.io.Closeable;
2222
import java.io.IOException;
23+
import java.time.Duration;
2324

2425
import org.slf4j.Logger;
2526
import org.slf4j.LoggerFactory;
@@ -62,6 +63,12 @@ public class IAMInstanceCredentialsProvider
6263
private static final Logger LOG =
6364
LoggerFactory.getLogger(IAMInstanceCredentialsProvider.class);
6465

66+
/**
67+
* How far in advance of credential expiry must IAM credentials be refreshed.
68+
* See HADOOP-19181. S3A: IAMCredentialsProvider throttling results in AWS auth failures
69+
*/
70+
public static final Duration TIME_BEFORE_EXPIRY = Duration.ofMinutes(5);
71+
6572
/**
6673
* The credentials provider.
6774
* Initially a container credentials provider, but if that fails
@@ -130,8 +137,12 @@ private synchronized AwsCredentials getCredentials() {
130137
// close it to shut down any thread
131138
iamCredentialsProvider.close();
132139
isContainerCredentialsProvider = false;
140+
141+
// create an async credentials provider with a safe credential
142+
// expiry time.
133143
iamCredentialsProvider = InstanceProfileCredentialsProvider.builder()
134144
.asyncCredentialUpdateEnabled(true)
145+
.staleTime(TIME_BEFORE_EXPIRY)
135146
.build();
136147
return iamCredentialsProvider.resolveCredentials();
137148
} else {

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/TestS3AAWSCredentialsProvider.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@
5555
import org.apache.hadoop.fs.s3a.auth.CredentialProviderListFactory;
5656
import org.apache.hadoop.fs.s3a.auth.IAMInstanceCredentialsProvider;
5757
import org.apache.hadoop.fs.s3a.auth.NoAuthWithAWSException;
58+
import org.apache.hadoop.fs.s3a.auth.NoAwsCredentialsException;
5859
import org.apache.hadoop.fs.s3a.auth.ProfileAWSCredentialsProvider;
5960
import org.apache.hadoop.fs.s3a.auth.delegation.CountInvocationsProvider;
6061
import org.apache.hadoop.fs.s3a.impl.InstantiationIOException;
6162
import org.apache.hadoop.fs.s3a.test.PublicDatasetTestUtils;
6263
import org.apache.hadoop.io.retry.RetryPolicy;
64+
import org.apache.hadoop.test.HadoopTestBase;
6365
import org.apache.hadoop.util.Sets;
6466

6567
import static org.apache.hadoop.fs.s3a.Constants.ASSUMED_ROLE_CREDENTIALS_PROVIDER;
@@ -79,7 +81,7 @@
7981
/**
8082
* Unit tests for {@link Constants#AWS_CREDENTIALS_PROVIDER} logic.
8183
*/
82-
public class TestS3AAWSCredentialsProvider extends AbstractS3ATestBase {
84+
public class TestS3AAWSCredentialsProvider extends HadoopTestBase {
8385

8486
/**
8587
* URI of the test file: this must be anonymously accessible.
@@ -921,4 +923,19 @@ public static AwsCredentialsProvider create() throws ClassNotFoundException {
921923
}
922924
}
923925

926+
@Test
927+
public void testIAMInstanceCredentialsProvider() throws Throwable {
928+
929+
final Configuration conf =
930+
createProviderConfiguration(IAMInstanceCredentialsProvider.class);
931+
Path testFile = getExternalData(conf);
932+
try (AWSCredentialProviderList list = createAWSCredentialProviderList(testFile.toUri(), conf)) {
933+
try {
934+
list.resolveCredentials();
935+
} catch (NoAwsCredentialsException e) {
936+
/// this is OK.
937+
}
938+
939+
}
940+
}
924941
}

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/auth/ITestAssumeRole.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public class ITestAssumeRole extends AbstractS3ATestBase {
102102
private static final Statement STATEMENT_ALL_BUCKET_READ_ACCESS
103103
= statement(true, S3_ALL_BUCKETS, S3_BUCKET_READ_OPERATIONS);
104104

105+
public static final String MALFORMED_POLICY_DOCUMENT = "MalformedPolicyDocument";
106+
105107
/**
106108
* test URI, built in setup.
107109
*/
@@ -244,13 +246,13 @@ public void testAssumeRoleNoARN() throws Exception {
244246

245247
@Test
246248
public void testAssumeRoleFSBadPolicy() throws Exception {
247-
describe("Attemnpt to create the FS with malformed JSON");
249+
describe("Attempt to create the FS with malformed JSON");
248250
Configuration conf = createAssumedRoleConfig();
249251
// add some malformed JSON
250252
conf.set(ASSUMED_ROLE_POLICY, "}");
251253
expectFileSystemCreateFailure(conf,
252254
AWSBadRequestException.class,
253-
"JSON");
255+
MALFORMED_POLICY_DOCUMENT);
254256
}
255257

256258
@Test
@@ -261,7 +263,7 @@ public void testAssumeRoleFSBadPolicy2() throws Exception {
261263
conf.set(ASSUMED_ROLE_POLICY, "{'json':'but not what AWS wants}");
262264
expectFileSystemCreateFailure(conf,
263265
AWSBadRequestException.class,
264-
"Syntax errors in policy");
266+
MALFORMED_POLICY_DOCUMENT);
265267
}
266268

267269
@Test

0 commit comments

Comments
 (0)