AWS Lambda関数の通信先を制御してみる。

(記事を書いた2019/12/21に公開するのを忘れ半年遅れで公開となりました）

### はじめに
 皆さんは AWS Lambda でどのような処理を実装されていますか？ AWS サービスの API （例えば、 Systems Manager の Parameter Store の API や Amazon EC2 の API ）、外部のサービスにアクセスさせたりしていますか？
企業向けシステムを構築する際には、「通信先」について情報漏洩リスクにもつながるため、関心事として高いです。
当記事では、AWS Lambda 関数を利用してアプリケーションを実装する際、どのように通信先を制御を**「強制するか」**紹介していきたいと思います。

### サマリ
 - デフォルトの Lambda 関数構成（VPC内リソースにアクセスしない）の場合、Lambda 関数に Security Group も NACL も設定できず、Lambda 関数からの通信を Lambda 関数の外で制御することができない。
 - VPC 内リソースにアクセス可能なLambda関数として構成することで、 VPC の仕組みを利用した通信先の制御が Lambda 関数の外（ロジックではなく設定）で可能になる。
 - VPC 内リソースにアクセス可能なLambdaについては[こちら](https://qiita.com/horit0123/items/86c727d8d3ae74b9e52a)
 
### AWS Lambda 関数の起動と外部との通信
 私が初めて Lambda 関数を実装したときの機能は以下を含んだものでした。

- Lambda 関数が受け取ったデータを処理して応答する
- データ処理をする際に外部サイトを呼び出す
- データ処理結果を Amazon DynamoDB に格納する

上記全て問題なく実装でき動作もしました。
デフォルトの構成でアプリケーションを実装すると**「どこにでも通信が可能」**なのです。どこにでもというのは、インターネットに公開されたエンドポイントであればどこにでもという意味です。

これは、企業のネットワークやセキュリティ担当者からすると以下の点（それ以外にもあるかもしれませんが）が気になる点になるかと思います。
1. 受け取ったデータは安全なデータか 
2. 外部サイトへのアクセスはログが残るのか
3. 許可された外部サイトにのみアクセスが行われているか

善良な開発者がプログラムを開発し、開発者とは別のレビュアやツールによってレビューが適切に行われ通信先を含め確認をすることも可能ではありますが、動的に設定される情報等で通信先が変わることもありえます。また、仮に人に頼ったレビューであれば、日々、リファクタリングやフィードバックをもとにした改善をしている場合、開発スピードの低下やレビュー漏れも発生する可能性があります。ですから静的なレビューだけではなく実行時に通信先を制御し、モニタリングし監査できる情報を確保すること重要（重要度は、そのシステムが取り扱う「情報」の重要度等に依存）になります。

そこで、今回は私が作った上記の特徴を持つアプリを例に、前述の
2. 外部サイトへのアクセスはログが残るのか
3. 許可された外部サイトにのみアクセスが行われているか
について触れていきたいと思います。

### 当記事における外部の定義
まずは当記事における「外部」の定義を行いたいと思います。外部の反対は「内部」となるため、内部と外部の定義をすることになります。
当記事における「外部」は「該当のLambda関数の所有者が所有または管理するネットワーク外に出る通信」を外部と定義し、「所有または管理するネットワーク内に留まる通信」は内部と定義します。

例：
- 経路が外部に該当するものはすべて外部です。
- 片方のリソースが外部ネットワークにある物も全て外部です。

|FROM |中間経路|TOリソース|　定義　|
|---|---|---|---|
|内部|内部|内部|**内部**|
|内部|内部|外部|**外部**|
|内部|外部|内部|**外部**|
|外部|内部|内部|**外部**|


AWSでは、[VPC(Virtual Private Cloud)](https://aws.amazon.com/jp/vpc/)というサービスがありAmazon EC2, [Amazon ECS](https://aws.amazon.com/jp/ecs/) Amazon RDS, [Amazon Redshift](https://aws.amazon.com/jp/redshift/)などのリソースを配置することができます。そしてオンプレミスのデータセンターとの専用線接続する最終的なあて先としても利用できます。

このVPCはAWSアカウント所有者でルーティングの制御ができます。また、仮想ファイヤーウォールでもあるSecurity GroupやNACL(Network Access Control List)でInbound/Outboundの制御が可能になっています。

つまり、アプリケーション用に構築したEC2やContainerがどこから通信を受けることができどこに通信可能か制御が可能になっています。つまり、VPC内で通信を行うこと、あるいは、所有者が管理する複数のVPCやオンプレミスとの専用線接続に限定して通信を許可すれば、当記事における「内部」だけに通信先を限定することがとして位置づけられるものになります。


　なお、余談ですが、2019年12月3日に発表された[VPC Ingress Routing](https://aws.amazon.com/jp/blogs/aws/new-vpc-ingress-routing-simplifying-integration-of-third-party-appliances/)という機能を利用すると、VPC内に入ってきたパケットの宛先を強制的に特定のENIにルーティングし、処理した上で、最終の宛先に特定するという制御も可能になっています。

### VPCによる通信先制御
 Lambda関数には、各関数ごとに[VPC 内のリソースにアクセスするように Lambda 関数を設定する](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-vpc.html)ことが可能になっています。
　詳細の解説は[こちらの記事](https://qiita.com/horit0123/items/86c727d8d3ae74b9e52a)にあります。
　AWS LambdaのLambda関数はデフォルトでは、所有者のVPC内の制御の影響は受けませんが、VPC内のリソースにアクセスしたい場合や、VPCによる通信先制御を利用したい場合に有効化することでSecurity Group/NACLといった仮想ファイヤーウォールによるOutbound通信の制御や名前解決、そして、VPC Route Tableによる通信宛先の制御が可能となります。

　セキュリティでは予防的な統制や発見的な統制、訂正的な統制という考え方がありますが、VPCによるRoute Table/Security Group/NACLのように事前に予防策として防ぐことがこれで可能となります。さらにVPCでは、 [VPC Flow Logs](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/flow-logs.html) や[トラフィックミラーリング](https://aws.amazon.com/jp/blogs/news/new-vpc-traffic-mirroring/)の機能も利用可能となるため、モニタリング、そして、モニタリング結果から分析や異常の検知・対応等のアクションも可能となります。

ちなみに、2020年8月にはAWS Lambda関数の作成や更新時にVPC内リソースにアクセスすることを強制できる設定がIAMポリシーのCondition句に追加されました。詳細はこちらの[ブログ](https://aws.amazon.com/jp/blogs/compute/using-aws-lambda-iam-condition-keys-for-vpc-settings/) をご参照ください。これを利用することで、通信先を強制することが可能になります。


### VPC 内のリソースにアクセスするように Lambda 関数 はアンチパターンなのか
2019年9月末（東京リージョン）以降、私はアンチパターンではないと考えます。これ以前は、アンチパターンでした。理由は、「VPC 内のリソースにアクセスするように Lambda 関数を設定する」を有効化することで、関数の**起動時**にVPC内にENIが作成されるようになるのですが、その作成時間が10秒以上かかり応答が遅延していたためでした。ただ、[こちらの改善](https://aws.amazon.com/jp/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/)により、**関数作成時（起動時ではない）** にENIが作成されるようになったことや共有されるようになったことで起動時のペナルティが大幅に改善されたのです。これにより、**”アンチ”** ではなく、セキュアな通信を強制する場合の **”標準”** になったと私は考えます

### まとめ
AWS Lambdaの各Lambda関数の通信先については、VPCの仕組み（Route Table/NACL/Security Groupやログ）を活用することで予防・ロギング・モニタリングが可能となります。Lambda関数内ロジックではなく、VPCの設定で対応をすることで、関数開発者と別の役割の人が制御することになり権限分離も可能となりよりセキュアな状態になると考えます。
2019年9月（東京リージョン）以降はVPC内にアクセスするLambda関数に対する起動時のペナルティも大幅な改善がされておりますので、ご検討ください。