Skip to content

Commit 0f455bc

Browse files
committed
Adding examples for cloudfront distribution-tenants
1 parent 8dddfe6 commit 0f455bc

File tree

1 file changed

+290
-0
lines changed

1 file changed

+290
-0
lines changed

packages/aws-cdk-lib/aws-cloudfront/README.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,296 @@ new cloudfront.Distribution(this, 'myDist', {
6767
defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') },
6868
});
6969
```
70+
### CloudFront SaaS Manager resources
71+
72+
#### Multi-tenant distribution and tenant providing ACM certificates
73+
You can use Cloudfront to build multi-tenant distributions to house applications.
74+
75+
To create a multi-tenant distribution w/parameters, create a Distribution construct, and then update DistributionConfig in the CfnDistribution to use connectionMode: "tenant-only":
76+
```ts
77+
// Create the simple Origin
78+
const myBucket = new s3.Bucket(this, 'myBucket');
79+
const s3Origin = origins.S3BucketOrigin.withOriginAccessControl(myBucket, {
80+
originAccessLevels: [cloudfront.AccessLevel.READ, cloudfront.AccessLevel.LIST],
81+
});
82+
83+
// Create the Distribution construct
84+
const myMultiTenantDistribution = new cloudfront.Distribution(this, 'distribution', {
85+
defaultBehavior: {
86+
origin: s3Origin,
87+
},
88+
defaultRootObject: 'index.html', // recommended to specify
89+
});
90+
91+
// Access the underlying L1 CfnDistribution to configure SaaS Manager properties which are not yet available in the L2 Distribution construct
92+
const cfnDistribution = myMultiTenantDistribution.node.defaultChild as cloudfront.CfnDistribution;
93+
94+
const defaultCacheBehavior: cloudfront.DefaultCacheBehaviorProperty = {
95+
targetOriginId: myBucket.bucketArn,
96+
viewerProtocolPolicy: 'allow-all',
97+
compress: false,
98+
allowedMethods: ['GET', 'HEAD'],
99+
cachePolicyId: cloudfront.CachePolicy.CACHING_OPTIMIZED.cachePolicyId
100+
};
101+
// Create the updated distributionConfig
102+
const distributionConfig: cloudfront.DistributionConfigProperty = {
103+
defaultCacheBehavior: defaultCacheBehavior,
104+
enabled: true,
105+
// the properties below are optional
106+
connectionMode: 'tenant-only',
107+
origins: [
108+
{
109+
id: myBucket.bucketArn,
110+
domainName: myBucket.bucketDomainName,
111+
s3OriginConfig: {},
112+
originPath: "/{{tenantName}}"
113+
},
114+
],
115+
tenantConfig: {
116+
parameterDefinitions: [
117+
{
118+
definition: {
119+
stringSchema: {
120+
required: false,
121+
// the properties below are optional
122+
comment: 'tenantName',
123+
defaultValue: 'root',
124+
},
125+
},
126+
name: 'tenantName',
127+
},
128+
],
129+
},
130+
};
131+
132+
// Override the distribution configuration to enable multi-tenancy.
133+
cfnDistribution.distributionConfig = distributionConfig;
134+
```
135+
136+
Create a distribution tenant using an existing ACM certificate
137+
```ts
138+
const cfnDistributionTenant = new cloudfront.CfnDistributionTenant(this, 'distribution-tenant', {
139+
distributionId: myMultiTenantDistribution.distributionId,
140+
domains: ['my-tenant.my.domain.com'],
141+
name: 'my-tenant',
142+
enabled: true,
143+
parameters: [ // Override the default 'tenantName' parameter (root) defined in the multi-tenant distribution.
144+
{
145+
name: 'tenantName',
146+
value: 'app',
147+
},
148+
],
149+
customizations: {
150+
certificate: {
151+
arn: 'REPLACE_WITH_ARN', // Certificate must be in us-east-1 region and cover 'my-tenant.my.domain.com'
152+
},
153+
},
154+
});
155+
```
156+
157+
#### Multi-tenant distribution and tenant with CloudFront-hosted certificate
158+
A distribution tenant with CloudFront-hosted domain validation is useful if you don't currently have traffic to the domain.
159+
160+
Start by creating a parent multi-tenant distribution
161+
```ts
162+
// Create the simple Origin
163+
const myBucket = new s3.Bucket(this, 'myBucket');
164+
const s3Origin = origins.S3BucketOrigin.withOriginAccessControl(myBucket, {
165+
originAccessLevels: [cloudfront.AccessLevel.READ, cloudfront.AccessLevel.LIST],
166+
});
167+
168+
// Create the Distribution construct
169+
const myMultiTenantDistribution = new cloudfront.Distribution(this, 'cf-hosted-distribution', {
170+
defaultBehavior: {
171+
origin: s3Origin,
172+
},
173+
defaultRootObject: 'index.html', // recommended to specify
174+
});
175+
176+
// Access the underlying L1 CfnDistribution to configure SaaS Manager properties which are not yet available in the L2 Distribution construct
177+
const cfnDistribution = myMultiTenantDistribution.node.defaultChild as cloudfront.CfnDistribution;
178+
179+
const defaultCacheBehavior: cloudfront.DefaultCacheBehaviorProperty = {
180+
targetOriginId: myBucket.bucketArn,
181+
viewerProtocolPolicy: 'allow-all',
182+
compress: false,
183+
allowedMethods: ['GET', 'HEAD'],
184+
cachePolicyId: cloudfront.CachePolicy.CACHING_OPTIMIZED.cachePolicyId
185+
};
186+
// Create the updated distributionConfig
187+
const distributionConfig: cloudfront.DistributionConfigProperty = {
188+
defaultCacheBehavior: defaultCacheBehavior,
189+
enabled: true,
190+
// the properties below are optional
191+
connectionMode: 'tenant-only',
192+
origins: [
193+
{
194+
id: myBucket.bucketArn,
195+
domainName: myBucket.bucketDomainName,
196+
s3OriginConfig: {},
197+
originPath: "/{{tenantName}}"
198+
},
199+
],
200+
tenantConfig: {
201+
parameterDefinitions: [
202+
{
203+
definition: {
204+
stringSchema: {
205+
required: false,
206+
// the properties below are optional
207+
comment: 'tenantName',
208+
defaultValue: 'root',
209+
},
210+
},
211+
name: 'tenantName',
212+
},
213+
],
214+
},
215+
};
216+
217+
// Override the distribution configuration to enable multi-tenancy.
218+
cfnDistribution.distributionConfig = distributionConfig;
219+
```
220+
221+
Create a connection group and a cname record in an existing hosted zone to validate domain ownership
222+
```ts
223+
const connectionGroup = new cloudfront.CfnConnectionGroup(this, 'cf-hosted-connection-group', {
224+
enabled: true,
225+
ipv6Enabled: true,
226+
name: 'my-connection-group',
227+
});
228+
229+
// Import the existing hosted zone info, replacing with your hostedZoneId and zoneName
230+
const hostedZoneId = 'YOUR_HOSTED_ZONE_ID';
231+
const zoneName = 'my.domain.com';
232+
const hostedZone = HostedZone.fromHostedZoneAttributes(this, 'hosted-zone', {
233+
hostedZoneId,
234+
zoneName,
235+
});
236+
237+
const record = new CnameRecord(this, 'cname-record', {
238+
domainName: connectionGroup.attrRoutingEndpoint,
239+
zone: hostedZone,
240+
recordName: 'cf-hosted-tenant.my.domain.com',
241+
});
242+
```
243+
244+
Create the cloudfront-hosted tenant, passing in the previously created connection group
245+
```ts
246+
const cloudfrontHostedTenant = new cloudfront.CfnDistributionTenant(this, 'cf-hosted-tenant', {
247+
distributionId: myMultiTenantDistribution.distributionId,
248+
name: 'cf-hosted-tenant',
249+
domains: ['cf-hosted-tenant.my.domain.com'],
250+
connectionGroupId: connectionGroup.attrId,
251+
enabled: true,
252+
managedCertificateRequest: {
253+
validationTokenHost: 'cloudfront'
254+
},
255+
});
256+
```
257+
258+
#### Multi-tenant distribution and tenant with self-hosted certificate
259+
A tenant with self-hosted domain validation is useful if you already have traffic to the domain and can't tolerate downtime during migration to multi-tenant architecture.
260+
261+
The tenant will be created, and the managed certificate will be awaiting validation of domain ownership. You can then validate domain ownership via http redirect or token file upload. [More details here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/managed-cloudfront-certificates.html#complete-domain-ownership)
262+
263+
Traffic won't be migrated until you update your hosted zone to point the tenant domain to the CloudFront RoutingEndpoint.
264+
265+
Start by creating a parent multi-tenant distribution
266+
```ts
267+
// Create the simple Origin
268+
const myBucket = new s3.Bucket(this, 'myBucket');
269+
const s3Origin = origins.S3BucketOrigin.withOriginAccessControl(myBucket, {
270+
originAccessLevels: [cloudfront.AccessLevel.READ, cloudfront.AccessLevel.LIST],
271+
});
272+
273+
// Create the Distribution construct
274+
const myMultiTenantDistribution = new cloudfront.Distribution(this, 'cf-hosted-distribution', {
275+
defaultBehavior: {
276+
origin: s3Origin,
277+
},
278+
defaultRootObject: 'index.html', // recommended to specify
279+
});
280+
281+
// Access the underlying L1 CfnDistribution to configure SaaS Manager properties which are not yet available in the L2 Distribution construct
282+
const cfnDistribution = myMultiTenantDistribution.node.defaultChild as cloudfront.CfnDistribution;
283+
284+
const defaultCacheBehavior: cloudfront.DefaultCacheBehaviorProperty = {
285+
targetOriginId: myBucket.bucketArn,
286+
viewerProtocolPolicy: 'allow-all',
287+
compress: false,
288+
allowedMethods: ['GET', 'HEAD'],
289+
cachePolicyId: cloudfront.CachePolicy.CACHING_OPTIMIZED.cachePolicyId
290+
};
291+
// Create the updated distributionConfig
292+
const distributionConfig: cloudfront.DistributionConfigProperty = {
293+
defaultCacheBehavior: defaultCacheBehavior,
294+
enabled: true,
295+
// the properties below are optional
296+
connectionMode: 'tenant-only',
297+
origins: [
298+
{
299+
id: myBucket.bucketArn,
300+
domainName: myBucket.bucketDomainName,
301+
s3OriginConfig: {},
302+
originPath: "/{{tenantName}}"
303+
},
304+
],
305+
tenantConfig: {
306+
parameterDefinitions: [
307+
{
308+
definition: {
309+
stringSchema: {
310+
required: false,
311+
// the properties below are optional
312+
comment: 'tenantName',
313+
defaultValue: 'root',
314+
},
315+
},
316+
name: 'tenantName',
317+
},
318+
],
319+
},
320+
};
321+
322+
// Override the distribution configuration to enable multi-tenancy.
323+
cfnDistribution.distributionConfig = distributionConfig;
324+
```
325+
326+
Create a connection group so we have access to the RoutingEndpoint associated with the tenant we are about to create
327+
```ts
328+
const connectionGroup = new cloudfront.CfnConnectionGroup(this, 'self-hosted-connection-group', {
329+
enabled: true,
330+
ipv6Enabled: true,
331+
name: 'self-hosted-connection-group',
332+
});
333+
```
334+
335+
Create a distribution tenant with a self-hosted domain.
336+
```ts
337+
const selfHostedTenant = new cloudfront.CfnDistributionTenant(this, 'self-hosted-tenant', {
338+
distributionId: myMultiTenantDistribution.distributionId,
339+
connectionGroupId: connectionGroup.attrId,
340+
name: 'self-hosted-tenant',
341+
domains: ['self-hosted-tenant.my.domain.com'],
342+
enabled: true,
343+
managedCertificateRequest: {
344+
primaryDomainName: 'self-hosted-tenant.my.domain.com',
345+
validationTokenHost: 'self-hosted',
346+
},
347+
});
348+
349+
// Export the RoutingEndpoint, skip this step if you'd prefer to fetch it from the CloudFront console or via Cloudfront.ListConnectionGroups API
350+
new cdk.CfnOutput(this, 'RoutingEndpoint', {
351+
value: connectionGroup.attrRoutingEndpoint,
352+
description: 'CloudFront Routing Endpoint to be added to my hosted zone CNAME records',
353+
});
354+
```
355+
After this self-hosted tenant is created, [follow the steps here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/managed-cloudfront-certificates.html#complete-domain-ownership) to complete domain setup.
356+
357+
Validate domain ownership using the section "I have existing traffic"
358+
359+
Then, when you are ready to accept traffic, follow the steps [here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/managed-cloudfront-certificates.html#point-domains-to-cloudfront) using the RoutingEndpoint from above
70360

71361
### VPC origins
72362

0 commit comments

Comments
 (0)