How to create multiple behaviors & origins with stable API?
https://docs.aws.amazon.com/cdk/api/latest/docs/aws-cloudfront-readme.html#cloudfrontwebdistribution-api-stable
Specifically, I'm interested in how to provide behavior for API Gateway.
This is a 馃摃 documentation issue
I have a CloudFront distribution that serves an S3 bucket and an APIGateway, where the GET requests are cached by CF.
I'm not using the API part right now, but it should still work unless some API changed. I hope this gives you a starting point
cloudfront
````js
export class Frontend extends cdk.Construct {
constructor(scope: cdk.Construct, id: string) {
super(scope, id);
const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
zoneName: 'DOMAIN', //replace
hostedZoneId: 'HOSTEDZOMEID', //replace
});
const cert = new acm.DnsValidatedCertificate(this, 'Certificate', {
domainName: 'DOMAIN', //replace
hostedZone,
});
const frontendBucket = new s3.Bucket(this, 'FrontendBucket', {
websiteIndexDocument: 'index.html',
publicReadAccess: true,
});
const distribution = new cloudfront.CloudFrontWebDistribution(this, 'Distribution', {
originConfigs: [
{
customOriginSource: {
domainName: 'API.DOMAIN', //replace
},
behaviors: [{
pathPattern: '/api/*',
compress: true,
}]
},
{
customOriginSource: {
domainName: frontendBucket.bucketWebsiteDomainName,
originProtocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY,
},
behaviors : [ {
isDefaultBehavior: true,
compress: true,
}]
}
],
errorConfigurations: [
],
aliasConfiguration: {
names: ['DOMAIN'], //replace
acmCertRef: cert.certificateArn,
sslMethod: SSLMethod.SNI,
securityPolicy: SecurityPolicyProtocol.TLS_V1_2_2018,
}
});
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('PATH_TO_FRONTEND_CODE')],
destinationBucket: frontendBucket,
distribution,
});
new route53.ARecord(this, 'Alias', {
zone: hostedZone,
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
});
new route53.AaaaRecord(this, 'AliasAAA', {
zone: hostedZone,
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution))
});
}
}
API, truncated
js
export class Api extends cdk.Construct {
constructor(scope: cdk.Construct, id: string, props: DatabaseProps) {
super(scope, id);
const exampleLambda = new lambda.Function(this, 'ExampleLambda', {
//...
})
const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
zoneName: 'DOMAIN', //replace
hostedZoneId: 'HOSTEDZONEID', //replace
});
const cert = new acm.DnsValidatedCertificate(this, 'Certificate', {
domainName: 'API.DOMAIN', //replace
hostedZone,
});
const api = new apigateway.LambdaRestApi(this, 'api', {
handler: exampleLambda,
proxy: false,
endpointTypes: [apigateway.EndpointType.REGIONAL],
domainName: {
domainName: 'API.DOMAIN', //replace
certificate: cert,
securityPolicy: apigateway.SecurityPolicy.TLS_1_2,
}
});
new route53.ARecord(this, 'CustomDomainAliasRecord', {
zone: hostedZone,
target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)),
recordName: 'API.DOMAIN', //replace
});
//some more lambda code
}
}
````
Ohh.... yes, using the custom domain name for API gateway is a good workaround.
Thank you!
@DioNNiS can you close the corresponding Stack Overflow issue pls =)
Another alternative is to not set up an A/AAAA Record for api.domain and point the CF Origin to the GW execution url.
You'll need to define your GW DomainName separately and set up the base path mapping there (you don't actually have to do this, but it simplifies things significantly).
const api = new apigateway.RestApi(this, '...', { ... })
const apiDomain = new apigateway.DomainName(this, '...', {
certificate: props.certificate,
domainName: '...'
...
})
apiDomain.addBasePathMapping(api, { basePath: 'prod', stage: api.deploymentStage });
And for your CF Origin...
new cloudfront.CloudFrontWebDistribution(this, '...', {
originConfigs: [
{
customOriginSource: {
domainName: `${api.restApiId}.execute-api.${cdk.Stack.of(this).region}.amazonaws.com`,
originPath: '/prod',
originProtocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY
...
In my situation (multi-tenancy SaaS) I used an *.[APEX] domain for both API Gateway DomainName and CloudFront CNAME, as well as a wildcard Route53 record to point any *.[APEX] lookup to my CF DomainName.
The official aws-solution-constructs package implements it similarly (takes the api.url value and reduces it to a naked domain): https://github.com/awslabs/aws-solutions-constructs/blob/58f54de71b6aa18b130866f10462f65c2b5a80bd/source/patterns/%40aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts#L20