From 3de444a4ef9bbf9b0f2228efafffb875172c46ab Mon Sep 17 00:00:00 2001 From: Arthur Frade de Araujo Date: Wed, 25 Feb 2026 12:06:50 -0300 Subject: [PATCH 1/4] feat(api-gateway): SecurityPolicy support --- .../events/api-gateway/lib/rest-api.js | 6 ++++ lib/plugins/aws/provider.js | 3 ++ .../events/api-gateway/lib/rest-api.test.js | 28 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js index 894fca97e..08463742f 100644 --- a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js +++ b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js @@ -17,10 +17,15 @@ module.exports = { let endpointType = 'EDGE'; let vpcEndpointIds; let BinaryMediaTypes; + let SecurityPolicy; if (apiGateway.binaryMediaTypes) { BinaryMediaTypes = apiGateway.binaryMediaTypes; } + if (apiGateway.securityPolicy) { + SecurityPolicy = apiGateway.securityPolicy; + } + if (this.serverless.service.provider.endpointType) { endpointType = this.serverless.service.provider.endpointType.toUpperCase(); @@ -52,6 +57,7 @@ module.exports = { BinaryMediaTypes, DisableExecuteApiEndpoint, EndpointConfiguration, + SecurityPolicy }; // Tags diff --git a/lib/plugins/aws/provider.js b/lib/plugins/aws/provider.js index 2bb29e701..63c2ca584 100644 --- a/lib/plugins/aws/provider.js +++ b/lib/plugins/aws/provider.js @@ -848,6 +848,9 @@ class AwsProvider { type: 'array', items: { type: 'string', pattern: '^\\S+\\/\\S+$' }, }, + securityPolicy: { + type: 'string' + }, description: { type: 'string' }, disableDefaultEndpoint: { type: 'boolean' }, metrics: { type: 'boolean' }, diff --git a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js index c8b0fe418..9d1f0931d 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js @@ -51,6 +51,30 @@ describe('#compileRestApi()', () => { EndpointConfiguration: { Types: ['EDGE'], }, + SecurityPolicy: undefined, + Policy: '', + }, + }); + }); + + it('should create a REST API resource with security policy', () => { + awsCompileApigEvents.serverless.service.provider.apiGateway = { + securityPolicy: 'SecurityPolicy_TLS13_1_3_2025_09' + } + awsCompileApigEvents.compileRestApi(); + const resources = + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources; + + expect(resources.ApiGatewayRestApi).to.deep.equal({ + Type: 'AWS::ApiGateway::RestApi', + Properties: { + BinaryMediaTypes: undefined, + DisableExecuteApiEndpoint: undefined, + Name: 'dev-new-service', + EndpointConfiguration: { + Types: ['EDGE'], + }, + SecurityPolicy: 'SecurityPolicy_TLS13_1_3_2025_09', Policy: '', }, }); @@ -75,6 +99,7 @@ describe('#compileRestApi()', () => { EndpointConfiguration: { Types: ['EDGE'], }, + SecurityPolicy: undefined, Policy: '', Tags: [ { Key: 'tagKey1', Value: 'tagValue1' }, @@ -113,6 +138,7 @@ describe('#compileRestApi()', () => { EndpointConfiguration: { Types: ['EDGE'], }, + SecurityPolicy: undefined, Policy: { Version: '2012-10-17', Statement: [ @@ -148,6 +174,7 @@ describe('#compileRestApi()', () => { Types: ['EDGE'], }, Policy: '', + SecurityPolicy: undefined, }, }); }); @@ -181,6 +208,7 @@ describe('#compileRestApi()', () => { }, Name: 'dev-new-service', Policy: '', + SecurityPolicy: undefined, }, }); }); From e78c1bcfbaf88f1ca4369ad48a226a2d80178f8c Mon Sep 17 00:00:00 2001 From: Arthur Frade de Araujo Date: Wed, 25 Feb 2026 14:46:42 -0300 Subject: [PATCH 2/4] style(api-gateway): SecurityPolicy support --- .../resources/api-gateway-cloud-watch-role/handler.js | 5 +---- .../aws/package/compile/events/api-gateway/lib/rest-api.js | 2 +- lib/plugins/aws/provider.js | 2 +- .../package/compile/events/api-gateway/lib/rest-api.test.js | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/plugins/aws/custom-resources/resources/api-gateway-cloud-watch-role/handler.js b/lib/plugins/aws/custom-resources/resources/api-gateway-cloud-watch-role/handler.js index 972471766..d2d253392 100644 --- a/lib/plugins/aws/custom-resources/resources/api-gateway-cloud-watch-role/handler.js +++ b/lib/plugins/aws/custom-resources/resources/api-gateway-cloud-watch-role/handler.js @@ -58,10 +58,7 @@ async function create(event, context) { return (await iam.send(new ListAttachedRolePoliciesCommand({ RoleName: roleName }))) .AttachedPolicies; } catch (error) { - if ( - error.code === 'NoSuchEntity' || - error.message.includes('cannot be found') - ) { + if (error.code === 'NoSuchEntity' || error.message.includes('cannot be found')) { // Role doesn't exist yet, create; await iam.send( new CreateRoleCommand({ diff --git a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js index 08463742f..4668c974c 100644 --- a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js +++ b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js @@ -57,7 +57,7 @@ module.exports = { BinaryMediaTypes, DisableExecuteApiEndpoint, EndpointConfiguration, - SecurityPolicy + SecurityPolicy, }; // Tags diff --git a/lib/plugins/aws/provider.js b/lib/plugins/aws/provider.js index 63c2ca584..eb69f86b0 100644 --- a/lib/plugins/aws/provider.js +++ b/lib/plugins/aws/provider.js @@ -849,7 +849,7 @@ class AwsProvider { items: { type: 'string', pattern: '^\\S+\\/\\S+$' }, }, securityPolicy: { - type: 'string' + type: 'string', }, description: { type: 'string' }, disableDefaultEndpoint: { type: 'boolean' }, diff --git a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js index 9d1f0931d..118a75fac 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js @@ -59,8 +59,8 @@ describe('#compileRestApi()', () => { it('should create a REST API resource with security policy', () => { awsCompileApigEvents.serverless.service.provider.apiGateway = { - securityPolicy: 'SecurityPolicy_TLS13_1_3_2025_09' - } + securityPolicy: 'SecurityPolicy_TLS13_1_3_2025_09', + }; awsCompileApigEvents.compileRestApi(); const resources = awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources; From e7ee96622d356dd50285fa2a77fc3299a0c3e12d Mon Sep 17 00:00:00 2001 From: Arthur Frade de Araujo Date: Tue, 7 Apr 2026 16:38:05 -0300 Subject: [PATCH 3/4] feat(api-gateway): EndpointAccessMode support --- docs/events/apigateway.md | 37 +++++++++++++++++++ .../events/api-gateway/lib/rest-api.js | 6 +++ lib/plugins/aws/provider.js | 4 ++ .../events/api-gateway/lib/rest-api.test.js | 30 +++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/docs/events/apigateway.md b/docs/events/apigateway.md index d84ed239c..7657f3e55 100644 --- a/docs/events/apigateway.md +++ b/docs/events/apigateway.md @@ -739,6 +739,43 @@ provider: - vpce-456 ``` +### Security Policy + +You can configure the TLS version for your API Gateway REST API by setting the `securityPolicy` property under `apiGateway` in the `provider` block. This maps directly to the [SecurityPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-securitypolicy) property of the `AWS::ApiGateway::RestApi` CloudFormation resource. +Specific explanation about Security Policy types and structure can be found [here](https://aws.amazon.com/blogs/compute/enhancing-api-security-with-amazon-api-gateway-tls-security-policies/) + +```yml +service: my-service +provider: + name: aws + apiGateway: + securityPolicy: TLS_1_2 +functions: + hello: + events: + - http: + path: user/create + method: get +``` + +### Endpoint Access Mode + +You can control how clients access your API Gateway endpoint by setting the `endpointAccessMode` property under `apiGateway` in the `provider` block. Valid values are `STRICT` and `BASIC`. This maps directly to the [EndpointAccessMode](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of the `AWS::ApiGateway::RestApi` CloudFormation resource. According to AWS documentation, if a security policy is configured with a legacy template (that doesn't have the `SecurityPolicy_` prefix) access Mode should be empty) + +```yml +service: my-service +provider: + name: aws + apiGateway: + endpointAccessMode: STRICT +functions: + hello: + events: + - http: + path: user/create + method: get +``` + ### Request Parameters To pass optional and required parameters to your functions, so you can use them in API Gateway tests and SDK generation, marking them as `true` will make them required, `false` will make them optional. diff --git a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js index 4668c974c..95086b74e 100644 --- a/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js +++ b/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.js @@ -18,6 +18,7 @@ module.exports = { let vpcEndpointIds; let BinaryMediaTypes; let SecurityPolicy; + let EndpointAccessMode; if (apiGateway.binaryMediaTypes) { BinaryMediaTypes = apiGateway.binaryMediaTypes; } @@ -26,6 +27,10 @@ module.exports = { SecurityPolicy = apiGateway.securityPolicy; } + if (apiGateway.endpointAccessMode) { + EndpointAccessMode = apiGateway.endpointAccessMode.toUpperCase(); + } + if (this.serverless.service.provider.endpointType) { endpointType = this.serverless.service.provider.endpointType.toUpperCase(); @@ -58,6 +63,7 @@ module.exports = { DisableExecuteApiEndpoint, EndpointConfiguration, SecurityPolicy, + EndpointAccessMode, }; // Tags diff --git a/lib/plugins/aws/provider.js b/lib/plugins/aws/provider.js index eb69f86b0..003a7fbee 100644 --- a/lib/plugins/aws/provider.js +++ b/lib/plugins/aws/provider.js @@ -851,6 +851,10 @@ class AwsProvider { securityPolicy: { type: 'string', }, + endpointAccessMode: { + type: 'string', + enum: ['strict', 'basic', ''].map(caseInsensitive), + }, description: { type: 'string' }, disableDefaultEndpoint: { type: 'boolean' }, metrics: { type: 'boolean' }, diff --git a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js index 118a75fac..79f7177cd 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/api-gateway/lib/rest-api.test.js @@ -52,6 +52,7 @@ describe('#compileRestApi()', () => { Types: ['EDGE'], }, SecurityPolicy: undefined, + EndpointAccessMode: undefined, Policy: '', }, }); @@ -75,6 +76,31 @@ describe('#compileRestApi()', () => { Types: ['EDGE'], }, SecurityPolicy: 'SecurityPolicy_TLS13_1_3_2025_09', + EndpointAccessMode: undefined, + Policy: '', + }, + }); + }); + + it('should create a REST API resource with endpoint access mode', () => { + awsCompileApigEvents.serverless.service.provider.apiGateway = { + endpointAccessMode: 'STRICT', + }; + awsCompileApigEvents.compileRestApi(); + const resources = + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources; + + expect(resources.ApiGatewayRestApi).to.deep.equal({ + Type: 'AWS::ApiGateway::RestApi', + Properties: { + BinaryMediaTypes: undefined, + DisableExecuteApiEndpoint: undefined, + Name: 'dev-new-service', + EndpointConfiguration: { + Types: ['EDGE'], + }, + SecurityPolicy: undefined, + EndpointAccessMode: 'STRICT', Policy: '', }, }); @@ -100,6 +126,7 @@ describe('#compileRestApi()', () => { Types: ['EDGE'], }, SecurityPolicy: undefined, + EndpointAccessMode: undefined, Policy: '', Tags: [ { Key: 'tagKey1', Value: 'tagValue1' }, @@ -139,6 +166,7 @@ describe('#compileRestApi()', () => { Types: ['EDGE'], }, SecurityPolicy: undefined, + EndpointAccessMode: undefined, Policy: { Version: '2012-10-17', Statement: [ @@ -175,6 +203,7 @@ describe('#compileRestApi()', () => { }, Policy: '', SecurityPolicy: undefined, + EndpointAccessMode: undefined, }, }); }); @@ -209,6 +238,7 @@ describe('#compileRestApi()', () => { Name: 'dev-new-service', Policy: '', SecurityPolicy: undefined, + EndpointAccessMode: undefined, }, }); }); From 9bf439bf3d024d6c28d0cc981368a02410fe59b5 Mon Sep 17 00:00:00 2001 From: Arthur Frade de Araujo Date: Tue, 7 Apr 2026 16:46:57 -0300 Subject: [PATCH 4/4] fix: definitions --- lib/plugins/aws/provider.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/plugins/aws/provider.js b/lib/plugins/aws/provider.js index 003a7fbee..e2ba5bf89 100644 --- a/lib/plugins/aws/provider.js +++ b/lib/plugins/aws/provider.js @@ -852,8 +852,7 @@ class AwsProvider { type: 'string', }, endpointAccessMode: { - type: 'string', - enum: ['strict', 'basic', ''].map(caseInsensitive), + anyOf: ['strict', 'basic', ''].map(caseInsensitive), }, description: { type: 'string' }, disableDefaultEndpoint: { type: 'boolean' },