Skip to content

Commit 52999f7

Browse files
committed
chore: wip
1 parent f94aaad commit 52999f7

File tree

7 files changed

+152
-205
lines changed

7 files changed

+152
-205
lines changed

.stacks/core/cloud/src/cloud/cdn.ts

Lines changed: 51 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/* eslint-disable no-new */
2-
import type { CfnResource, NestedStackProps, aws_certificatemanager as acm, aws_wafv2 as wafv2 } from 'aws-cdk-lib'
2+
import type { CfnResource } from 'aws-cdk-lib'
33
import {
44
AssetHashType,
55
Duration,
66
Fn,
77
NestedStack,
88
RemovalPolicy,
9+
Stack,
10+
aws_certificatemanager as acm,
911
aws_cloudfront as cloudfront,
1012
aws_lambda as lambda,
1113
aws_cloudfront_origins as origins,
@@ -18,43 +20,37 @@ import {
1820
import type { Construct } from 'constructs'
1921
import { hasFiles } from '@stacksjs/storage'
2022
import { path as p } from '@stacksjs/path'
23+
import type { NestedCloudProps } from '../types'
2124
import type { EnvKey } from '~/storage/framework/stacks/env'
2225

23-
interface ResourceNestedStackProps extends NestedStackProps {
24-
env: {
25-
account: string
26-
region: string
27-
}
28-
appName: string
29-
appEnv: string
30-
domain: string
31-
partialAppKey: string
32-
zone: route53.HostedZone
33-
certificate: acm.Certificate
34-
logBucket: s3.Bucket
35-
firewall: wafv2.CfnWebACL
36-
storage: {
37-
publicBucket: s3.Bucket
38-
accessPoint: s3.CfnAccessPoint | undefined
39-
}
40-
}
41-
4226
export class CdnStack extends NestedStack {
43-
cdn!: cloudfront.Distribution
44-
originAccessIdentity!: cloudfront.OriginAccessIdentity
45-
cdnCachePolicy!: cloudfront.CachePolicy
46-
apiCachePolicy: cloudfront.CachePolicy | undefined
47-
vanityUrl!: string
48-
apiVanityUrl!: string
49-
props: ResourceNestedStackProps
50-
51-
constructor(scope: Construct, props: ResourceNestedStackProps) {
27+
originAccessIdentity: cloudfront.OriginAccessIdentity
28+
cdnCachePolicy: cloudfront.CachePolicy
29+
zone: route53.IHostedZone
30+
certificateArn: string
31+
certificate: acm.ICertificate
32+
logBucket: s3.IBucket
33+
34+
constructor(scope: Construct, props: NestedCloudProps) {
5235
super(scope, 'Cdn', props)
53-
this.props = props
54-
// ...
55-
const originAccessIdentity = new cloudfront.OriginAccessIdentity(this, 'OAI')
5636

57-
const cdnCachePolicy = new cloudfront.CachePolicy(this, 'CdnCachePolicy', {
37+
// do lookups
38+
this.zone = route53.PublicHostedZone.fromLookup(this, 'AppUrlHostedZone', {
39+
domainName: props.domain,
40+
})
41+
this.certificateArn = Stack.of(this).formatArn({
42+
service: 'acm',
43+
resource: 'certificate',
44+
resourceName: 'Certificate', // replace with your actual certificate logical ID
45+
})
46+
this.certificate = acm.Certificate.fromCertificateArn(this, 'Certificate', this.certificateArn)
47+
const bucketPrefix = `${props.appName}-${props.appEnv}`
48+
this.logBucket = s3.Bucket.fromBucketName(this, 'LogBucket', `${bucketPrefix}-logs-${props.partialAppKey}`)
49+
50+
// proceed with cdn logic
51+
this.originAccessIdentity = new cloudfront.OriginAccessIdentity(this, 'OAI')
52+
53+
this.cdnCachePolicy = new cloudfront.CachePolicy(this, 'CdnCachePolicy', {
5854
comment: 'Stacks CDN Cache Policy',
5955
cachePolicyName: `${props.appName}-${props.appEnv}-cdn-cache-policy`,
6056
minTtl: config.cloud.cdn?.minTtl ? Duration.seconds(config.cloud.cdn.minTtl) : undefined,
@@ -63,11 +59,9 @@ export class CdnStack extends NestedStack {
6359
cookieBehavior: this.getCookieBehavior(config.cloud.cdn?.cookieBehavior),
6460
})
6561

66-
// const timestamp = new Date().getTime()
67-
6862
// Fetch the timestamp from SSM Parameter Store
6963
const timestampParam = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'TimestampParam', {
70-
parameterName: `/${this.props.appName.toLowerCase()}/timestamp`,
64+
parameterName: `/${props.appName.toLowerCase()}/timestamp`,
7165
version: 1,
7266
})
7367

@@ -77,24 +71,18 @@ export class CdnStack extends NestedStack {
7771
if (!timestamp) {
7872
timestamp = new Date().getTime().toString()
7973
new ssm.StringParameter(this, 'TimestampParam', {
80-
parameterName: `/${this.props.appName.toLowerCase()}/timestamp`,
74+
parameterName: `/${props.appName.toLowerCase()}/timestamp`,
8175
stringValue: timestamp,
8276
})
8377
}
8478

85-
new route53.ARecord(this, 'AliasRecord', {
86-
recordName: this.props.domain,
87-
zone: this.props.zone,
88-
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(this.cdn)),
89-
})
90-
9179
// this edge function ensures pretty docs urls
9280
// soon to be reused for our Meema features
9381
const originRequestFunction = new lambda.Function(this, 'OriginRequestFunction', {
9482
// this needs to have partialAppKey & timestamp to ensure it is unique, because there is a chance that during testing, you deploy
9583
// the same app many times using the same app key. Since Origin Request (Lambda@Edge) functions are replicated functions, the
9684
// deletion process takes a long time. This is to ensure that the function is always unique in cases of quick recreations.
97-
functionName: `${this.props.appName}-${this.props.appEnv}-origin-request-${this.props.partialAppKey}-${timestamp}`,
85+
functionName: `${props.appName}-${props.appEnv}-origin-request-${props.partialAppKey}-${timestamp}`,
9886
description: 'The Stacks Origin Request function that prettifies URLs',
9987
runtime: lambda.Runtime.NODEJS_18_X,
10088
handler: 'dist/origin-request.handler',
@@ -112,21 +100,21 @@ export class CdnStack extends NestedStack {
112100
cfnOriginRequestFunction.applyRemovalPolicy(RemovalPolicy.RETAIN)
113101

114102
const cdn = new cloudfront.Distribution(this, 'Distribution', {
115-
domainNames: [this.props.domain],
103+
domainNames: [props.domain],
116104
defaultRootObject: 'index.html',
117105
comment: `CDN for ${config.app.url}`,
118-
certificate: this.props.certificate,
106+
certificate,
119107
enableLogging: true,
120-
logBucket: this.props.logBucket,
108+
logBucket: props.logBucket,
121109
httpVersion: cloudfront.HttpVersion.HTTP2_AND_3,
122110
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
123111
enabled: true,
124112
minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
125-
webAclId: this.props.firewall.attrArn,
113+
webAclId: props.firewall.attrArn,
126114
enableIpv6: true,
127115

128116
defaultBehavior: {
129-
origin: new origins.S3Origin(this.props.storage.publicBucket, {
117+
origin: new origins.S3Origin(props.publicBucket, {
130118
originAccessIdentity: this.originAccessIdentity,
131119
}),
132120
edgeLambdas: [
@@ -142,7 +130,7 @@ export class CdnStack extends NestedStack {
142130
cachePolicy: this.cdnCachePolicy,
143131
},
144132

145-
additionalBehaviors: this.additionalBehaviors(),
133+
additionalBehaviors: this.additionalBehaviors(props),
146134

147135
// Add custom error responses
148136
errorResponses: [
@@ -158,9 +146,9 @@ export class CdnStack extends NestedStack {
158146
// setup the www redirect
159147
// Create a bucket for www.yourdomain.com and configure it to redirect to yourdomain.com
160148
const wwwBucket = new s3.Bucket(this, 'WwwBucket', {
161-
bucketName: `www.${this.props.domain}`,
149+
bucketName: `www.${props.domain}`,
162150
websiteRedirect: {
163-
hostName: this.props.domain,
151+
hostName: props.domain,
164152
protocol: s3.RedirectProtocol.HTTPS,
165153
},
166154
removalPolicy: RemovalPolicy.DESTROY,
@@ -169,15 +157,15 @@ export class CdnStack extends NestedStack {
169157

170158
// Create a Route53 record for www.yourdomain.com
171159
new route53.ARecord(this, 'WwwAliasRecord', {
172-
recordName: `www.${this.props.domain}`,
173-
zone: this.props.zone,
160+
recordName: `www.${props.domain}`,
161+
zone: this.zone,
174162
target: route53.RecordTarget.fromAlias(new targets.BucketWebsiteTarget(wwwBucket)),
175163
})
176164

177-
this.cdn = cdn
178-
this.originAccessIdentity = originAccessIdentity
179-
this.cdnCachePolicy = cdnCachePolicy
180-
this.vanityUrl = `https://${this.cdn.domainName}`
165+
// this.cdn = cdn
166+
// this.originAccessIdentity = originAccessIdentity
167+
// this.cdnCachePolicy = cdnCachePolicy
168+
// this.vanityUrl = `https://${this.cdn.domainName}`
181169
}
182170

183171
getCookieBehavior(behavior: string | undefined): cloudfront.CacheCookieBehavior | undefined {
@@ -252,20 +240,20 @@ export class CdnStack extends NestedStack {
252240
return config.cloud.deploy?.api
253241
}
254242

255-
deployApi() {
243+
deployApi(props) {
256244
const keysToRemove = ['_HANDLER', '_X_AMZN_TRACE_ID', 'AWS_REGION', 'AWS_EXECUTION_ENV', 'AWS_LAMBDA_FUNCTION_NAME', 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE', 'AWS_LAMBDA_FUNCTION_VERSION', 'AWS_LAMBDA_INITIALIZATION_TYPE', 'AWS_LAMBDA_LOG_GROUP_NAME', 'AWS_LAMBDA_LOG_STREAM_NAME', 'AWS_ACCESS_KEY', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN', 'AWS_LAMBDA_RUNTIME_API', 'LAMBDA_TASK_ROOT', 'LAMBDA_RUNTIME_DIR', '_']
257245
keysToRemove.forEach(key => delete env[key as EnvKey])
258246

259247
const secrets = new secretsmanager.Secret(this, 'StacksSecrets', {
260-
secretName: `${this.props.appName}-${this.props.appEnv}-secrets`,
248+
secretName: `${props.appName}-${props.appEnv}-secrets`,
261249
description: 'Secrets for the Stacks application',
262250
generateSecretString: {
263251
secretStringTemplate: JSON.stringify(env),
264252
generateStringKey: Object.keys(env).join(',').length.toString(),
265253
},
266254
})
267255

268-
const functionName = `${this.props.appName}-${this.props.appEnv}-server`
256+
const functionName = `${props.appName}-${props.appEnv}-server`
269257

270258
// this.apiVanityUrl = api.url
271259
}
@@ -327,11 +315,11 @@ export class CdnStack extends NestedStack {
327315
return hasFiles(p.projectPath('docs'))
328316
}
329317

330-
additionalBehaviors(): Record<string, cloudfront.BehaviorOptions> {
318+
additionalBehaviors(props): Record<string, cloudfront.BehaviorOptions> {
331319
let behaviorOptions: Record<string, cloudfront.BehaviorOptions> = {}
332320

333321
if (this.shouldDeployApi()) {
334-
this.deployApi()
322+
this.deployApi(props)
335323

336324
behaviorOptions = this.apiBehaviorOptions()
337325
}

.stacks/core/cloud/src/cloud/dns.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* eslint-disable no-new */
2+
import {
3+
NestedStack,
4+
aws_route53 as route53,
5+
} from 'aws-cdk-lib'
6+
import type { Construct } from 'constructs'
7+
import type { NestedCloudProps } from '../types'
8+
9+
export class DnsStack extends NestedStack {
10+
constructor(scope: Construct, props: NestedCloudProps) {
11+
super(scope, 'Dns', props)
12+
13+
// lets see if the zone already exists because Buddy should have created it already
14+
// const zone = route53.PublicHostedZone.fromLookup(this, 'AppUrlHostedZone', {
15+
// domainName: props.domain,
16+
// })
17+
18+
// TODO: fix this – redirects do not work yet
19+
// config.dns.redirects?.forEach((redirect) => {
20+
// const slug = redirect.split('.').map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join('') // creates a CamelCase slug from the redirect
21+
// const hostedZone = route53.HostedZone.fromLookup(this, `RedirectHostedZone${slug}`, { domainName: redirect })
22+
// this.redirectZones.push(hostedZone)
23+
// })
24+
}
25+
}

.stacks/core/cloud/src/cloud/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/* eslint-disable no-new */
22
import type { Construct } from 'constructs'
33
import { Stack } from 'aws-cdk-lib'
4-
import type { CloudProps } from '../types'
4+
import type { CloudOptions } from '../types'
55
import { CdnStack } from './cdn'
6+
import { DnsStack } from './dns'
67
import { DocsStack } from './docs'
78
import { StorageStack } from './storage'
89
import { SecurityStack } from './security'
910

1011
export class Cloud extends Stack {
11-
constructor(scope: Construct, id: string, props: CloudProps) {
12+
constructor(scope: Construct, id: string, props: CloudOptions) {
1213
super(scope, id, props)
1314

1415
// please beware: be careful changing the order of the stacks creation below
16+
new DnsStack(this, props)
1517
new SecurityStack(this, props)
1618
new StorageStack(this, props)
1719
new CdnStack(this, props)

0 commit comments

Comments
 (0)