Skip to content

Commit 5f06f52

Browse files
authored
fix: support FIPS in endpoint heuristics (#3923)
1 parent 48e996b commit 5f06f52

File tree

11 files changed

+4450
-12
lines changed

11 files changed

+4450
-12
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "bugfix",
3+
"category": "endpoint",
4+
"description": "Support FIPS in endpoint heuristics"
5+
}

lib/region_config.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ var regionConfig = require('./region_config_data.json');
33

44
function generateRegionPrefix(region) {
55
if (!region) return null;
6+
if (isFipsRegion(region)) {
7+
if (isFipsCnRegion(region)) return 'fips-cn-*';
8+
return 'fips-*';
9+
}
610

711
var parts = region.split('-');
812
if (parts.length < 3) return null;
@@ -56,6 +60,12 @@ function configureEndpoint(service) {
5660
);
5761
}
5862

63+
// set FIPS signingRegion and endpoint.
64+
if (isFipsRegion(service.config.region)) {
65+
config = util.copy(config);
66+
service.signingRegion = getRealRegion(service.config.region);
67+
}
68+
5969
// set global endpoint
6070
service.isGlobalEndpoint = !!config.globalEndpoint;
6171
if (config.signingRegion) {
@@ -90,10 +100,33 @@ function getEndpointSuffix(region) {
90100
return defaultSuffix;
91101
}
92102

103+
function isFipsRegion(region) {
104+
return region && (region.startsWith('fips-') || region.endsWith('-fips'));
105+
}
106+
107+
function isFipsCnRegion(region) {
108+
return (
109+
region &&
110+
region.startsWith('fips-cn-') ||
111+
(region.startsWith('cn-') && region.endsWith('-fips'))
112+
);
113+
}
114+
115+
function getRealRegion(region) {
116+
return isFipsRegion(region)
117+
? ['fips-aws-global', 'aws-fips'].includes(region)
118+
? 'us-east-1'
119+
: region === 'fips-aws-us-gov-global'
120+
? 'us-gov-west-1'
121+
: region.replace(/fips-(dkr-|prod-)?|-fips/, '')
122+
: region;
123+
}
124+
93125
/**
94126
* @api private
95127
*/
96128
module.exports = {
97129
configureEndpoint: configureEndpoint,
98-
getEndpointSuffix: getEndpointSuffix
130+
getEndpointSuffix: getEndpointSuffix,
131+
getRealRegion: getRealRegion,
99132
};

lib/region_config_data.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
"*/*": {
44
"endpoint": "{service}.{region}.amazonaws.com"
55
},
6+
"fips-*/*": {
7+
"endpoint": "{service}-fips.{region}.amazonaws.com"
8+
},
9+
"fips-cn-*/*": {
10+
"endpoint": "{service}-fips.{region}.amazonaws.com.cn"
11+
},
612
"cn-*/*": {
713
"endpoint": "{service}.{region}.amazonaws.com.cn"
814
},
@@ -61,6 +67,91 @@
6167
"*/sdb": {
6268
"endpoint": "{service}.{region}.amazonaws.com",
6369
"signatureVersion": "v2"
70+
},
71+
72+
"fips-*/api.ecr": {
73+
"endpoint": "ecr-fips.{region}.amazonaws.com"
74+
},
75+
"fips-*/api.sagemaker": {
76+
"endpoint": "api-fips.sagemaker.{region}.amazonaws.com"
77+
},
78+
"fips-*/batch": {
79+
"endpoint": "fips.batch.{region}.amazonaws.com"
80+
},
81+
"fips-*/streams.dynamodb": {
82+
"endpoint": "dynamodb-fips.{region}.amazonaws.com"
83+
},
84+
"fips-*/route53": {
85+
"endpoint": "route53-fips.amazonaws.com"
86+
},
87+
"fips-*/transcribe": {
88+
"endpoint": "fips.transcribe.{region}.amazonaws.com"
89+
},
90+
"fips-*/waf": {
91+
"endpoint": "waf-fips.amazonaws.com"
92+
},
93+
"fips-us-gov-east-1/acm-pca": {
94+
"endpoint": "acm-pca.{region}.amazonaws.com"
95+
},
96+
"fips-us-gov-west-1/acm-pca": {
97+
"endpoint": "acm-pca.{region}.amazonaws.com"
98+
},
99+
"fips-us-gov-east-1/batch": {
100+
"endpoint": "batch.{region}.amazonaws.com"
101+
},
102+
"fips-us-gov-west-1/batch": {
103+
"endpoint": "batch.{region}.amazonaws.com"
104+
},
105+
"us-gov-east-1-fips/dynamodb": {
106+
"endpoint": "dynamodb.{region}.amazonaws.com"
107+
},
108+
"us-gov-west-1-fips/dynamodb": {
109+
"endpoint": "dynamodb.{region}.amazonaws.com"
110+
},
111+
"fips-us-gov-east-1/elasticloadbalancing": {
112+
"endpoint": "elasticloadbalancing.{region}.amazonaws.com"
113+
},
114+
"fips-us-gov-west-1/elasticloadbalancing": {
115+
"endpoint": "elasticloadbalancing.{region}.amazonaws.com"
116+
},
117+
"us-gov-east-1-fips/guardduty": {
118+
"endpoint": "guardduty.{region}.amazonaws.com"
119+
},
120+
"us-gov-west-1-fips/guardduty": {
121+
"endpoint": "guardduty.{region}.amazonaws.com"
122+
},
123+
"fips-us-gov-east-1/monitoring": {
124+
"endpoint": "monitoring.{region}.amazonaws.com"
125+
},
126+
"fips-us-gov-west-1/monitoring": {
127+
"endpoint": "monitoring.{region}.amazonaws.com"
128+
},
129+
"fips-aws-us-gov-global/organizations": {
130+
"endpoint": "organizations.{region}.amazonaws.com"
131+
},
132+
"fips-us-gov-east-1/resource-groups": {
133+
"endpoint": "resource-groups.{region}.amazonaws.com"
134+
},
135+
"fips-us-gov-west-1/resource-groups": {
136+
"endpoint": "resource-groups.{region}.amazonaws.com"
137+
},
138+
"fips-aws-us-gov-global/route53": {
139+
"endpoint": "route53.us-gov.amazonaws.com"
140+
},
141+
"fips-us-gov-east-1/servicecatalog-appregistry": {
142+
"endpoint": "servicecatalog-appregistry.{region}.amazonaws.com"
143+
},
144+
"fips-us-gov-west-1/servicecatalog-appregistry": {
145+
"endpoint": "servicecatalog-appregistry.{region}.amazonaws.com"
146+
},
147+
"fips-us-gov-west-1/states": {
148+
"endpoint": "states.{region}.amazonaws.com"
149+
},
150+
"us-gov-east-1-fips/streams.dynamodb": {
151+
"endpoint": "dynamodb.{region}.amazonaws.com"
152+
},
153+
"us-gov-west-1-fips/streams.dynamodb": {
154+
"endpoint": "dynamodb.{region}.amazonaws.com"
64155
}
65156
},
66157

