はじめに
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をインストール
以下のコードを用いてインストールします。
npm install --save-dev cdk-nag
aws-nagを使ったテストコードの例
#!/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', {});
テストの実行:
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ポリシーのテスト例
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テンプレートに予期せぬ変更がないかを確認します。
これにより、意図しない変更によって引き起こされる問題を未然に防ぐことができます。
ただし、開発初期段階では頻繁に変更が発生するため、本番運用が始まってから導入することを検討しています。
import { Template } from 'aws-cdk-lib/assertions';
// スタックをテンプレートに合成
const template = Template.fromStack(stack);
// スナップショットと比較
expect(template.toJSON()).toMatchSnapshot();
GitHub Actionsを利用した自動テスト
GitHub Actionsを利用することで、コードの変更をトリガーに自動的にテストを実行することができます。
以下は、GitHub Actionsの設定例です。
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を活用することで、自動テストを継続的に実行し、品質の維持と向上を図ることができます。
今後も、プロジェクトの状況に応じてテスト戦略を柔軟に見直していきたいと考えています。