初心者のためのAWS CDKを使った環境構築

# はじめに
深い知識のない人でも比較的簡単に環境構築できるAWS CDKを紹介します。
初心者向けの内容となっていますので、少しでも皆さんの参考になれば幸いです。


# こんな人に読んで欲しい
- AWS CDKを使ってみたい
- もっと簡単に環境構築したい
- 手動で環境構築したことがある


# 目次
- CDKとは
- 本記事のゴール
- リソース定義
- CDKデプロイ
- おまけ(bootstrapやデプロイに失敗した場合)
- まとめ


# CDKとは
[AWS CDK(AWS Cloud Development Kit)](https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/home.html)とは、プログラミング言語（使用可能言語については後述）を使用してAWS上のリソースを定義できるツールです。
一度定義さえしてしまえば、デプロイや破棄が簡単に可能な点がメリットであると感じます。
また、立ち上げたリソースにはそれぞれ料金がかかりますが、CDKの利用自体は料金がかかりませんので安心してください。

対応言語
- TypeScript
- JavaScript
- Python
- Java
- C#
- Go


# 本記事のゴール
今回は`TypeScript`を使って`S3＋CloudFront`の環境を構築します。
複雑な定義は行いませんので、構築後はぜひみなさんの開発に役立ててください。


# リソース定義
既に複数アカウントをお持ちの場合は、どのユーザで実行するかを明示するため各コマンドに`profile`を指定しましょう。
profile作成が必要な場合は[こちら](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html#cli-configure-files-where)を参考にしてください。

## CDK init
はじめにCDKのインストールをしましょう。
作業ディレクトリに移動し、以下コマンドを実行してください。

```
npm install -g aws-cdk
```

次のコマンドでバージョンが表示されれば成功です。
私の環境では`2.111.0`です。

```
cdk --version
```

インストール方法は[こちら](https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/getting_started.html#getting_started_install)を参照しました。

次にCDKアプリの初回作成です。
以下コマンドを実行しましょう。

```
cdk init app --language typescript
```

`All done！`が表示されれば成功です。

![cdk-init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952770/c6473a86-b39a-0d48-40e3-0ae4aeb9eabf.png)

いくつかのファイル、ディレクトリが作成されます。

![dir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952770/857db39d-acac-b9b5-6ff6-8a54e6b723cf.png)


## S3+CloudFrontのリソース定義
`cdk-stack.ts`の中に各リソースを定義していきます。

定義している各項目の説明は省きますが、公式ドキュメントに詳細が記載されているので、目的に合わせてカスタマイズしてください。
- [AWS CDK　2.122.0　S3](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3-readme.html)
- [AWS CDK　2.122.0　CloudFront](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html)

```cdk-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { RemovalPolicy, StackProps } 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 cf_origins from 'aws-cdk-lib/aws-cloudfront-origins';

export class CdkStack extends cdk.Stack {

  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // create S3 Bucket
    const s3Bucket = new s3.Bucket(this, 'WebsiteBucket', {
      objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.S3_MANAGED,
      removalPolicy: RemovalPolicy.DESTROY,
    });
    // set OAI
    const oai = new cf.OriginAccessIdentity(this, 'OriginAccessIdentity', {
      comment: 'website-distribution-originAccessIdentity',
    });

    // set Bucket Policy
    const frontWebBucketPolicyStatement = new iam.PolicyStatement({
      actions: ['s3:GetObject'],
      effect: iam.Effect.ALLOW,
      principals: [new iam.CanonicalUserPrincipal(oai.cloudFrontOriginAccessIdentityS3CanonicalUserId)],
      resources: [`${s3Bucket.bucketArn}/*`],
    });
    s3Bucket.addToResourcePolicy(frontWebBucketPolicyStatement);

    const distribution = new cf.Distribution(this, 'WebsiteDistribution', {
      comment: 'website_distribution',
      defaultRootObject: 'index.html',
      priceClass: cf.PriceClass.PRICE_CLASS_200,
      defaultBehavior: {
        allowedMethods: cf.AllowedMethods.ALLOW_GET_HEAD,
        cachedMethods: cf.CachedMethods.CACHE_GET_HEAD,
        cachePolicy: cf.CachePolicy.CACHING_DISABLED,
        viewerProtocolPolicy: cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        origin: new cf_origins.S3Origin(s3Bucket, {
          originAccessIdentity: oai,
        }),
      },
      minimumProtocolVersion: cf.SecurityPolicyProtocol.TLS_V1_2_2021,
    });
  }
}
```


# CDKデプロイ
## bootstrap
初回は`bootstrap`を実行しましょう。
これはCDKを使用するプロジェクトを初期化し、CDKのスタックをデプロイするための準備作業をしてくれます。
少し時間がかかるので、慌てず待ちましょう。

```
cdk bootstrap --profile {profile}
```

エラーが出なければbootstrap完了です！

## deploy
それでは最後にデプロイしていきましょう。
デプロイしても良いか聞かれるので`y`を入力して次に進んでください。

```
cdk deploy --profile {profile}
```

エラーが出なければデプロイ完了です！

確認すると、S3とCloudFrontが作成されています。
それぞれ指定した設定が反映されていることがわかります。

![スクリーンショット 2024-01-24 8.43.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952770/d1d7ae6e-8368-19ca-30bf-0ff64498b811.png)
![スクリーンショット 2024-01-24 8.41.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952770/2c503800-84ae-df0f-7827-c037e622244d.png)


# おまけ(bootstrapやデプロイに失敗した場合)
何らかの理由で失敗した場合、まずはコンソールに出力されるログを確認しましょう。
私の場合リソース定義に誤りがあり、CloudFormationスタックが`UPDATE_ROLLBACK_FAILED`状態になり、手動削除する必要がありました。
[手動削除または手動更新手順](https://repost.aws/ja/knowledge-center/cloudformation-update-rollback-failed)

また作成したリソース一式を削除してくれる便利なコマンドがあるので、こちらを実行してみるのも手かなと思います。

```
cdk destroy --profile {profile}
```


# まとめ
今回は`AWS CDK`を紹介しました。
リソース定義の書き方については勉強コストがかかりますが、2回目以降の構築が格段に早く、簡単になると思います。
私自身CDKを使い始めたばかりですので、お気づきの点があればぜひコメントください。
ここまで読んでくださりありがとうございました！