Skip to content

Commit fa91891

Browse files
committed
HADOOP-19066. S3A: AWS SDK V2 - Enabling FIPS should be allowed with central endpoint
1 parent 3f98cb6 commit fa91891

File tree

3 files changed

+114
-20
lines changed

3 files changed

+114
-20
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public class DefaultS3ClientFactory extends Configured
110110
*/
111111
@VisibleForTesting
112112
public static final String ERROR_ENDPOINT_WITH_FIPS =
113-
"An endpoint cannot set when " + FIPS_ENDPOINT + " is true";
113+
"Non central endpoint cannot be set when " + FIPS_ENDPOINT + " is true";
114114

115115
@Override
116116
public S3Client createS3Client(
@@ -290,10 +290,11 @@ private <BuilderT extends S3BaseClientBuilder<BuilderT, ClientT>, ClientT> void
290290
builder.fipsEnabled(fipsEnabled);
291291

292292
if (endpoint != null) {
293-
checkArgument(!fipsEnabled,
294-
"%s : %s", ERROR_ENDPOINT_WITH_FIPS, endpoint);
295293
boolean endpointEndsWithCentral =
296294
endpointStr.endsWith(CENTRAL_ENDPOINT);
295+
checkArgument(!fipsEnabled || endpointEndsWithCentral, "%s : %s",
296+
ERROR_ENDPOINT_WITH_FIPS,
297+
endpoint);
297298

298299
// No region was configured,
299300
// determine the region from the endpoint.

hadoop-tools/hadoop-aws/src/site/markdown/tools/hadoop-aws/connecting.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,18 @@ For a single bucket:
360360
</property>
361361
```
362362

363-
If this option is `true`, the endpoint option `fs.s3a.endpoint` MUST NOT be set:
363+
If `fs.s3a.endpoint.fips` is `true`, the endpoint option `fs.s3a.endpoint` MUST NOT be set to
364+
any non-central endpoint value. If `fs.s3a.endpoint.fips` is `true`, the only *optionally* allowed
365+
value for `fs.s3a.endpoint` is central endpoint `s3.amazonaws.com`.
364366

367+
S3A error message if `s3.eu-west-2.amazonaws.com` endpoint is used with FIPS:
368+
```
369+
Non central endpoint cannot be set when fs.s3a.endpoint.fips is true : https://s3.eu-west-2.amazonaws.com
370+
```
371+
372+
S3A validation is used to fail-fast before the SDK returns error.
373+
374+
AWS SDK error message if S3A does not fail-fast:
365375
```
366376
A custom endpoint cannot be combined with FIPS: https://s3.eu-west-2.amazonaws.com
367377
```
@@ -379,6 +389,9 @@ Received an UnknownHostException when attempting to interact with a service.
379389
380390
```
381391

392+
For more details on endpoint and region settings, please check
393+
[S3 endpoint and region settings in detail](connecting.html#s3_endpoint_region_details).
394+
382395
*Important* OpenSSL and FIPS endpoints
383396

384397
Linux distributions with an FIPS-compliant SSL library may not be compatible with wildfly.

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

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import static org.apache.hadoop.fs.s3a.Constants.AWS_REGION;
4949
import static org.apache.hadoop.fs.s3a.Constants.CENTRAL_ENDPOINT;
5050
import static org.apache.hadoop.fs.s3a.Constants.ENDPOINT;
51+
import static org.apache.hadoop.fs.s3a.Constants.FIPS_ENDPOINT;
5152
import static org.apache.hadoop.fs.s3a.Constants.PATH_STYLE_ACCESS;
5253
import static org.apache.hadoop.fs.s3a.DefaultS3ClientFactory.ERROR_ENDPOINT_WITH_FIPS;
5354
import static org.apache.hadoop.fs.s3a.S3ATestUtils.removeBaseAndBucketOverrides;
@@ -156,6 +157,11 @@ public void testCentralEndpoint() throws Throwable {
156157
S3Client client = createS3Client(conf, CENTRAL_ENDPOINT, null, US_EAST_2, false);
157158

158159
expectInterceptorException(client);
160+
161+
client = createS3Client(conf, CENTRAL_ENDPOINT, null,
162+
US_EAST_2, true);
163+
164+
expectInterceptorException(client);
159165
}
160166

161167
@Test
@@ -168,11 +174,21 @@ public void testCentralEndpointWithRegion() throws Throwable {
168174

169175
expectInterceptorException(client);
170176

177+
client = createS3Client(conf, CENTRAL_ENDPOINT, US_WEST_2,
178+
US_WEST_2, true);
179+
180+
expectInterceptorException(client);
181+
171182
client = createS3Client(conf, CENTRAL_ENDPOINT, US_EAST_1,
172183
US_EAST_1, false);
173184

174185
expectInterceptorException(client);
175186

187+
client = createS3Client(conf, CENTRAL_ENDPOINT, US_EAST_1,
188+
US_EAST_1, true);
189+
190+
expectInterceptorException(client);
191+
176192
}
177193

178194
@Test
@@ -203,7 +219,7 @@ public void testWithFipsAndEndpoint() throws Throwable {
203219
describe("Create a client with fips and an endpoint");
204220

205221
intercept(IllegalArgumentException.class, ERROR_ENDPOINT_WITH_FIPS, () ->
206-
createS3Client(getConfiguration(), CENTRAL_ENDPOINT, null, US_EAST_1, true));
222+
createS3Client(getConfiguration(), US_WEST_2, null, US_EAST_1, true));
207223
}
208224

209225
@Test
@@ -293,28 +309,23 @@ public void testCentralEndpointAndDifferentRegionThanBucket() throws Throwable {
293309
ENDPOINT,
294310
AWS_REGION,
295311
ALLOW_REQUESTER_PAYS,
296-
KEY_REQUESTER_PAYS_FILE);
312+
KEY_REQUESTER_PAYS_FILE,
313+
FIPS_ENDPOINT);
297314

298315
removeBaseAndBucketOverrides(
299316
DEFAULT_REQUESTER_PAYS_BUCKET_NAME,
300317
newConf,
301318
ENDPOINT,
302319
AWS_REGION,
303320
ALLOW_REQUESTER_PAYS,
304-
KEY_REQUESTER_PAYS_FILE);
321+
KEY_REQUESTER_PAYS_FILE,
322+
FIPS_ENDPOINT);
305323

