diff --git a/packages/aws-cdk-lib/aws-apigateway/README.md b/packages/aws-cdk-lib/aws-apigateway/README.md index 3f94003b7872d..e2887054c988e 100644 --- a/packages/aws-cdk-lib/aws-apigateway/README.md +++ b/packages/aws-cdk-lib/aws-apigateway/README.md @@ -1190,6 +1190,27 @@ new apigateway.DomainName(this, 'custom-domain', { }); ``` +AWS recommends using enhanced security policies for improved security. You can specify TLS 1.3 security policies: + +```ts +declare const acmCertificateForExampleCom: any; + +// For regional or private APIs +new apigateway.DomainName(this, 'custom-domain-tls13', { + domainName: 'example.com', + certificate: acmCertificateForExampleCom, + securityPolicy: apigateway.SecurityPolicy.TLS13_1_3_2025_09 // TLS 1.3 (recommended) +}); + +// For edge-optimized APIs +new apigateway.DomainName(this, 'custom-domain-edge-tls13', { + domainName: 'example.com', + certificate: acmCertificateForExampleCom, + endpointType: apigateway.EndpointType.EDGE, + securityPolicy: apigateway.SecurityPolicy.TLS13_2025_EDGE // TLS 1.3 for edge +}); +``` + Once you have a domain, you can map base paths of the domain to APIs. The following example will map the URL to the `api1` API and to the `api2` API. diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts b/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts index 5e09dcd25f76e..ce533b19654f9 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts @@ -37,6 +37,18 @@ export enum SecurityPolicy { /** Cipher suite TLS 1.2 */ TLS_1_2 = 'TLS_1_2', + + /** Cipher suite TLS 1.3 */ + TLS13_1_3_2025_09 = 'SecurityPolicy_TLS13_1_3_2025_09', + + /** Cipher suite TLS 1.3 and TLS 1.2 with post-quantum cryptography */ + TLS13_1_2_PQ_2025_09 = 'SecurityPolicy_TLS13_1_2_PQ_2025_09', + + /** Cipher suite TLS 1.3 for edge-optimized endpoints */ + TLS13_2025_EDGE = 'SecurityPolicy_TLS13_2025_EDGE', + + /** Cipher suite TLS 1.3 (FIPS compliant) */ + TLS13_1_3_FIPS_2025_09 = 'SecurityPolicy_TLS13_1_3_FIPS_2025_09', } export interface DomainNameOptions { @@ -204,8 +216,16 @@ export class DomainName extends Resource implements IDomainName { if (this.endpointType === EndpointType.EDGE) { throw new ValidationError('multi-level basePath is only supported when endpointType is EndpointType.REGIONAL', this); } - if (this.securityPolicy && this.securityPolicy !== SecurityPolicy.TLS_1_2) { - throw new ValidationError('securityPolicy must be set to TLS_1_2 if multi-level basePath is provided', this); + // Multi-level base path mapping requires TLS 1.2 or higher + const tls12OrHigher = [ + SecurityPolicy.TLS_1_2, + SecurityPolicy.TLS13_1_3_2025_09, + SecurityPolicy.TLS13_1_2_PQ_2025_09, + SecurityPolicy.TLS13_2025_EDGE, + SecurityPolicy.TLS13_1_3_FIPS_2025_09, + ]; + if (this.securityPolicy && !tls12OrHigher.includes(this.securityPolicy)) { + throw new ValidationError('securityPolicy must be set to TLS 1.2 or higher if multi-level basePath is provided', this); } return true; } diff --git a/packages/aws-cdk-lib/aws-apigateway/test/domains.test.ts b/packages/aws-cdk-lib/aws-apigateway/test/domains.test.ts index a1fa83a727150..6acf2c24a4bfc 100644 --- a/packages/aws-cdk-lib/aws-apigateway/test/domains.test.ts +++ b/packages/aws-cdk-lib/aws-apigateway/test/domains.test.ts @@ -109,6 +109,44 @@ describe('domains', () => { }); }); + test('accepts TLS 1.3 security policies', () => { + // GIVEN + const stack = new Stack(); + const cert = new acm.Certificate(stack, 'Cert', { domainName: 'example.com' }); + + // WHEN + new apigw.DomainName(stack, 'tls13-domain', { + domainName: 'tls13.example.com', + certificate: cert, + securityPolicy: apigw.SecurityPolicy.TLS13_1_3_2025_09, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::DomainName', { + 'DomainName': 'tls13.example.com', + 'SecurityPolicy': 'SecurityPolicy_TLS13_1_3_2025_09', + }); + }); + + test('allows TLS 1.3 for multi-level base paths', () => { + // GIVEN + const stack = new Stack(); + const cert = new acm.Certificate(stack, 'Cert', { domainName: 'example.com' }); + const api = new apigw.RestApi(stack, 'api'); + api.root.addMethod('GET'); + + // WHEN - Should not throw error + expect(() => { + new apigw.DomainName(stack, 'domain', { + domainName: 'api.example.com', + certificate: cert, + securityPolicy: apigw.SecurityPolicy.TLS13_1_3_2025_09, + mapping: api, + basePath: 'v1/users', + }); + }).not.toThrow(); + }); + test('"mapping" can be used to automatically map this domain to the deployment stage of an API', () => { // GIVEN const stack = new Stack(); @@ -201,7 +239,7 @@ describe('domains', () => { basePath: 'v1/api', securityPolicy: apigw.SecurityPolicy.TLS_1_0, }); - }).toThrow(/securityPolicy must be set to TLS_1_2 if multi-level basePath is provided/); + }).toThrow(/securityPolicy must be set to TLS 1.2 or higher if multi-level basePath is provided/); }); test('can use addApiMapping', () => {