@@ -24,25 +24,36 @@ import {accessLogFormat} from "./RestApiGateway/accessLogFormat.js"
2424import { Certificate , CertificateValidation } from "aws-cdk-lib/aws-certificatemanager"
2525import { Bucket } from "aws-cdk-lib/aws-s3"
2626import { BucketDeployment , Source } from "aws-cdk-lib/aws-s3-deployment"
27- import { ARecord , HostedZone , RecordTarget } from "aws-cdk-lib/aws-route53"
27+ import {
28+ ARecord ,
29+ AaaaRecord ,
30+ HostedZone ,
31+ IHostedZone ,
32+ RecordTarget
33+ } from "aws-cdk-lib/aws-route53"
2834import { ApiGateway as ApiGatewayTarget } from "aws-cdk-lib/aws-route53-targets"
2935import { NagSuppressions } from "cdk-nag"
3036import { ACCOUNT_RESOURCES , LAMBDA_RESOURCES } from "../constants"
37+ import { addSuppressions } from "../utils/helpers"
3138
3239/** Configuration for creating a REST API with optional mTLS and log forwarding integrations. */
3340export interface RestApiGatewayProps {
3441 /** Stack name, used as prefix for resource naming and DNS records. */
3542 readonly stackName : string
3643 /** Shared retention period for API and deployment-related log groups. */
3744 readonly logRetentionInDays : number
38- /** Truststore object key to enable mTLS; leave undefined to disable mTLS. */
45+ /** Truststore object key to enable mTLS; leave undefined to disable mTLS or when enableServiceDomain is false . */
3946 readonly mutualTlsTrustStoreKey : string | undefined
4047 /** Enables creation of a second subscription filter to forward logs to CSOC. */
4148 readonly forwardCsocLogs : boolean
4249 /** Destination ARN used by the optional CSOC subscription filter. */
4350 readonly csocApiGatewayDestination : string
4451 /** Managed policies attached to the API Gateway execution role. */
4552 readonly executionPolicies : Array < IManagedPolicy >
53+ /**
54+ * When true (default), creates the custom service domain, ACM certificate, and Route53 records.
55+ */
56+ readonly enableServiceDomain ?: boolean
4657}
4758
4859/** Creates a regional REST API with standard logging, DNS, and optional mTLS/CSOC integration. */
@@ -63,18 +74,25 @@ export class RestApiGateway extends Construct {
6374 * mutualTlsTrustStoreKey: "truststore.pem",
6475 * forwardCsocLogs: true,
6576 * csocApiGatewayDestination: "arn:aws:logs:eu-west-2:123456789012:destination:csoc",
66- * executionPolicies: [myLambdaInvokePolicy]
77+ * executionPolicies: [myLambdaInvokePolicy],
78+ * enableServiceDomain: true
6779 * })
6880 * api.api.root.addResource("patients")
6981 * ```
7082 */
7183 public constructor ( scope : Construct , id : string , props : RestApiGatewayProps ) {
7284 super ( scope , id )
7385
86+ const enableServiceDomain = ( props . enableServiceDomain ?? true )
87+
7488 if ( props . forwardCsocLogs && props . csocApiGatewayDestination === "" ) {
7589 throw new Error ( "csocApiGatewayDestination must be provided when forwardCsocLogs is true" )
7690 }
7791
92+ if ( ! enableServiceDomain && props . mutualTlsTrustStoreKey ) {
93+ throw new Error ( "mutualTlsTrustStoreKey should not be provided when enableServiceDomain is false" )
94+ }
95+
7896 // Imports
7997 const cloudWatchLogsKmsKey = Key . fromKeyArn (
8098 this , "cloudWatchLogsKmsKey" , ACCOUNT_RESOURCES . CloudwatchLogsKmsKeyArn )
@@ -94,12 +112,17 @@ export class RestApiGateway extends Construct {
94112 const trustStoreBucketKmsKey = Key . fromKeyArn (
95113 this , "TrustStoreBucketKmsKey" , ACCOUNT_RESOURCES . TrustStoreBucketKMSKey )
96114
97- const epsDomainName : string = ACCOUNT_RESOURCES . EpsDomainName
98- const hostedZone = HostedZone . fromHostedZoneAttributes ( this , "HostedZone" , {
99- hostedZoneId : ACCOUNT_RESOURCES . EpsZoneId ,
100- zoneName : epsDomainName
101- } )
102- const serviceDomainName = `${ props . stackName } .${ epsDomainName } `
115+ let hostedZone : IHostedZone | undefined
116+ let serviceDomainName : string | undefined
117+
118+ if ( enableServiceDomain ) {
119+ const epsDomainName : string = ACCOUNT_RESOURCES . EpsDomainName
120+ hostedZone = HostedZone . fromHostedZoneAttributes ( this , "HostedZone" , {
121+ hostedZoneId : ACCOUNT_RESOURCES . EpsZoneId ,
122+ zoneName : epsDomainName
123+ } )
124+ serviceDomainName = `${ props . stackName } .${ epsDomainName } `
125+ }
103126
104127 // Resources
105128 const logGroup = new LogGroup ( this , "ApiGatewayAccessLogGroup" , {
@@ -125,14 +148,16 @@ export class RestApiGateway extends Construct {
125148 } )
126149 }
127150
128- const certificate = new Certificate ( this , "Certificate" , {
129- domainName : serviceDomainName ,
130- validation : CertificateValidation . fromDns ( hostedZone )
131- } )
151+ const certificate = enableServiceDomain && hostedZone && serviceDomainName
152+ ? new Certificate ( this , "Certificate" , {
153+ domainName : serviceDomainName ,
154+ validation : CertificateValidation . fromDns ( hostedZone )
155+ } )
156+ : undefined
132157
133158 let mtlsConfig : MTLSConfig | undefined
134159
135- if ( props . mutualTlsTrustStoreKey ) {
160+ if ( enableServiceDomain && props . mutualTlsTrustStoreKey ) {
136161 const trustStoreKeyPrefix = `cpt-api/${ props . stackName } -truststore`
137162 const logGroup = new LogGroup ( this , "LambdaLogGroup" , {
138163 encryptionKey : cloudWatchLogsKmsKey ,
@@ -214,13 +239,16 @@ export class RestApiGateway extends Construct {
214239
215240 const apiGateway = new RestApi ( this , "ApiGateway" , {
216241 restApiName : `${ props . stackName } -apigw` ,
217- domainName : {
218- domainName : serviceDomainName ,
219- certificate : certificate ,
220- securityPolicy : SecurityPolicy . TLS_1_2 ,
221- endpointType : EndpointType . REGIONAL ,
222- mtls : mtlsConfig
223- } ,
242+ ...( enableServiceDomain
243+ ? {
244+ domainName : {
245+ domainName : serviceDomainName ! ,
246+ certificate : certificate ! ,
247+ securityPolicy : SecurityPolicy . TLS_1_2 ,
248+ endpointType : EndpointType . REGIONAL ,
249+ mtls : mtlsConfig
250+ }
251+ } : { } ) ,
224252 disableExecuteApiEndpoint : mtlsConfig ? true : false , // NOSONAR
225253 endpointConfiguration : {
226254 types : [ EndpointType . REGIONAL ]
@@ -239,21 +267,23 @@ export class RestApiGateway extends Construct {
239267 managedPolicies : props . executionPolicies
240268 } ) . withoutPolicyUpdates ( )
241269
242- new ARecord ( this , "ARecord" , {
243- recordName : props . stackName ,
244- target : RecordTarget . fromAlias ( new ApiGatewayTarget ( apiGateway ) ) ,
245- zone : hostedZone
246- } )
270+ if ( enableServiceDomain && hostedZone ) {
271+ new ARecord ( this , "ARecord" , {
272+ recordName : props . stackName ,
273+ target : RecordTarget . fromAlias ( new ApiGatewayTarget ( apiGateway ) ) ,
274+ zone : hostedZone
275+ } )
247276
248- const cfnStage = apiGateway . deploymentStage . node . defaultChild as CfnStage
249- cfnStage . cfnOptions . metadata = {
250- guard : {
251- SuppressedRules : [
252- "API_GW_CACHE_ENABLED_AND_ENCRYPTED"
253- ]
254- }
277+ new AaaaRecord ( this , "AaaaRecord" , {
278+ recordName : props . stackName ,
279+ target : RecordTarget . fromAlias ( new ApiGatewayTarget ( apiGateway ) ) ,
280+ zone : hostedZone
281+ } )
255282 }
256283
284+ const cfnStage = apiGateway . deploymentStage . node . defaultChild as CfnStage
285+ addSuppressions ( [ cfnStage ] , [ "API_GW_CACHE_ENABLED_AND_ENCRYPTED" ] )
286+
257287 // Outputs
258288 this . api = apiGateway
259289 this . role = role
0 commit comments