306324
newConf.set(ENDPOINT, CENTRAL_ENDPOINT);
307325
newConf.set(AWS_REGION, EU_WEST_1);
308326
newConf.setBoolean(ALLOW_REQUESTER_PAYS, true);
309327

310-
Path filePath = new Path(PublicDatasetTestUtils
311-
.getRequesterPaysObject(newConf));
312-
newFS = (S3AFileSystem) filePath.getFileSystem(newConf);
313-
314-
Assertions
315-
.assertThat(newFS.exists(filePath))
316-
.describedAs("Existence of path: " + filePath)
317-
.isTrue();
328+
assertRequesterPaysFileExistence(newConf);
318329
}
319330

320331
@Test
@@ -329,23 +340,68 @@ public void testCentralEndpointAndSameRegionAsBucket() throws Throwable {
329340
ENDPOINT,
330341
AWS_REGION,
331342
ALLOW_REQUESTER_PAYS,
332-
KEY_REQUESTER_PAYS_FILE);
343+
KEY_REQUESTER_PAYS_FILE,
344+
FIPS_ENDPOINT);
333345

334346
removeBaseAndBucketOverrides(
335347
DEFAULT_REQUESTER_PAYS_BUCKET_NAME,
336348
newConf,
337349
ENDPOINT,
338350
AWS_REGION,
339351
ALLOW_REQUESTER_PAYS,
340-
KEY_REQUESTER_PAYS_FILE);
352+
KEY_REQUESTER_PAYS_FILE,
353+
FIPS_ENDPOINT);
341354