lib/request.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,10 @@ AWS.Request = inherit({
313313
var region = service.config.region;
314314
var customUserAgent = service.config.customUserAgent;
315315

316-
if (service.isGlobalEndpoint) {
317-
if (service.signingRegion) {
318-
region = service.signingRegion;
319-
} else {
320-
region = 'us-east-1';
321-
}
316+
if (service.signingRegion) {
317+
region = service.signingRegion;
318+
} else if (service.isGlobalEndpoint) {
319+
region = 'us-east-1';
322320
}
323321

324322
this.domain = domain && domain.active;

lib/service.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ AWS.Service = inherit({
636636

637637
var e = endpoint;
638638
e = e.replace(/\{service\}/g, this.api.endpointPrefix);
639-
e = e.replace(/\{region\}/g, this.config.region);
639+
e = e.replace(/\{region\}/g, regionConfig.getRealRegion(this.config.region));
640640
e = e.replace(/\{scheme\}/g, this.config.sslEnabled ? 'https' : 'http');
641641
return e;
642642
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"url": "https://aws.amazon.com/"
99
},
1010
"config": {
11-
"test_args": "test test/json test/model test/protocol test/query test/services test/signers test/xml test/s3 test/cloudfront test/dynamodb test/polly test/rds test/publisher test/event-stream"
11+
"test_args": "test test/json test/model test/protocol test/query test/services test/signers test/xml test/s3 test/cloudfront test/dynamodb test/polly test/rds test/publisher test/event-stream test/endpoint"
1212
},
1313
"homepage": "https://github.com/aws/aws-sdk-js",
1414
"contributors": [

scripts/region-checker/allowlist.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ var allowlist = {
2727
110,
2828
112
2929
],
30+
'/region_config.js': [
31+
117
32+
],
3033
'/request.js': [
34+
318,
3135
319
3236
],
3337
'/services/s3.js': [

test/endpoint/fips/fips.spec.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const test_cases = require('./test_cases.json');
2+
const helpers = require('../../helpers');
3+
const AWS = helpers.AWS;
4+
5+
async function testApiCall(input) {
6+
const { clientName, region, signingRegion, hostname } = input;
7+
8+
if (!AWS[clientName]) {
9+
throw new Error(`${clientName} does not exist`);
10+
}
11+
12+
const client =
13+
clientName === 'IotData'
14+
? // requires an explicit `endpoint' configuration option.
15+
new AWS.IotData({ region, endpoint: 'endpoint' })
16+
: new AWS[clientName]({ region });
17+
18+
const req = client[Object.keys(client.api.operations)[0]]();
19+
req.on('complete', () => {
20+
expect(region).to.equal(client.config.region);
21+
expect(signingRegion).to.equal(req.httpRequest.region);
22+
expect(hostname).to.equal(req.httpRequest.endpoint.host);
23+
});
24+
25+
try {
26+
await req.promise();
27+
} catch (error) {}
28+
};
29+
30+
describe('endpoints.fips', function() {
31+
beforeEach(function () {
32+
helpers.mockResponse({
33+
data: {}
34+
});
35+
});
36+
37+
for (const test_case of test_cases) {
38+
it(`testing ${test_case.clientName} with region: ${test_case.region}`, async function() {
39+
await testApiCall(test_case);
40+
});
41+
}
42+
});

0 commit comments

Comments
 (0)