Hyperplane ENIでLambdaをプライベートリソースにアクセスさせる

お久しぶりです、きおかです。

VPCエンドポイントを作成する機会がありまして、プライベートDNSが成功するかを確認する必要がありました。

EC2インスタンスを新たに立てるのはキーペアや接続方法など考えることが多く少し手間だったので、LambdaでPythonを使って実施することにしました。

VPC Lambdaについて

2019年にLambdaのVPC接続が効率化されたらしいです。
具体的には、AWS HyperplaneというNLBとNAT Gateway用のプラットフォームを活用することで、LambdaがVPCに接続する際にNAT機能を使えるようにし、その結果複数のAWS Lambda Service VPCからCustomer VPCに接続する際に必要なENI数が効率化されたと考えてよさそうです。関数の数とENIの数に比例関係がなくなったともいえそうです。

LambdaのVPC接続は、構築の際に詳細設定で「VPCを有効化」にチェックを入れて、VPCを指定すれば実現できます。

これにより、例えば作成直後のプライベートリソースに関数を実行したい場合に、もしそのプライベートリソースをAWSマネコンで作成したのであれば、そのまま同じくAWSマネコンで実行できるというわけですね。

CLIが使えなかったりEC2を新たに構築して接続設定をするのに手間がかかる場合に役立ちそうです。

今回はAWSマネコンでVPCエンドポイントを作成した後、プライベートDNS名前解決がされるかどうかをテストするためにこの手法を用いました。

実装

Pythonのsocketライブラリを使います。バージョンは3.10を使いました。

コードは以下です。

import socket

# Public Regional endpoint for each VPC endpoint
vpce_queries = [{ここにリージョンレベルのパブリックエンドポイントを追加}]

ip_addresses = []

def lambda_handler(event, context):
    for query in vpce_queries:
        try:
            # 各ドメインに対してgetaddrinfoを実行
            addresses = socket.getaddrinfo(query, None)
            addr_list = [address[4][0] for address in addresses]
            # 結果をdataリストに追加
            ip_addresses.append(addr_list)
        except socket.gaierror as e:
            # エラーが発生した場合、その情報をip_addressesリストに追加
            ip_addresses.append(f"Error with {query}: {e}")
    return ip_addresses

socket.getaddrinfo()の返り値の構造は(family, type, proto, cannoname, sockaddr)で、sockaddrの中にIPアドレスが入っています。
https://docs.python.org/3/library/socket.html#socket.getaddrinfo

IPアドレスだけみたいので、返り値からその部分だけ抽出しています。また、複数サブネットにまたがっていたりすると返り値も複数返ってくるため、返り値に対してサブリストの数だけfor文を回しています。

さいごに

色々調べていると、Lambda Function URLsというLambdaにurlを付与して外部公開ができたり、Hyperplane ENIのIPを固定化してLambdaを即時的なアウトバウンドIPを固定化したリバースプロキシとして使う方法もあったり、DynamoDBへのクエリなど短い実行の場合はTCPコネクションを張り続けること(TCP keep-alive)もできるらしいです。

色々勉強することがありそうで、わくわくします!引き続き勉強頑張ろうと思います!

Last modified: 2023-12-22

Author