見出し画像

ExternalのApplication Load Balancer(ALB)をAPIGateway+InternalのALBに置き換えてみた

はじめに

こんにちは、はまです。
ナビタイムジャパンでインフラ環境の管理・構築・運用を担当しています。

当社はAmazon Web Service(AWS)を主軸としてサービスを構築しており、
今回は、コスト削減を目的として実施した、
外部受付用のApplication Load Balancer(ALB, 以後ExternalALB)を
Amazon API Gateway(APIGateway) + 内部受付用のALB(以後InternalALB)に置き換えた話をさせていただければと思います。

経緯

当社のAPIサーバーの内、今回の対象となったAPIサーバは、
基本的にAmazon Virtual Private Cloud (VPC)内のアクセスがメインとなりますが、一部インターネット経由でアクセスする処理があるため、ExternalALBとInternalALBの2つを平行運用する形となっていました。
ExternalALBに関しては使用頻度も低く、固定費がかかってしまうため、こちらを削減することでコスト削減が見込めるという所から今回の取り組みは始まりました。
その代替案として挙がったのが、APIGateway(HTTP API)+ VPCリンク でプライベートのサブネットに存在しているInternalALBを利用する形でした。

構成

AWS Lambda

今回利用するHTTP APIはAWS WAF(WAF)をアタッチすることができない為、
Lambdaオーソライザーを使用することにより、アクセス制御を実現しています。

APIGateway

APIタイプにHTTP APIを使用することで、REST APIと比べてコスト減になります。また、VPCリンクを使用することで、プライベートサブネット内に存在しているリソースにアクセスすることが可能になります。

注意点

コストに関して

APIGatewayはリクエスト数に対する課金、ALBは固定費となる為、リクエスト数が多いALBの場合はコストメリットが得られない可能性があります。
当社の場合、置き換え対象がリクエスト数が少ないALBだった為、コスト削減が見込めました。

今回の例で考えると、

  • ALB(時間課金)

    • 0.0243USD(時間、東京リージョン)

    • → 0.0243 * 24(時間) * 31(日) = 18.0792USD(月間)

  • APIGatewayのHTTP API (リクエスト数に対する課金)

    • 100万リクエストあたり 1.29USD(月間、東京リージョン)

※2022年9月時点の料金です、最新はこちら(ALB, APIGateway)をご確認ください。

となり、 置き換え対象のALBの月間リクエスト数が、1400万リクエストより多いか少ないかが、この構成を採用するコストメリットを測る上で重要なポイントとなりました。
※ ALBの場合はロードバランサーキャパシティーユニット (LCU)、APIGatewayの場合はデータ転送量による課金も発生しますが、今回は細かいので省略します。

APIGatewayの制限に関して

また、ALBをAPIGatewayのHTTP APIに置き換えるにあたって、APIGateway側の制限(TLS1.2限定、Timeoutのmaxが30秒 etc…)も気にする必要があります。

セキュリティ面に関して

今回の対応は外部からプライベートサブネットのリソースにアクセスできる口を作ることになる為、元々InternalのALBのみで運用している場合などはセキュリティ面の考慮が必要です。

作成手順

Lambda

今回は特定IPアドレスの場合にのみアクセス可能としたいため、リクエスト元のIPがLambda内に定義しているIPアドレスと一致した場合に認証を通すLambdaを予め作成しておきます。
以下Lambdaのコード例です。

def lambda_handler(event, context):

    response = {
        'isAuthorized': False
    }

    ## 許可するアクセス元IPを指定
    IP_WHITE_LIST = ['xxx.xxx.xxx.xxx','xxx.xxx.xxx.xxx']

    source_ip = event['requestContext']['http']['sourceIp']
    
    if source_ip in IP_WHITE_LIST:
        response = {
            'isAuthorized': True
        }
     
    return response

APIGateway

VPCリンクの作成
アクセスしたいInternal ALBの存在しているサブネット, セキュリティグループを指定し、VPCリンクを作成します。

APIGatewayの作成
APIタイプにHTTP APIを指定し作成。
ルートの作成→ ルートとメソッドは「ANY, /{proxy+}」 を指定
その後認可、統合をそれぞれ設定します。

認可
オーソライザーに事前に作成したLambdaを指定します。
オーソライザーのキャッシュをONにし、IDソースを「$request.header.X-Forwarded-For」にすることで、アクセス元IP単位でのキャッシュを実現し、Lambdaの発火回数を削減、レスポンスタイムの削減にも繋がります。

オーソライザーの設定

統合
統合ターゲットでプライベートリソースを選択、接続先のALB、VPCリンクを指定します。
また、HTTPSでアクセスする際のドメインについてはこの時点で指定が必要です(HTTPS ホスト名)。

統合の設定

カスタムドメイン作成
最後に先ほど指定したドメインでカスタムドメインを作成、APIGatewayとの紐づけを実施し、その後名前解決できるようにドメインの設定を行うことで利用可能となります。

終わりに

今回は手動で作成する手順をご紹介しましたが、複数環境で同一のものを構築する必要がある場合は、AWS CloudFormationでのテンプレート化を行う方が良さそうです。
当社も複数環境で運用をしているため、今後テンプレート化についても進めていく予定です。

最後までお読みいただき、ありがとうございました。