CloudFrontをCDKでデプロイしてみた

# 動機
Lightsail上にWordPressサイトを複数設置しているのですが、最近DDoS攻撃が激しくWAFを導入することにしました。
ただ、WAFはCloudFront、APIGateway、ALBにしか対応していないため、Lightsailに適用しようと思うと前段にALBまたはCloudFrontをおく必要があります。

じゃあ、CloudFrontを前段に置こう！

![スクリーンショット 2023-07-13 10.35.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1926542/f07ca9db-8bb1-53b9-1916-df9c227168df.png)


ん？

ってことはCloudFrontのディストリビューションをサイトごとに作成しないといけない。。。
コンソール上でぽちぽちするのは結構大変だな。

ここでAWS-CDKの出番です。

https://aws.amazon.com/jp/cdk/

# AWS CDKとは
IaC(Infrastructure as Code)を行えるフレームワークです。
TypeScript、Python、Java、.NET、Goなどの様々なプログラミング言語でAWSのサービスをデプロイする処理を記述することができます。

私の場合、TypeScriptの経験があるので今回はTypeScriptでCloudFrontをデプロイするコードを書き、パラメータを変更するだけで複数のディストリビューションを作成できるようにしました。

# 前提条件
* ACM(AmazonCertificateManager)およびWAF(WebApplicationFirewall)はすでに作成済みとします
* 各種パラメータはdotenvを利用して.envファイルから取得することとします(dotenvインストール済みの前提)

https://www.npmjs.com/package/dotenv

:::note warn
ACMでの証明書発行もCDK上で行なってしまおうとしたのですが、証明書認証待ちでタイムアウトしてしまい、デプロイがロールバックするのでACMでの証明書発行はコンソール上で手動で行うことにしました。
:::

# 実際のコード
以下のコマンドを実行してCDKプロジェクトを作成します。
```
$ cdk init app --language typescript
```
libフォルダにあるファイルを修正します。

```typescript:cloud-front_stack.ts
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as acm from 'aws-cdk-lib/aws-certificatemanager'
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 'dotenv/config'

export class WordpressCloudFrontStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

		// 証明書取得
	  const certificate = acm.Certificate.fromCertificateArn(
	    this,
	    process.env.SITE_CERT?? '',
	    process.env.CERT_ARN?? ''
    );

		// オリジン設定
		const origin = new origins.HttpOrigin(process.env.ORIGIN_DOMAIN_NAME?? '')

		// ディストリビューション作成
		const distribution = new cloudfront.Distribution(this, process.env.DISTRIBUTION_NAME?? '', {
  		defaultBehavior: {
  		  origin: origin,
  		  viewerProtocolPolicy:cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
  		  cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
  		},
			domainNames:[process.env.DOMAIN_NAME?? ''],
			certificate:certificate,
		  enableLogging: true, // Optional, this is implied if logBucket is specified
  		logBucket: new s3.Bucket(this, 'wordpress-cloudfront-log', {
    		objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
  		}),
  		logFilePrefix: process.env.DOMAIN_NAME?? ''+'/',
  		logIncludesCookies: false,
    })

		// ビヘイビアの追加
		const pathsStr = process.env.PATHS?? ''
		for(let path of pathsStr.split(':')){
			distribution.addBehavior(
				path,origin,
				{
					viewerProtocolPolicy:cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
					cachePolicy:cloudfront.CachePolicy.CACHING_DISABLED
				}
			)
		}
  }
}

```

また.envファイルに以下のように記述します。
```.env
CDK_DEFAULT_ACCOUNT='[利用していないので空でいい]'
CDK_DEFAULT_REGION='[メインで使うリージョン]'
SITE_CERT='[ACMで作成した証明書の名前]'
CERT_ARN='[ACMで作成した証明書のARN]'
DOMAIN_NAME='[ACMで作成した証明書の　ドメイン]'
ORIGIN_DOMAIN_NAME='[Lightsail上のWordPressに設定しているドメイン]'
DISTRIBUTION_NAME='[CloudFront上に作成するディストリビューションにつける名前]'
PATHS="/wp-admin/*:*.php"
WEB_ACL_ID="[WAFで作成したWebACLのID]"
```

PATHSはキャッシュしないファイルパスを指定しています。
今回はWordPressでキャッシュするとまずい/wp-admin/内のファイルおよびphpファイルに対してCACHING_DISABLEDポリシーを設定します。

# まとめ
無事にCloudFrontディストリビューションをデプロイし、WAFのルールセットを反映させることができました。
今後もAWS-CDKをうまく利用しながら開発効率を上げていきたいと思います。