ちょっと前にやったことなので記憶があいまいですが、
今後もやる可能性のある事なので備忘録として残しておこうと思います。
VPC内で実行するLambda
AWSのEC2やRDSなどのVPC内のリソースにLambdaでアクセスする場合、
LambdaにVPC設定をすることで可能になります↓
【AWS】LambdaをVPC内で実行し、EC2のMySQLにアクセスする
https://www.geekfeed.co.jp/geekblog/lambda_vpc
しかし一方で、VPCにpublicなサブネットを設定していない場合、VPC内Lambdaからは外部のネットワークに接続することができなくなります。
つまり以下のアクセスが不可能となります。
- VPC内Lambda→VPC内Lambda
- VPC内Lambda→VPC外Lambda
- VPC内Lambda→VPC外リソース(PrivateLinkがサポートされているもの以外)
例えば、VPC内リソースからデータ取得後、そのデータを別リソースに保存したりする場合などに
データ取得Lambda→データ保存Lambdaというように連携することがあると思いますが、
LambdaからLambdaを呼び出す場合もネットワーク経由で行うため、これができなくなってしまいます。
※Lambdaを呼び出そうとしたときにTimeoutになります。
今回はこれを解決し、VPC内Lambdaから外部リソースへのアクセスができるように設定したいと思います。
方針
PrivateLinkによる外部サービスアクセス
まず、冒頭に書いた「3. VPC内Lambda→VPC外リソース」ですが、
AWSのサービスでPrivateLinkがサポートされている場合、Publicサブネットの設定などの面倒な設定はせずに
VPC内Lambdaから外部サービスへのアクセスが可能です。
例えば、EC2, CloudWatch, SNSなどの多くのサービスがPrivateLinkにサポートされています。
PrivateLinkがサポートしているサービスはこちらを参照
が、Lambdaは無いです。
そこで、Lambdaやその他の外部リソースにアクセスできるようにするため、
VPCそのものに設定を加えていきたいと思います。
構成
VPCにNAT Gatewayを持つPublicサブネットを作成し、PrivateサブネットからそのNAT Gateway経由でアクセスします。
Publicサブネット+NAT Gatewayの設定
VPCを作成した時点でPrivateサブネットは作成されているはずですので、
Publicサブネットの作成からしていきたいと思います。
①Publicサブネットの作成
普通にサブネットを作成します。わかりやすいようにNameタグを設定しておきます。
AZの指定ですが、すでにVPC Lambdaで設定しているPrivateサブネットが存在するAZを指定しておきます。
②NAT Gatewayの作成
NAT Gatewayを作成します。
①で作成したPublicサブネットを指定します。
③ルートテーブルの設定
さてここまでprivate, publicと言ってきましたが、
AWSの参考記事にも書かれている通り、
注: サブネットがプライベートであるかパブリックであるかは、そのルートテーブルにより決まります。パブリックサブネットにはインターネットゲートウェイを指すルートがあり、プライベートサブネットにはありません。
です。
つまり以下の手順によって
NAT Gatewayを設定したサブネットがPrivateサブネットになり、
Internet Gatewayを設定したサブネットがPublicサブネットになります。
Privateサブネットを関連付けたルートテーブルの作成
デフォルトで作成されているルートテーブルがあると思いますが、新規に作成しています。
NAT Gatewayを設定します。
Publicサブネットを関連付けたルートテーブルの作成
VPC作成時のInternet Gatewayを設定します。
以上で設定終了です。
アクセスの流れ的には
VPC内Lambda (private subnet) → NAT Gateway (public subnet) → Internet Gateway → 外部
って感じですかね?
AWS歴3か月の雑魚なので認識間違ってたらすみません。
lambdaの呼び出し方
通常のlambda呼び出しと変わりません。
ランタイムはNode.jsです。
constAWS=require('aws-sdk');constlambda=newAWS.Lambda();exports.handler=function(event,context,callback){// ペイロード。呼び出すLambda関数に受け渡す引数的な。letpayload={"hoge":"huga"};// ペイロードをStringにする。payload=JSON.stringify(payload);// invoke引数設定let params={FunctionName:"実行するlambda名",InvocationType:"RequestResponse",Payload:payload};// Lambda関数呼び出しlambda.invoke(params,function(err,data){if(err){context.fail(err);}context.succeed(data);});}
備考
参考のAWSリンクにもありますが、
private、publicのサブネットを持ったVPC作成を一発でやる方法があります。
用途がはっきりしているVPCを作成する場合はこれも使えるかも。
参考
How do I give internet access to my Lambda function in a VPC?
VPC内のLambdaからインターネットにアクセスする