【CloudFormation】VPC内のEC2インスタンスからAWS SESを使用してメール送信する方法

May
2024-11-21
2024-11-21

こんにちは。

今回は、AWS CloudFormationを用いてVPC内のEC2インスタンスからAWS SES(Simple Email Service)を利用してメールを送信するための環境を構築する手順をご紹介します。

このテンプレートは、AWS上で自動的にインフラをプロビジョニングし、SESを用いたメール送信機能を簡単にセットアップするためのものです。

テンプレートの概要

  1. VPCとパブリックサブネットの作成
    テンプレートは、まずインターネットゲートウェイ付きのVPCとパブリックサブネットを作成します。これにより、EC2インスタンスがインターネットに接続できる環境が整います。

  2. セキュリティグループの設定
    SSH(ポート22)とHTTP(ポート80)へのアクセスを許可するセキュリティグループを定義。
    EC2インスタンスはインターネットからアクセス可能で、ウェブサーバーとして機能します。

  3. SESアクセスを許可するIAMロールの作成
    EC2インスタンスがAWS SESにアクセスできるようにするIAMロールを作成します。
    このロールは、SESを通じてメールを送信するために必要な権限を持ちます。

  4. SESのメールアドレス認証
    SESでは、送信元および受信先メールアドレスの認証が必要です。
    テンプレートには、指定したメールアドレスをSESに認証させるためのリソースも含まれており、これによってメール送信が許可されます。

  5. EC2インスタンスの作成
    テンプレート内でEC2インスタンスが自動的に作成され、HTTPサーバー(Apache)がインストールされます。
    さらに、SESを使用してメールを送信するために必要なIAMロールがこのインスタンスにアタッチされ、インスタンスは外部と通信可能な状態になります。

VPC内のEC2構築について

今回の作業に取り組む前に、以前ご紹介したブログ記事に記載されている「VPC内にEC2インスタンスを構築する方法」について一度ご確認いただければと思います。

これにより、VPCの設定やEC2インスタンスのデプロイ手順について、より具体的な理解が深まるかと思います。

CloudFormationを使用してVPC内に簡単にEC2構築してみる

今回は、既に使用しているEC2のCloudFormationテンプレート「ec2_template.yaml」に、SESを利用するためのコードを追加し、VPC内のEC2インスタンスからメールを送信できるようにします。

テンプレートにSES作成コード追加

ファイル名:ec2_template.yaml

元のテンプレートに、SES(Simple Email Service)を利用できるコードを追加しました。

このコードにより、SESのインスタンスが自動で作成され、メール送信が可能になります。

SESの送信元と送信先のメールアドレスを、パラメーターとして指定できるように、Input Parametersの設定部分にコードを追加しました(青いの背景色で示されています)。

指定がない場合はデフォルトのメールアドレス「test-mail_send@test.com」が使用され、必要に応じて任意のアドレスに変更することもできます。

AWSTemplateFormatVersion:
  "2010-09-09"
Description: Provision EC2
# ------------------------------------------------------------#
# Input Parameters (Key Pair)
# ------------------------------------------------------------#
Parameters:
  KeyName:
    Type: "AWS::EC2::KeyPair::KeyName"
 
  VPCCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: 172.32.10.0/24 ←CIDR IPは自分の環境と合わせて設定してください。
 
  PublicSubnetCIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the VPC
    Type: String
    Default: 172.32.10.0/26 ←CIDR IPは自分の環境と合わせて設定してください。
 
  SenderMail:
    Description: Please enter the SES Email Verification for Sender
    Type: String
    Default: test-mail_send@test.com
 
  RecieverMail:
    Description: Please enter the SES Email Verification for Reciever
    Type: String
    Default: test-mail_recieve@test.com

Resources:
# ------------------------------------------------------------#
#  VPC作成
# ------------------------------------------------------------#
# VPC Create
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      # VPCのCidrblockはパラメータで指定する
      CidrBlock: !Ref VPCCIDR
      # VPC に対して DNS 解決がサポートされているか
      EnableDnsSupport: "true"
      # VPC 内に起動されるインスタンスが DNS ホスト名を取得するか
      EnableDnsHostnames: "true"
      # VPC 内に起動されるインスタンスの許可されているテナンシー
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: "test-vpc"

# InternetGateway Create
  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: Name
          Value: "test-igw"

# IGW Attach
  InternetGatewayAttachment:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

# ------------------------------------------------------------#
#  Public Subnet
# ------------------------------------------------------------#          
# Public Subnet Create
  PublicSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      # VPCのPublic SubnetのCidrblockはパラメータで指定する
      CidrBlock: !Ref PublicSubnetCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: "test-public-subnet"
# ------------------------------------------------------------#
#  RouteTable 
# ------------------------------------------------------------#          
# Public RouteTable Create
  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: "test-public-route"

# ------------------------------------------------------------#
# Routing (ルーティング)
# ------------------------------------------------------------#
# PublicRoute Create
  PublicRoute:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------#
# PublicRouteTable Associate PublicSubnet
  PublicSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
# ------------------------------------------------------------#
# WebServerセキュリティグループ作成
# ------------------------------------------------------------#
# WebServerセキュリティグループ
  WebServerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: test-sg-group
      GroupDescription: web server test
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          #指定のIPから接続できるように設定する
          CidrIp: 0.0.0.0/0  ←CIDR IPは自分の環境と合わせて設定してください。
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          #指定のIPから接続できるように設定する
          CidrIp: 0.0.0.0/0  ←CIDR IPは自分の環境と合わせて設定してください。
      Tags:
        - Key: Name
          Value: "test-sg-group"
