【保存版】AWS CDKでインフラ構築する際のテスト戦略 - 3つの必須アプローチ

## はじめに

AWS CDK (Cloud Development Kit) を使ってインフラストラクチャをコード化する際、楽して適切なテスト戦略を立てることは非常に重要だと考えています。

本記事では、AWS CDK + TypeScriptを使用する場合のテスト手法について、検討した内容をご紹介します。

## テストの全体構成

私たちのプロジェクトでは、以下の3つの観点からテストを実施することにしました。

**1. aws-nagを用いたベストプラクティス確認**
目的: AWSのベストプラクティスを遵守し、セキュアで信頼性の高いインフラストラクチャを構築する

**2. Fine-grained Assertionsによる要件の確認**
目的: 意図した通りのインフラストラクチャが作成できていることを確認する

**3. Snapshot Testingによる差分の検出**
目的: インフラストラクチャの定義に勝手な変更が加えられていないことを確認する

### 1. aws-nagを用いたベストプラクティス確認

`cdk synth`コマンドを実行する際、aws-nagを併用することで、AWSのベストプラクティスに沿ったリソース定義がなされているかを確認します。

これにより、セキュリティや信頼性に関する潜在的な問題を早期に発見し、修正することができます。

#### cdk-nagをインストール
以下のコードを用いてインストールします。
```bash
npm install --save-dev cdk-nag
```

#### aws-nagを使ったテストコードの例
```typescript
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkTestStack } from '../lib/cdk_test-stack';
import { AwsSolutionsChecks } from 'cdk-nag';
import { Aspects } from 'aws-cdk-lib';

const app = new cdk.App();
// cdk-nagのAwsSolutionsチェックを追加し、詳細なログ出力を有効にする
Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));
new CdkTestStack(app, 'CdkTestStack', {});
```

テストの実行:
```bash
cdk synth
```

出力結果の例:
```
[Error at /CdkTestStack/Bucket/Resource] AwsSolutions-S1: S3バケットでサーバーアクセスログが無効になっています。バケットに対するリクエストの詳細な記録を提供するために、サーバーアクセスログを有効にする必要があります。

[Error at /CdkTestStack/Bucket/Resource] AwsSolutions-S2: S3バケットでパブリックアクセスが制限・ブロックされていません。不正アクセスを防止するために、バケットではパブリックアクセスを制限・ブロックする必要があります。

[Error at /CdkTestStack/Bucket/Resource] AwsSolutions-S3: S3バケットでデフォルトの暗号化が有効になっていません。データ保護のため、少なくともSSEを有効にする必要があります。

[Error at /CdkTestStack/Bucket/Resource] AwsSolutions-S10: S3バケットでSSLの使用が必須になっていません。中間者攻撃などによるネットワークトラフィックの盗聴や改ざんを防ぐために、HTTPS (TLS) を使用する必要があります。Amazon S3バケットポリシーのaws:SecureTransport条件を使用して、HTTPS (TLS) による暗号化された接続のみを許可する必要があります。

エラーが見つかりました
```

### 2. Fine-grained Assertionsによる要件の確認

Fine-grained Assertionsを用いて、構築するリソースが指定した要件を満たしているかを確認します。例えば、特定のタグが付与されているか、必要なIAMポリシーが設定されているかなどを検証します。

これにより、設計通りにリソースが構築されていることを担保できます。

プロジェクトの要求レベルに合わせて、テストの粒度を調整することが大切です。

- 基本的なテスト: リソースの存在確認や、基本的な設定の確認
- 詳細なテスト: 詳細な設定や、関連するリソース間の整合性の確認


#### S3バケットとIAMポリシーのテスト例

```typescript
import { Template } from 'aws-cdk-lib/assertions';

// スタックをテンプレートに合成
const template = Template.fromStack(stack);

// S3バケットが1つ存在することを確認
template.resourceCountIs('AWS::S3::Bucket', 1);

// S3バケットがバージョニング有効化されていることを確認
template.hasResourceProperties('AWS::S3::Bucket', {
  VersioningConfiguration: {
    Status: 'Enabled'
  }
});

// IAMポリシーが特定のアクションを許可していることを確認
template.hasResourceProperties('AWS::IAM::Policy', {
  PolicyDocument: {
    Statement: [
      {
        Action: [
          's3:GetObject',
          's3:PutObject',
        ],
        Effect: 'Allow',
        Resource: '*',
      },
    ],
  },
});
```

### 3. Snapshot Testingによる差分の検出

Snapshot Testingを導入することで、生成されるCloudFormationテンプレートに予期せぬ変更がないかを確認します。

これにより、意図しない変更によって引き起こされる問題を未然に防ぐことができます。

ただし、開発初期段階では頻繁に変更が発生するため、本番運用が始まってから導入することを検討しています。

```typescript
import { Template } from 'aws-cdk-lib/assertions';

// スタックをテンプレートに合成
const template = Template.fromStack(stack);

// スナップショットと比較
expect(template.toJSON()).toMatchSnapshot();
```

## GitHub Actionsを利用した自動テスト

GitHub Actionsを利用することで、コードの変更をトリガーに自動的にテストを実行することができます。

以下は、GitHub Actionsの設定例です。

```yaml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Use Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '20.x'

    - name: Install dependencies
      run: npm ci

    - name: Run cdk synth
      run: npx cdk synth

    - name: Run tests
      run: npm test
```

## まとめ

AWS CDKを用いたインフラストラクチャのコード化において、適切なテスト戦略を立てることは非常に重要だと考えています。

aws-nagを用いたベストプラクティス確認、Fine-grained Assertionsによる要件の確認、Snapshot Testingによる差分の検出を組み合わせることで、品質と効率性を両立するテストを実現できます。

さらに、GitHub Actionsを活用することで、自動テストを継続的に実行し、品質の維持と向上を図ることができます。

今後も、プロジェクトの状況に応じてテスト戦略を柔軟に見直していきたいと考えています。

## 参考資料
-   [AWS Cloud Development Kit と CDK Nag でアプリケーションのセキュリティとコンプライアンスを管理](https://aws.amazon.com/jp/blogs/news/manage-application-security-and-compliance-with-the-aws-cloud-development-kit-and-cdk-nag/)
-   [あらゆる言語でのCDKアプリケーションのテスト
](https://aws.amazon.com/jp/blogs/news/testing-cdk-applications-in-any-language/)
-   [CDKテスト入門](https://pages.awscloud.com/rs/112-TZM-766/images/CDK%E3%81%A7%E3%82%82%E3%83%86%E3%82%B9%E3%83%88%E3%81%8C%E3%81%97%E3%81%9F%E3%81%84.pdf)