All checks were successful
Setup EC2 Tools / setup-server (push) Successful in 2m40s
112 lines
4 KiB
TypeScript
112 lines
4 KiB
TypeScript
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';
|
|
|
|
export interface TrypostMediaStackProps extends cdk.StackProps {
|
|
/**
|
|
* Name of the S3 bucket.
|
|
* @default 'trypostmedia'
|
|
*/
|
|
readonly bucketName?: string;
|
|
|
|
/**
|
|
* Removal policy for S3 bucket when stack is deleted.
|
|
* @default cdk.RemovalPolicy.RETAIN
|
|
*/
|
|
readonly removalPolicy?: cdk.RemovalPolicy;
|
|
|
|
/**
|
|
* Whether to auto delete objects when the bucket is removed.
|
|
* Only applicable if removalPolicy is DESTROY.
|
|
* @default false
|
|
*/
|
|
readonly autoDeleteObjects?: boolean;
|
|
}
|
|
|
|
export class TrypostMediaStack extends cdk.Stack {
|
|
public readonly mediaBucket: s3.Bucket;
|
|
public readonly distribution: cloudfront.Distribution;
|
|
|
|
constructor(scope: Construct, id: string, props?: TrypostMediaStackProps) {
|
|
super(scope, id, props);
|
|
|
|
const bucketName = props?.bucketName ?? 'trypostmedia';
|
|
const removalPolicy = props?.removalPolicy ?? cdk.RemovalPolicy.RETAIN;
|
|
const autoDeleteObjects = props?.autoDeleteObjects ?? false;
|
|
|
|
// 1. S3 Bucket for Media Storage
|
|
this.mediaBucket = new s3.Bucket(this, 'TrypostMediaBucket', {
|
|
bucketName,
|
|
removalPolicy,
|
|
autoDeleteObjects,
|
|
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, // Direct public access to S3 is blocked
|
|
encryption: s3.BucketEncryption.S3_MANAGED,
|
|
enforceSSL: true,
|
|
cors: [
|
|
{
|
|
allowedMethods: [
|
|
s3.HttpMethods.GET,
|
|
s3.HttpMethods.HEAD,
|
|
s3.HttpMethods.PUT,
|
|
s3.HttpMethods.POST,
|
|
s3.HttpMethods.DELETE,
|
|
],
|
|
allowedOrigins: ['*'],
|
|
allowedHeaders: ['*'],
|
|
exposedHeaders: ['ETag'],
|
|
maxAge: 3000,
|
|
},
|
|
],
|
|
});
|
|
|
|
// 2. CloudFront Distribution with Origin Access Control (OAC)
|
|
// S3BucketOrigin.withOriginAccessControl automatically configures OAC
|
|
// and attaches the required IAM policy to the S3 bucket allowing CloudFront read access.
|
|
this.distribution = new cloudfront.Distribution(this, 'TrypostMediaDistribution', {
|
|
comment: 'CloudFront distribution for trypostmedia S3 bucket',
|
|
defaultBehavior: {
|
|
origin: origins.S3BucketOrigin.withOriginAccessControl(this.mediaBucket),
|
|
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
|
|
responseHeadersPolicy: cloudfront.ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS_AND_SECURITY_HEADERS,
|
|
compress: true,
|
|
},
|
|
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
|
|
});
|
|
|
|
// 3. CloudFormation Outputs
|
|
new cdk.CfnOutput(this, 'BucketName', {
|
|
value: this.mediaBucket.bucketName,
|
|
description: 'The name of the media S3 bucket',
|
|
exportName: `${this.stackName}-BucketName`,
|
|
});
|
|
|
|
new cdk.CfnOutput(this, 'BucketArn', {
|
|
value: this.mediaBucket.bucketArn,
|
|
description: 'The ARN of the media S3 bucket',
|
|
exportName: `${this.stackName}-BucketArn`,
|
|
});
|
|
|
|
new cdk.CfnOutput(this, 'DistributionId', {
|
|
value: this.distribution.distributionId,
|
|
description: 'The ID of the CloudFront distribution',
|
|
exportName: `${this.stackName}-DistributionId`,
|
|
});
|
|
|
|
new cdk.CfnOutput(this, 'DistributionDomainName', {
|
|
value: this.distribution.distributionDomainName,
|
|
description: 'The domain name of the CloudFront distribution',
|
|
exportName: `${this.stackName}-DistributionDomainName`,
|
|
});
|
|
|
|
new cdk.CfnOutput(this, 'DistributionUrl', {
|
|
value: `https://${this.distribution.distributionDomainName}`,
|
|
description: 'The URL of the CloudFront distribution (use for AWS_URL in Laravel .env)',
|
|
exportName: `${this.stackName}-DistributionUrl`,
|
|
});
|
|
}
|
|
}
|