LoginSignup
9
3

More than 3 years have passed since last update.

VPC内のLambdaからはSES向けのVPCエンドポイントを使用してもBoto3ではメールを送信できない

Posted at

初めに

本記事はタイトルについて検証を行った詳細を記載します

書くきっかけですが、最近久しぶりにVPCと戯れることになりました。
VPCを使った構成ですんなり行った思い出はなく、実際に沼にハマりました。

ポイントをまとめましたので、どなたかのお役にたてば嬉しいです

結論だけ知りたい方は最後まで飛ばしてください

検証を行うことになった背景

VPC内のLambdaからメールを送る
ただこちらを行いたいだけでした

アーキテクチャとしては以下となります
RDS→Lambda(VPC内)→SES→ユーザー

あまり見ないアーキテクチャですね
RDS Proxyがリリースされてから、LambdaとRDSの組み合わせは使用する頻度が多くなりました
DynamoDBだけでは辛い部分もあるので、今後こちらのアーキテクチャは増えるようになるのではないでしょうか

実装するに当たって、どのようにVPCから外へ出るか調べていました
すると、2020年5月にSES向けのVPCエンドポイントがリリースされているじゃありませんか

これは簡単に実装が終わるなと試してみたところ、Lambdaでタイムアウトが発生しました
これが長い検証の始まりです...

検証内容

CloudWatchには以下のように表示されていました

Task timed out after 30.03 seconds

VPCの外に出れていないようです

1. SESの設定を疑う

まずはSESの検証が正しく行われているかテスト送信を行い確認です
サンドボックス環境にありましたので、何か影響があるのかもしれないと考えていました

テスト送信はコンソールから簡単に行えます
手順はこちら

送信元から送信先へ想定通りにメールが送信されました

SESのコンソールからは正しく送信が行えることが確認できましたので、別の原因を探します

2. 権限周り

ロールか、セキュリティーグループの設定の問題だろうと思い、まずはガバガバの設定を行いました
とりあえずVPCの外に出れるか確認です

  1. セキュリティーグループのインバウンドとアウトバウンドで全ての通信を許可
  2. ロールに以下ポリシーを追加
"ses:SendEmail","ses:SendRawEmail"を全てのリソースから許可
AWSLambdaVPCAccessExecutionRole
VPCFullAccess
SESFullAccess

それでもタイムアウトは改善されませんでした

3. ロジックの問題

次に行ったのはSESへ送信するロジックの見直しです
python3.8でBoto3を使っていました
ソースはこちらを参考にしています

ロジックに問題があるのか、設定に問題があるのか切り分けるためにまずはVPCの外にLambdaを作成し、同じソースコードで送信を行いました

すると、VPCの外にあるLambdaからはメールを送信できました
ソースに問題はなく、おそらくVPC関連の問題だということがこれまでの検証でわかりました

4. エンドポイントを指定する?

VPC内のLambdaからSQSを利用する場合ですがエンドポイントを指定する必要があります
手順には記載がありませんでしたが、これと同じでSESもエンドポントを指定する必要があるのではないかと疑いました

boto3ではclientを生成時に引数でエンドポイントを指定することができます
公式

VPCエンドポイントのURLを追加してみました

import boto3
ses_client = boto3.client('ses', region_name='ap-northeast-1', endpoint_url='com.amazonaws.region.email-smtp')

こちらで送信を試してみたところ以下エラーが発生しました

[ERROR] ValueError: Invalid endpoint: com.amazonaws.ap-northeast-1.email-smtp

エンドポイントとして無効なようです

5. Lambda(VPC内)→Lambda(VPC外)→SES

もうやけくそに近くなってきました
SES向けのVPCエンドポイントはどうやら使えないようだと思い別のアプローチをすることにしました

2020年10月にLambdaがPrivateLinkに対応していました

これを試したところ問題なくメールの送信まで行えました
でもスマートじゃない...

6. SMTPインターフェース...?

海外の方がAmazon SES SMTP インターフェイスを使用した E メールの送信をすればいけるよ!
と教えてくれているのを見つけました

リージョンごとにユーザー名とパスワードが必要になります。

うーん微妙...
boto3で送りたい...

7. サポートへ問い合わせ

もう自らの知識ではどうにもならないと判断し、問い合わせを行いました
以下回答の抜粋です

VPCエンドポイントがサポートされておりますのは「1.SES SMTP インターフェースを使う」方法となります。
一方、お客様が実施しようとしている Boto3のsend_emailメソッドを使う方法は「2.SES API(AWSCLI,AWS SDK) を使う」となり、VPCエンドポイントには対応しておりません。
「2.SES API(AWSCLI,AWS SDK) を使う」場合には以下のいずれかにて対応いただければと存じます。
・LambdaをVPC外で起動する
・LambdaをVPC内に起動し、NAT Gateway を配置して Lambda からインターネットへ接続できるようにする

まじか!!!
どこにもBoto3じゃあかんとは書いてなかったやんけ!!!
という気持ちでしたが、無事解決できてよかったです
サポートの方に感謝

このあとNAT Gatewayでの方法を試してメールが届くことを確認しました

結論

  • VPC内LambdaからBoto3を使ってメールを送信する場合はNATゲートウェイを使用してインターネット接続を行う必要がある
  • SES向けのVPCエンドポイントを使う場合はBoto3は使えない(タイムアウトになる)
  • SES向けのVPCエンドポイントを使う場合はAmazon SES SMTP インターフェイスを使用する必要がある

組み合わせ

SES向け VPCエンドポイント 送信方法
方法1 使用 SMTPインターフェース
方法2 不使用 NATゲートウェイ + Boto3

サポートに聞くのが強い

9
3
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
9
3