2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[aws-cdk]S3 + CloudFrontで静的コンテンツ配信する

Posted at

S3 + CloudFrontの構成で静的コンテンツ配信する構成をCDKで作ってみた。

YAMLから開放されて非常に良い・・・CDKはいいぞ!:relaxed:

前提

  • aws-cdkの実行環境は構築済み
  • Route53の設定済み
  • ACMで証明書を発行済み

準備

不足しているパッケージを追加します。

$ npm i -D @aws-cdk/aws-s3 @aws-cdk/aws-cloudfront @aws-cdk/aws-route53-targets

コード

ディレクトリ構成

今回は以下の構成で動かすことを想定しています。l

./
├ bin/
│   └ cdk.ts
└ lib/
    └ sample/
        └ index.ts

bin/cdk.ts

sample/index.tsのpropsに値を渡してあげるだけです。

import * as cdk from '@aws-cdk/core';
import { SampleStack } from '../lib/sample';

const app = new cdk.App();

new SampleStack(app, "sample-stack", {
    // 公開したいドメイン名を指定(バケット名にもなる)
    domain: "sample.xxxxxxx.com",
    // 設定済みのRoute53の情報
    route53HostedZoneId: "xxxxxxxxx",
    route53HostedZoneName: "xxxxxxxxxxx",
    // 作成済みの証明書のARN
    acmCertificateArn: "arn:aws:acm:us-east-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    // CloudFrontに設定するTTL
    cfTtl: cdk.Duration.minutes(5),
});

Stack

import * as core from "@aws-cdk/core";
import * as s3 from "@aws-cdk/aws-s3";
import * as cf from "@aws-cdk/aws-cloudfront";
import * as route53 from "@aws-cdk/aws-route53";
import * as targets from "@aws-cdk/aws-route53-targets";

export interface SampleStackProps extends core.StackProps {
    readonly domain: string;
    readonly route53HostedZoneId: string;
    readonly route53HostedZoneName: string;
    readonly acmCertificateArn: string;
    readonly cfTtl: core.Duration;
}

export class SampleStack extends core.Stack {
    constructor(scope: core.Construct, id: string, props: SampleStackProps) {
        super(scope, id, props);

        const bucket = new s3.Bucket(this, "S3Bucket", {
            bucketName: props.domain,
            accessControl: s3.BucketAccessControl.PRIVATE,
            removalPolicy: core.RemovalPolicy.DESTROY,
        });

        const identity = new cf.OriginAccessIdentity(this, "OriginAccessIdentity", {
            comment: `${bucket.bucketName} access identity`,
        });

        const distribution = new cf.CloudFrontWebDistribution(this, "Distribution", {
            enableIpV6: true,
            httpVersion: cf.HttpVersion.HTTP2,
            viewerProtocolPolicy: cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
            viewerCertificate: {
                aliases: [props.domain],
                props: {
                    acmCertificateArn: props.acmCertificateArn,
                    sslSupportMethod: cf.SSLMethod.SNI,
                    minimumProtocolVersion: "TLSv1.2_2019",
                },
            },
            originConfigs: [
                {
                    s3OriginSource: {
                        s3BucketSource: bucket,
                        originAccessIdentity: identity,
                    },
                    behaviors: [
                        {
                            isDefaultBehavior: true,
                            allowedMethods: cf.CloudFrontAllowedMethods.GET_HEAD,
                            cachedMethods: cf.CloudFrontAllowedCachedMethods.GET_HEAD,
                            defaultTtl: props.cfTtl,
                            maxTtl: props.cfTtl,
                            minTtl: props.cfTtl,
                            forwardedValues: {
                                queryString: false,
                            },
                        },
                    ],
                },
            ],
        });

        new route53.ARecord(this, "Route53ARecordSet", {
            zone: route53.HostedZone.fromHostedZoneAttributes(this, "Route53HostedZone", {
                hostedZoneId: props.route53HostedZoneId,
                zoneName: props.route53HostedZoneName,
            }),
            recordName: props.domain,
            target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
        });
    }
}

うごかす

しばらく待ちます・・・:coffee:

$ cdk deploy sample-stack
sample-stack: deploying...
sample-stack: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (7/7)

 ✅  sample-stack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/sample-stack/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

確認

とりあえず試したいだけなので、S3にはコンソールから適当なファイルをアップロード済みです

bin/cdk.tsSampleStackに渡したドメインを開くと、ページが表示されるかと思います!

$ open sample.xxxxxxx.com

スクリーンショット 2021-03-01 0.13.20.png

破棄

今回作った構成は不要なので消しておきます:bomb:
バケットの中身は事前に空にしておきます:bomb:

$ cdk destroy sample-stack
Are you sure you want to delete: sample-stack (y/n)? y
sample-stack: destroying...

 ✅  sample-stack: destroyed
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?