342355
newConf.set(ENDPOINT, CENTRAL_ENDPOINT);
343356
newConf.set(AWS_REGION, US_WEST_2);
344357
newConf.setBoolean(ALLOW_REQUESTER_PAYS, true);
345358

359+
assertRequesterPaysFileExistence(newConf);
360+
}
361+
362+
@Test
363+
public void testCentralEndpointAndFipsForPublicBucket() throws Throwable {
364+
describe("Access public bucket using central endpoint and region "
365+
+ "same as that of the public bucket with fips enabled");
366+
final Configuration conf = getConfiguration();
367+
final Configuration newConf = new Configuration(conf);
368+
369+
removeBaseAndBucketOverrides(
370+
newConf,
371+
ENDPOINT,
372+
AWS_REGION,
373+
ALLOW_REQUESTER_PAYS,
374+
KEY_REQUESTER_PAYS_FILE,
375+
FIPS_ENDPOINT);
376+
377+
removeBaseAndBucketOverrides(
378+
DEFAULT_REQUESTER_PAYS_BUCKET_NAME,
379+
newConf,
380+
ENDPOINT,
381+
AWS_REGION,
382+
ALLOW_REQUESTER_PAYS,
383+
KEY_REQUESTER_PAYS_FILE,
384+
FIPS_ENDPOINT);
385+
386+
newConf.set(ENDPOINT, CENTRAL_ENDPOINT);
387+
newConf.set(AWS_REGION, US_WEST_2);
388+
newConf.setBoolean(ALLOW_REQUESTER_PAYS, true);
389+
newConf.setBoolean(FIPS_ENDPOINT, true);
390+
391+
assertRequesterPaysFileExistence(newConf);
392+
}
393+
394+
/**
395+
* Assert that the file exists on the requester pays public bucket.
396+
*
397+
* @param conf the configuration object.
398+
* @throws IOException if file system operations encounter errors.
399+
*/
400+
private void assertRequesterPaysFileExistence(Configuration conf)
401+
throws IOException {
346402
Path filePath = new Path(PublicDatasetTestUtils
347-
.getRequesterPaysObject(newConf));
348-
newFS = (S3AFileSystem) filePath.getFileSystem(newConf);
403+
.getRequesterPaysObject(conf));
404+
newFS = (S3AFileSystem) filePath.getFileSystem(conf);
349405

350406
Assertions
351407
.assertThat(newFS.exists(filePath))
@@ -364,9 +420,33 @@ public void testCentralEndpointAndNullRegionWithCRUD() throws Throwable {
364420
removeBaseAndBucketOverrides(
365421
newConf,
366422
ENDPOINT,
367-
AWS_REGION);
423+
AWS_REGION,
424+
FIPS_ENDPOINT);
425+
426+
newConf.set(ENDPOINT, CENTRAL_ENDPOINT);
427+
428+
newFS = new S3AFileSystem();
429+
newFS.initialize(getFileSystem().getUri(), newConf);
430+
431+
assertOpsUsingNewFs();
432+
}
433+
434+
@Test
435+
public void testCentralEndpointAndNullRegionFipsWithCRUD() throws Throwable {
436+
describe("Access the test bucket using central endpoint and"
437+
+ " null region and fips enabled, perform file system CRUD operations");
438+
final Configuration conf = getConfiguration();
439+
440+
final Configuration newConf = new Configuration(conf);
441+
442+
removeBaseAndBucketOverrides(
443+
newConf,
444+
ENDPOINT,
445+
AWS_REGION,
446+
FIPS_ENDPOINT);
368447

369448
newConf.set(ENDPOINT, CENTRAL_ENDPOINT);
449+
newConf.setBoolean(FIPS_ENDPOINT, true);
370450

371451
newFS = new S3AFileSystem();
372452
newFS.initialize(getFileSystem().getUri(), newConf);

0 commit comments

Comments
 (0)