初めに
本記事はタイトルについて検証を行った詳細を記載します
書くきっかけですが、最近久しぶりに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の外に出れるか確認です
- セキュリティーグループのインバウンドとアウトバウンドで全ての通信を許可
- ロールに以下ポリシーを追加
"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 |
サポートに聞くのが強い