import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; import * as route53 from 'aws-cdk-lib/aws-route53'; import * as targets from 'aws-cdk-lib/aws-route53-targets'; import * as acm from 'aws-cdk-lib/aws-certificatemanager'; export class BetaSupplierSiteStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // 1. Create S3 Bucket for Website hosting const websiteBucket = new s3.Bucket(this, 'BetaSupplierSiteBucket', { bucketName: `betasuppliersite-${this.account}-${this.region}`, removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true, blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, // Secure by default, OAI will be used encryption: s3.BucketEncryption.S3_MANAGED, }); const ec2Origin = new origins.HttpOrigin('api.tradhox.com', { protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY, httpPort: 8080, }); // Look up the tradhox.com hosted zone const zone = route53.HostedZone.fromLookup(this, 'TradhoxZone', { domainName: 'tradhox.com', }); // Create a certificate in us-east-1 for CloudFront const certificate = new acm.DnsValidatedCertificate(this, 'SiteCertificate', { domainName: 'betapartners.tradhox.com', hostedZone: zone, region: 'us-east-1', // CloudFront requires certificates to be in us-east-1 }); // 2. Create CloudFront Distribution // origins.S3BucketOrigin.withOriginAccessControl will automatically create an Origin Access Control (OAC) // and update the S3 bucket policy to allow access only from this CloudFront distribution. const distribution = new cloudfront.Distribution(this, 'BetaSupplierSiteDistribution', { domainNames: ['betapartners.tradhox.com'], certificate: certificate, defaultRootObject: 'index.html', defaultBehavior: { origin: origins.S3BucketOrigin.withOriginAccessControl(websiteBucket), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD, cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, }, additionalBehaviors: { '/api/*': { origin: ec2Origin, viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER, }, }, errorResponses: [ { httpStatus: 404, responseHttpStatus: 200, // Return 200 for SPAs responsePagePath: '/index.html', ttl: cdk.Duration.seconds(0), }, { httpStatus: 403, responseHttpStatus: 200, // Return 200 for SPAs responsePagePath: '/index.html', ttl: cdk.Duration.seconds(0), } ] }); // Outputs new cdk.CfnOutput(this, 'BetaSupplierSiteBucketName', { value: websiteBucket.bucketName, description: 'The name of the S3 bucket for the betasupplier site', }); new cdk.CfnOutput(this, 'BetaSupplierSiteCloudFrontDomainName', { value: distribution.distributionDomainName, description: 'The domain name of the CloudFront distribution for betasupplier site', }); // 3. Create Route53 A Record to point to the CloudFront Distribution new route53.ARecord(this, 'SiteAliasRecord', { recordName: 'betapartners.tradhox.com', target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)), zone }); } }