# ------------------------------------------------------------#
# SES Accessするため、IAMロールの作成
# ------------------------------------------------------------#
  SESAccessRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: "SESPolicy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "ses:SendEmail"
                  - "ses:SendRawEmail"
                Resource: "*"
# ------------------------------------------------------------#
# インスタンスプロファイルの作成
# ------------------------------------------------------------#
  SESAccessInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref SESAccessRole
# ------------------------------------------------------------#
# SES Email Verification for Sender
# ------------------------------------------------------------#
  SESEmailIdentity:
    Type: AWS::SES::EmailIdentity
    Properties:
      EmailIdentity: !Ref SenderMail
# ------------------------------------------------------------#
# SES Email Verification for Recipient
# ------------------------------------------------------------#
  SESToEmailIdentity:
    Type: AWS::SES::EmailIdentity
    Properties:
      EmailIdentity: !Ref RecieverMail
# ------------------------------------------------------------#
# EC2インスタンス作成
# ------------------------------------------------------------#
# EC2インスタンス
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: ap-northeast-1a
      ImageId: ami-0329eac6c5240c99d
      IamInstanceProfile: !Ref SESAccessInstanceProfile
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      UserData:
          Fn::Base64: |
               #!/bin/bash
               sudo yum -y update
               sudo yum -y install httpd
               sudo systemctl start httpd.service
               sudo systemctl enable httpd.service
      NetworkInterfaces:
        # IPv4 アドレスを割り当てるか
        - AssociatePublicIpAddress: "true"
          # ------------------------------------------------------
          # アタッチの順序におけるネットワークインターフェイスの位置。
          # ネットワークインターフェイスを指定する場合必須
          # ------------------------------------------------------
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet
          GroupSet:
            - !Ref WebServerSG
      Tags:
        - Key: Name
          Value: "test-server-spd"

※CidrIp:0.0.0.0/0 の場合、EC2にどこからでもアクセスできるようになりますので、セキュリティ的によろしくないです。実際に構築する時、接続したい環境のIPアドレスを指定してください。

テンプレートを使用する手順

1.AWS自アカウントにログインしてください。

2.検索枠に「cloudformation」を記入すると、検索結果に「CloudFormation」が表示されます。CloudFormationをクリックすると、CloudFormationパンネルに遷移されます。

3.「スタック作成」→「テンプレートファイルのアップロード」を選択 → 作成した「ec2_template.yaml」をアプロードして、「次へ」をクリックする。

5.スタック名記入画面が表示されます。スタック名を記入してください。

※Key Nameのところに、事前に準備したキーペアファイル名を記入してください。後「次へ」       をクリックする。

6.「次へ」をクリックすると、最後に確認画面が表示されて「送信」ボタンが表示されます。

「送信」をクリックすると下記のスタックを作成している画面が表示されます。ステータスのところに CREATE_IN_PROGRESSと表示されることが確認できます。

スタック作成完了したら、「CREATE_COMPLETE」に変わります。それで完成です。

SESを使ったメールアドレス認証の流れと手順

SESを使ってメールを送信するには、送信先メールアドレスと送信元メールアドレスの認証が必要です。この記事では、SESを用いてメール送信先とメール送信元の認証を行う方法を解説します。

上記でテンプレート実施が完成した時点でSESから、登録したメールアドレス宛に認証メールが送信されます。このメールには、認証を行うためのリンクが含まれています。

受信したメールを開き、下記の添付画像通りに表示されている認証リンクをクリックします。リンクをクリックすることで、SESはそのメールアドレスが有効であることを確認します。reciev-mail-confirm

認証が成功すると、SESの管理画面で該当するメールアドレスが「認証済み」と表示されます。これで、そのメールアドレスからSESを通じたメール送信が可能になります。

SES


認証時の注意点
  • 認証メールが届かない場合は、迷惑メールフォルダを確認してください。また、メールアドレスが正しく入力されているか確認しましょう。
  • 認証リンクには有効期限があるため、できるだけ早めにクリックすることをお勧めします。

EC2にSSHから接続確認

1.スタック作成完了後に、EC2パンネルに移行してインスタンスのところに作成したEC2インスタンスが表示されることが確認できます。

create success-2

2.EC2を選択し「接続」をクリックすると、インスタンスにSSHから接続する方法を確認できます。

ssh接続方法-4

3.SSH接続するため、ローカル環境のターミナルからsshディレクトリに行って、上記のSSHクライアントの手順通りコメント実行してください。

4.下記ようにターミナルからEC2に接続できることが確認できます。

ssh-2

EC2からSESを使ってメール送信を確認する方法

EC2にSSH接続できたら、次に示すコマンドを実行して、SESを使ったメール送信を試してみましょう。

aws ses send-email \
  --from " test-mail_send@test.com" \
  --destination "ToAddresses=test-mail_recieve@test.com" \
  --message "Subject={Data=Test Email},Body={Text={Data=This is a test email}}" \
  --region ap-northeast-1  # 適切なリージョンに変更

ses send mailコマンドを実行後、送信先のメールアドレスにメールが届いたか確認してください。

以下のようにテストメールが正常に届いていれば、SESを使用したメール送信が成功したことになります。

ses-test-mail以上です。最後まで読んでくれてありがとうございました。