diff --git a/CHANGELOG.md b/CHANGELOG.md index daac6ae1..708a1448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [4.1.1] - 2020-05-25 + +### Changed +- Fix support for TLS 1.0 regional domains which were broken in the 4.0.0 release. Discovered by @jufemaiz ([#348](https://github.com/amplify-education/serverless-domain-manager/pull/348)) + ## [4.1.0] - 2020-05-18 ### Changed @@ -16,6 +21,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [4.0.0] - 2020-05-06 +### Breaking Changes +- Regional domains with TLS 1.0 no longer work. Fixed in 4.1.1 + ### Added - Add support for WebSocket and HTTP APIs. A domain name can be created for each API type (Rest, WebSocket, HTTP) for up to 3 domain names in a single Serverless config. Thanks @TehNrd ([#319](https://github.com/amplify-education/serverless-domain-manager/pull/319)) diff --git a/package-lock.json b/package-lock.json index c6d49e44..c2947526 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "serverless-domain-manager", - "version": "4.0.1", + "version": "4.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e0b49ae3..76e1aaf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless-domain-manager", - "version": "4.1.0", + "version": "4.1.1", "engines": { "node": ">=4.0" }, diff --git a/src/index.ts b/src/index.ts index d4e5802e..5e3d2854 100644 --- a/src/index.ts +++ b/src/index.ts @@ -152,14 +152,14 @@ class ServerlessCustomDomain { domain.apiMapping = await this.getBasePathMapping(domain); + await this.getDomainInfo(); + if (!domain.apiMapping) { await this.createBasePathMapping(domain); } else { await this.updateBasePathMapping(domain); } - await this.getDomainInfo(); - } catch (err) { this.logIfDebug(err, domain.givenDomainName); throw new Error(`Error: Unable to setup base domain mappings for ${domain.givenDomainName}`); @@ -390,11 +390,10 @@ class ServerlessCustomDomain { let createdDomain = {}; - // For EDGE domain name, create with APIGateway (v1) - if (domain.endpointType === Globals.endpointTypes.edge) { + // For EDGE domain name or TLS 1.0, create with APIGateway (v1) + if (domain.endpointType === Globals.endpointTypes.edge || domain.securityPolicy === "TLS_1_0") { // Set up parameters const params = { - certificateArn: domain.certificateArn, domainName: domain.givenDomainName, endpointConfiguration: { types: [domain.endpointType], @@ -402,6 +401,14 @@ class ServerlessCustomDomain { securityPolicy: domain.securityPolicy, }; + /* tslint:disable:no-string-literal */ + if (domain.endpointType === Globals.endpointTypes.edge) { + params["certificateArn"] = domain.certificateArn; + } else { + params["regionalCertificateArn"] = domain.certificateArn; + } + /* tslint:enable:no-string-literal */ + // Make API call to create domain try { // Creating EDGE domain so use APIGateway (v1) service @@ -581,8 +588,8 @@ class ServerlessCustomDomain { * Creates basepath mapping */ public async createBasePathMapping(domain: DomainConfig): Promise { - // Use APIGateway (v1) for EDGE domains - if (domain.endpointType === Globals.endpointTypes.edge) { + // Use APIGateway (v1) for EDGE or TLS 1.0 domains + if (domain.endpointType === Globals.endpointTypes.edge || domain.securityPolicy === "TLS_1_0") { const params = { basePath: domain.basePath, domainName: domain.givenDomainName, @@ -620,8 +627,11 @@ class ServerlessCustomDomain { * Updates basepath mapping */ public async updateBasePathMapping(domain: DomainConfig): Promise { - // Use APIGateway (v1) for EDGE domains - if (domain.endpointType === Globals.endpointTypes.edge) { + // Use APIGateway (v1) for EDGE or TLS 1.0 domains + // check here if the EXISTING domain is using TLS 1.0 regardless of what is configured + // We don't support updating custom domains so switching from TLS 1.0 to 1.2 will require recreating + // the domain + if (domain.endpointType === Globals.endpointTypes.edge || domain.domainInfo.securityPolicy === "TLS_1_0") { const params = { basePath: domain.apiMapping.ApiMappingKey || "(none)", domainName: domain.givenDomainName, diff --git a/test/integration-tests/integration.test.ts b/test/integration-tests/integration.test.ts index 65e5f33d..0ee9b7e7 100644 --- a/test/integration-tests/integration.test.ts +++ b/test/integration-tests/integration.test.ts @@ -86,6 +86,14 @@ const testCases = [ testFolder: "http-api", testStage: "$default", }, + { + testBasePath: "(none)", + testDescription: "Deploy regional domain with TLS 1.0", + testDomain: `regional-tls-1-0-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: "regional-tls-1-0", + testStage: "dev", + }, ]; describe("Integration Tests", function() { diff --git a/test/integration-tests/regional-tls-1-0/handler.js b/test/integration-tests/regional-tls-1-0/handler.js new file mode 100644 index 00000000..1bd222d6 --- /dev/null +++ b/test/integration-tests/regional-tls-1-0/handler.js @@ -0,0 +1,16 @@ +"use strict"; + +module.exports.helloWorld = (event, context, callback) => { + const response = { + statusCode: 200, + headers: { + "Access-Control-Allow-Origin": "*", // Required for CORS support to work + }, + body: JSON.stringify({ + message: "Go Serverless v1.0! Your function executed successfully!", + input: event, + }), + }; + + callback(null, response); +}; diff --git a/test/integration-tests/regional-tls-1-0/serverless.yml b/test/integration-tests/regional-tls-1-0/serverless.yml new file mode 100644 index 00000000..fc1219d3 --- /dev/null +++ b/test/integration-tests/regional-tls-1-0/serverless.yml @@ -0,0 +1,28 @@ +# Test regional domains with TLS 1.0 +service: regional-tls-1-0-${opt:RANDOM_STRING} +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: dev + endpointType: regional + +functions: + helloWorld: + handler: handler.helloWorld + events: + - http: + path: hello-world + method: get + cors: true +plugins: + - serverless-domain-manager +custom: + customDomain: + domainName: regional-tls-1-0-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + securityPolicy: tls_1_0 + endpointType: regional + +package: + exclude: + - node_modules/** diff --git a/test/unit-tests/index.test.ts b/test/unit-tests/index.test.ts index 6c34e4a1..34133b21 100644 --- a/test/unit-tests/index.test.ts +++ b/test/unit-tests/index.test.ts @@ -189,6 +189,61 @@ describe("Custom Domain Plugin", () => { }); }); + it("Creates basepath mapping for regional tls 1.0 REST api", async () => { + AWS.mock("APIGateway", "createBasePathMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + securityPolicy: "tls_1_0", + }); + plugin.initializeVariables(); + plugin.apigateway = new aws.APIGateway(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); + + await plugin.createBasePathMapping(dc); + + expect(spy).to.have.been.called.with({ + basePath: "test_basepath", + domainName: "test_domain", + restApiId: "test_rest_api_id", + stage: "test", + }); + }); + + it("Creates basepath mapping for regional tls 1.2 REST api", async () => { + AWS.mock("ApiGatewayV2", "createApiMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + + const spy = chai.spy.on(plugin.apigatewayV2, "createApiMapping"); + + await plugin.createBasePathMapping(dc); + + expect(spy).to.have.been.called.with({ + ApiId: "test_rest_api_id", + ApiMappingKey: "test_basepath", + DomainName: "test_domain", + Stage: "test", + }); + }); + it("Creates basepath mapping for regional HTTP/Websocket api", async () => { AWS.mock("ApiGatewayV2", "createApiMapping", (params, callback) => { callback(null, params); @@ -264,8 +319,15 @@ describe("Custom Domain Plugin", () => { plugin.apigatewayV2 = new aws.ApiGatewayV2(); const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); - dc.apiId = "test_api_id", + dc.apiId = "test_api_id"; dc.apiMapping = {ApiMappingId: "test_mapping_id"}; + dc.domainInfo = new DomainInfo({ + DomainNameConfigurations: [{ + ApiGatewayDomainName: "fake_dist_name", + HostedZoneId: "fake_zone_id", + SecurityPolicy: "TLS_1_2", + }], + }); const spy = chai.spy.on(plugin.apigatewayV2, "updateApiMapping");