16
7

More than 1 year has passed since last update.

AWS CDKでSPF、DKIM、DMARC設定をしたAmazon SES を作成する

Last updated at Posted at 2023-04-24

はじめに

NTTテクノクロス株式会社の渡邉洋平です。

今回はAWS CDKを使用して、「SPF、DKIM、DMARC設定を行ったAmazon SESを作成する方法」について解説します。
CDKでドメイン回りを設定するのは鬼門なのか、検索してもすぐに見つからない情報だったので、手を動かして実際に試してみました。

参考:SPF、DKIM、DMARC

送信元のなりすましを検出するための認証として「送信ドメイン認証」という技術が一般的にあります。

SPF、DKIM、DMARCの詳細は下記のような記事でも把握できるので割愛します。これら3つの対応をすべて実施することで、送信元の信頼性を高めることができます。

1. hostzoneの参照

※前提として、送信元メールアドレスを事前に同じアカウントのRoute53のホストゾーンに設定してあるものとします。

まずはじめに、指定済みのホストゾーンをCDKのコードから参照します。

  • この例では、example.comがドメインとして定義されている既存のpublicHostZoneを参照(fromLookup)している。
    const domainName: string = "example.com";

    const hostedZone = route53.PublicHostedZone.fromLookup(
      this,
      "existHostZone",
      {
        domainName: domainName,
      }
    );

2. 適切なメール配信設定を行う

次に、Amazon SESの設定を行います。ここでは、ses.EmailIdentityを使用して、SESの設定を行っています。

const identity = new ses.EmailIdentity(this, 'Identity', {
  identity: ses.Identity.publicHostedZone(hostedZone),
  mailFromDomain: `bounce.${domainName}`,
});

SPF設定

Amazon SESとして必要な手順は以下の通りです。

CDKのL2 Constructとしては、上記のmailFromDomain設定を入力した時点で完了です。ses.EmailIdentityが自動的にホストゾーンを編集してくれます。これは非常に便利ですね!

DKIM設定

Amazon SESとして必要な手順は以下の通りです。

実はDKIM設定もCDKのL2 Constructとしては、デフォルト値としてEasy DKIMを有効にしてくれる設定(dkimSigning: true)なので、これで十分であれば特別な設定は要りません。

BYODKIMなどを実施したい場合はこちらを参考にすると指定できます。
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ses.DkimIdentity.html

DMARC

Amazon SESとして必要な手順は以下の通りです。
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-authentication-dmarc.html

こちらは現行のCDK(v2.75.0)のConstructでは未対応であるため、明示的にDMARC設定を行います。具体的にはroute53.TxtRecordを使用して、DMARCのTXTレコードを作成します。

new route53.TxtRecord(this, 'DmarcRecord', {
  zone: hostedZone,
  recordName: `_dmarc.${domainName}`,
  values: [`v=DMARC1; p=none; rua=mailto:dmarcreports@${domainName}`],
  ttl: Duration.hours(1),
});

これで、Route53のホストゾーンでサブドメインを定義し、Amazon SESの設定とDMARC設定が完了しました。

コード

最後にこれまで説明したコードを改めて掲載します。

import { Duration, Stack, StackProps, RemovalPolicy } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as route53 from "aws-cdk-lib/aws-route53";
import * as ses from "aws-cdk-lib/aws-ses";

export class Route53Stack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const domainName: string = "example.com";

    const hostedZone = route53.PublicHostedZone.fromLookup(
      this,
      "existHostZone",
      {
        domainName: domainName,
      }
    );

    const identity = new ses.EmailIdentity(this, "Identity", {
      identity: ses.Identity.publicHostedZone(hostedZone),
      mailFromDomain: `bounce.${domainName}`,
    });

    new route53.TxtRecord(this, "DmarcRecord", {
      zone: hostedZone,
      recordName: `_dmarc.${domainName}`,
      values: [
        `v=DMARC1; p=none; rua=mailto:dmarcreports@${domainName}`,
      ],
      ttl: Duration.hours(1),
    });

  }
}

Appendix. to CloudFormation Template

理解を深めるため、CDKからDumpしたCloudformationテンプレートも記載します。(一部はマスク済)


Resources:
  IdentityDkimDnsToken133E6CCBA:
    Type: AWS::Route53::RecordSet
    Properties:
      Name:
        Fn::GetAtt:
          - Identity2D60E2CC
          - DkimDNSTokenName1
      Type: CNAME
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - Fn::GetAtt:
            - Identity2D60E2CC
            - DkimDNSTokenValue1
      TTL: "1800"
  IdentityDkimDnsToken2AD0AA6D9:
    Type: AWS::Route53::RecordSet
    Properties:
      Name:
        Fn::GetAtt:
          - Identity2D60E2CC
          - DkimDNSTokenName2
      Type: CNAME
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - Fn::GetAtt:
            - Identity2D60E2CC
            - DkimDNSTokenValue2
      TTL: "1800"
  IdentityDkimDnsToken3A6A24F78:
    Type: AWS::Route53::RecordSet
    Properties:
      Name:
        Fn::GetAtt:
          - Identity2D60E2CC
          - DkimDNSTokenName3
      Type: CNAME
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - Fn::GetAtt:
            - Identity2D60E2CC
            - DkimDNSTokenValue3
      TTL: "1800"
  Identity2D60E2CC:
    Type: AWS::SES::EmailIdentity
    Properties:
      EmailIdentity: example.com
      MailFromAttributes:
        MailFromDomain: bounce.example.com
  IdentityMailFromMxRecord4D92B544:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: bounce.example.com.
      Type: MX
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - 10 feedback-smtp.us-east-1.amazonses.com
      TTL: "1800"
  IdentityMailFromTxtRecord8A2CF0BC:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: bounce.example.com.
      Type: TXT
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - '"v=spf1 include:amazonses.com ~all"'
      TTL: "1800"
  DmarcRecord17E400DB:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: _dmarc.example.com.
      Type: TXT
      HostedZoneId: XXXXXXXXXXXXXXXXXXXX
      ResourceRecords:
        - '"v=DMARC1; p=none; rua=mailto:dmarcreports@example.com"'
      TTL: "3600"

まとめ

このようにAWS CDKを使用することで、SPF、DKIM、DMARC設定を実施したAmazon SESを簡単に作成することができました。

今回紹介したCDKコードを使用すれば、独自のドメインでメール配信を行う際に必要な設定を簡単に行うことができます。ぜひこのコードを参考に、自分のプロジェクトでCDKを活用してください!

16
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
7