AWS CDKで既存のCloudFrontにデプロイしたメモ

## 概要
すでに稼働しているCloudFrontに、新しくCDKでデプロイをする構成を行った。
バケット名、CloudFrontのIDが分かれば問題なくデプロイ可能であった。

## 環境

* `aws-cdk-lib`: `2.16.0`

## ソース

```cdk/lib/cdk-stack.ts
import * as core from 'aws-cdk-lib'
import * as s3 from 'aws-cdk-lib/aws-s3'
import * as cf from 'aws-cdk-lib/aws-cloudfront'
import * as iam from 'aws-cdk-lib/aws-iam'
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'
import { basePath } from '../constants/paths'
import { Construct } from 'constructs'

interface Props extends core.StackProps {
  bucketName: string
  identityName: string
  distributionId: string
  domainName: string
  projectNameTag: string
}

export class AWSCarTaGraphEditorClientStack extends core.Stack {
  constructor(scope: Construct, id: string, props: Props) {
    super(scope, id, props)
    // CloudFront オリジン用のS3バケットを作成
    const bucket = s3.Bucket.fromBucketName(
      this,
      props.bucketName,
      props.bucketName,
    )
    // CloudFront で設定する オリジンアクセスアイデンティティ を作成
    const identity = this.createIdentity(bucket, props.identityName)
    // S3バケットポリシーで、CloudFrontのオリジンアクセスアイデンティティを許可
    this.createPolicy(bucket, identity)

    // CloudFrontディストリビューションを作成
    const distribution = cf.Distribution.fromDistributionAttributes(
      this,
      props.distributionId,
      {
        domainName: '',
        distributionId: props.distributionId,
      },
    )
    // 指定したディレクトリをデプロイ
    this.deployS3(bucket, distribution, '../client/build', props.bucketName)

    // 確認用にCloudFrontのURLに整形して出力
    new core.CfnOutput(this, `${props.distributionId}-top-url`, {
      value: `https://${distribution.distributionDomainName}/`,
    })

    core.Tags.of(this).add('Project', props.projectNameTag)
  }

  private createIdentity(bucket: s3.IBucket, identityName: string) {
    const identity = new cf.OriginAccessIdentity(this, identityName, {
      comment: `${bucket.bucketName} access identity`,
    })
    return identity
  }

  private createPolicy(bucket: s3.IBucket, identity: cf.OriginAccessIdentity) {
    const myBucketPolicy = new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ['s3:GetObject', 's3:ListBucket'],
      principals: [
        new iam.CanonicalUserPrincipal(
          identity.cloudFrontOriginAccessIdentityS3CanonicalUserId,
        ),
      ],
      resources: [bucket.bucketArn + '/*', bucket.bucketArn],
    })
    bucket.addToResourcePolicy(myBucketPolicy)
  }

  private deployS3(
    siteBucket: s3.IBucket,
    distribution: cf.IDistribution,
    sourcePath: string,
    bucketName: string,
  ) {

    new s3deploy.BucketDeployment(
      this,
      `${bucketName}-deploy-with-invalidation`,
      {
        sources: [s3deploy.Source.asset(sourcePath)],
        destinationBucket: siteBucket,
        distribution,
        distributionPaths: [`/${basePath}/*`],
        destinationKeyPrefix: basePath,
      },
    )
  }
}
```

```ts:cdk/bin/cdk.ts
#!/usr/bin/env node
import 'source-map-support/register'
import * as cdk from 'aws-cdk-lib'
import { AWSCarTaGraphEditorClientStack } from '../lib/cdk-stack'
import * as dotenv from 'dotenv'

dotenv.config()
const envList = [
  'PROJECT_ID',
  'BUCKET_NAME',
  'DISTRIBUTION_ID',
  'TAG_PROJECT_NAME',
  'DOMAIN_NAME',
] as const
for (const key of envList) {
  if (!process.env[key]) throw new Error(`please add ${key} to .env`)
}
const processEnv = process.env as Record<typeof envList[number], string>

const app = new cdk.App()
const env = {
  account: process.env.CDK_DEFAULT_ACCOUNT,
  region: process.env.CDK_DEFAULT_REGION,
}
const projectId = processEnv.PROJECT_ID

new AWSCarTaGraphEditorClientStack(app, `${projectId}-stack`, {
  bucketName: processEnv.BUCKET_NAME,
  identityName: `${projectId}-origin-access-identity-to-s3-bucket`,
  distributionId: processEnv.DISTRIBUTION_ID,
  domainName: processEnv.DOMAIN_NAME,
  projectNameTag: processEnv.TAG_PROJECT_NAME,
  env,
})
```

```cdk:.env
PROJECT_ID=hogefuga
TAG_PROJECT_NAME=hogehoge
BUCKET_NAME=fuga-s3-bucket
DISTRIBUTION_ID=hoge
DOMAIN_NAME=piyo.cloudfront.net
```

バケット名はS3のバケット名。
DistributionIdとドメイン名はCloudFrontのIdとドメイン名を入力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/ff2b326c-654e-482a-5c9c-1eb57b569484.png)

## 参考
[AWS CDK v2を使ってSPA用のCloudFrontをデプロイしたメモ](https://qiita.com/hibohiboo/items/68bcb56350c74106aaa4)
[aws-cdkのv2が来たのでドキュメントを読んでみたメモ](https://qiita.com/hibohiboo/items/1a6dec3bbcf941ea4d9e)
[aws-cdk - BucketDeployment](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3_deployment.BucketDeployment.html)
[aws-cdk - Distribution](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.Distribution.html#static-fromwbrdistributionwbrattributesscope-id-attrs)