AWS CDK Ver.2 PythonでSESのメール送信Logを記録する構成を作成してみた

SESでメールを送信した際のLogを記録する構成をAWS CDKで作ってみました。今回は費用的な観点でS3に格納するような構成としています。

全コードはGithubを参照してください。
[Githubはここ](https://github.com/ShinyaT1994/cdk-ses-log.git)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660703/900ffb28-3146-35ef-44e8-1a5ebce08682.png)


## 前提条件
- AWS CDK v.2 がインストールされていること
- Python 3.x がインストールされていること
- AWSアカウントがあり、AWS CLIが設定されていること

※Cloud9を使うとこの辺りがPassできるため、Cloud9を使って今回の記事の内容は作成しています。

## 構築手順
### 1. CDKアプリの初期化
先ずはCDKアプリの初期化を行います。

```bash
$ mkdir cdk-ses-log
$ cd cdk-ses-log
$ cdk init --language python
```

### 2.必要なパッケージをインストール

続いて必要パッケージのインストールになります。
ここでは、CDKアプリを初期化した際に作成された.venvを有効化しています。

```bash
$ source .venv/bin/activate
$ pip install -r requirements.txt
```

### 3. スタックの記述
```python
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    aws_ses as ses,
    aws_iam as iam,
    aws_kinesisfirehose as firehose,
)
from constructs import Construct

class CdkSesLogStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        region = 'ap-northeast-1'
        account_id = '**********'
        
        # SESのメール送信Logを格納するS3 Bucket
        bucket = s3.Bucket(self, 'SesLogsBucket')
        
        # Firehose用のIAM Roleを作成
        firehose_role = iam.Role(
            self,
            'FirehoseDeliveryRole',
            assumed_by=iam.ServicePrincipal("firehose.amazonaws.com")
        )
        firehose_role.add_to_policy(
            iam.PolicyStatement(
                actions=[
                    's3:PutObject',
                    's3:GetBucketLocation',
                ],
                resources=[
                    bucket.bucket_arn,
                    f'{bucket.bucket_arn}/*'
                ],
            )
        )
        firehose_role.add_to_policy(
            iam.PolicyStatement(
                actions=[
                    'logs:PutLogEvents',
                ],
                resources=[
                    f'arn:aws:logs:{region}:{account_id}:log-group:/aws/kinesisfirehose/*',
                ],
            )
        )
        
        # Firehose delivery stream
        delivery_stream = firehose.CfnDeliveryStream(
            self,
            'SesLogsDeliveryStream',
            s3_destination_configuration={
                'bucketArn': bucket.bucket_arn,
                'roleArn': firehose_role.role_arn
            }
        )
        
        # SES用のIAM Roleを作成
        ses_role = iam.Role(
            self,
            'SesRole',
            assumed_by=iam.ServicePrincipal("ses.amazonaws.com")
        )
        firehose_statement = iam.PolicyStatement(
            actions=[
                'firehose:PutRecordBatch',
                'firehose:PutRecord',
            ],
            resources=[
                delivery_stream.attr_arn
            ],
        )
        ses_policy = iam.Policy(
            self, 
            'SesPolicy', 
            policy_name='ses-policy',
            statements=[firehose_statement],
        )
        ses_role.attach_inline_policy(ses_policy)
        
        # LogをFirehoseに送るためのConfiguration setを作成する
        configuration_set = ses.CfnConfigurationSet(
            self,
            'SesLoggingConfigurationSet',
            name ='ses-logging',
        )
        event_destination = ses.CfnConfigurationSetEventDestination(
            self,
            'SesLoggingConfigurationSetEventDestination',
            configuration_set_name=configuration_set.name,
            event_destination=ses.CfnConfigurationSetEventDestination.EventDestinationProperty(
                matching_event_types=['send'],
                enabled=True,
                kinesis_firehose_destination=ses.CfnConfigurationSetEventDestination.KinesisFirehoseDestinationProperty(
                    delivery_stream_arn=delivery_stream.attr_arn,
                    iam_role_arn=ses_role.role_arn,
                )
            )
        )
        
        # 依存関係を追加
        # 依存関係を挿入しない場合、IAM PolicyとConfigurationSetEventDestination間でエラーが発生
        configuration_set.add_dependency(delivery_stream)
        event_destination.add_dependency(ses_policy.node.default_child)
```

### 4. CDKのデプロイ
```bash
cdk deploy
```

デプロイが完了すると、SESのメール送信Logを記録する構成は構築できますが、IDに対してデフォルトととして登録はされません。
特定のSES IDに対してDefault Configuration Setを設定するために、AWS CLIを利用します。（調べましたが、CDKで設定する方法が見つかりませんでした）

```bash
aws sesv2 put-email-identity-configuration-set-attributes --email-identity <EmailIdentity> --configuration-set-name <ConfigurationSetName>
```

以上で構築完了です。

## まとめ
この記事では、SESのメール送信LogをS3に格納する構成を構築する方法を紹介しました。
どなたかの参考になれば幸いです。