VPC LambdaでHTTPプロキシとVPCエンドポイントを両立できるか試してみた

VPC LambdaでHTTPプロキシとVPCエンドポイントを両立できるか試してみた

Clock Icon2025.05.27

こんにちは。テクニカルサポートチームのShiinaです。

はじめに

企業のセキュリティポリシーによってインターネットへのアクセスが制限されている環境では、プロキシサーバを利用することがあります。
EC2 ではなく、AWS Lambda のようなサーバーレス環境でもプロキシサーバは利用できるのか気になったので試してみました。
さらに、S3 や API Gateway など AWS サービスへの通信はプロキシをバイパスして VPC エンドポイント経由でアクセスできるのかについても検証してみました。
セキュリティと利便性の両立に悩んでいる方の参考になれば嬉しいです。

結論

Lambda 関数の環境変数にHTTP_PROXYHTTPS_PROXYを設定することで HTTP プロキシサーバを利用することができます。

  • HTTP_PROXY:http://<ProxyServerIP>:<Port>
  • HTTPS_PROXY:http://<ProxyServerIP>:<Port>

さらに、NO_PROXYAWS_ENDPOINT_URL_S3AWS_ENDPOINT_URL_API_GATEWAYなどの環境変数を設定することで、特定の AWS サービスへの通信をプロキシ経由せず、VPC エンドポイント経由でアクセスできます。

例(S3 と API Gateway の場合)

  • NO_PROXY:s3.ap-northeast-1.amazonaws.com,execute-api.ap-northeast-1.amazonaws.com
  • AWS_ENDPOINT_URL_S3:https://s3.ap-northeast-1.amazonaws.com
  • AWS_ENDPOINT_URL_API_GATEWAY:https://execute-api.ap-northeast-1.amazonaws.com

検証環境

構成概要

Lambda 関数を配置した VPC を用意し、S3 ゲートウェイ型エンドポイントと API Gateway インターフェース型エンドポイントを作成します。
Lambda 関数を配置する VPC とは異なる VPC にプロキシサーバを構築します。
両 VPC 間はピアリング接続を行い、相互通信を可能にします。

構成図

AWSアーキテクチャ構成図
※厳密には Lambda は VPC 内に存在せず、サービス VPC から Hyperplane ENI 経由で接続されますが、分かりやすさのためこのような図にしています。

リソース

  • Lambda関数用 VPC

    • Lambda 関数を作成し、プライベートサブネットに配置
    • S3 ゲートウェイ型エンドポイント
    • API Gateway インターフェース型エンドポイント(※プライベート API エンドポイント/REST API を利用する際に作成)
  • プロキシサーバ用 VPC

    • Lambda関数用 VPC とは別に新たに VPC を作成し、HTTP プロキシサーバ(Squid)を構築
  • VPC ピアリング

    • Lambda 関数用 VPC とプロキシサーバ用 VPC 間で VPCピアリング接続
  • API Gawatey

    • リージョン API エンドポイントタイプ/REST API
    • プライベート API エンドポイントタイプ/REST API
  • S3

    • バケットを作成してオブジェクトを配置

検証ケース概要

Lambda 関数におけるプロキシサーバ利用の動作について、次の観点を検証しました。

  • プロキシサーバ経由でインターネットアクセスが可能か
  • AWS サービス(S3、API Gateway)へのアクセス時に、プロキシをバイパスして VPC エンドポイントを利用できるか

検証用 Lambda 関数の構成

検証用 Lambda 関数では以下の処理を実装しています。
1.リージョン API へアクセスする関数

  • 処理1: S3 バケットへのアクセス
  • 処理2: インターネットへのアクセス
  • 処理3: API Gateway(リージョン API エンドポイント/REST API)へのアクセス

2.プライベート API へアクセスする関数

  • 処理1: S3 バケットへのアクセス
  • 処理2: インターネットへのアクセス
  • 処理3: API Gateway(プライベート API エンドポイント/REST API)へのアクセス

サンプルコード

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
import os
import boto3
import datetime
import urllib.request
from botocore.exceptions import ClientError

# 環境変数から定数を取得
BUCKET_NAME = os.environ.get('BUCKET_NAME', 'XXXXXXX')
SOURCE_KEY = os.environ.get('SOURCE_KEY', 'XXXXXXXX.csv')
API_GATEWAY_URL = os.environ.get('API_GATEWAY_URL', 'https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111')
WEB_URL = os.environ.get('WEB_URL', 'https://www.google.com')

s3_client = boto3.client('s3')

def lambda_handler(event, context):
    try:
        # 1. S3からファイルを読み込み、同じバケットに保存
        print(f"Downloading {SOURCE_KEY} from bucket {BUCKET_NAME}")
        response = s3_client.get_object(Bucket=BUCKET_NAME, Key=SOURCE_KEY)
        file_content = response['Body'].read()

        today = datetime.datetime.now().strftime('%y%m%d')
        destination_key = f'result_{today}.csv'

        print(f"Uploading to {destination_key} in bucket {BUCKET_NAME}")
        s3_client.put_object(Bucket=BUCKET_NAME, Key=destination_key, Body=file_content)
        print("S3 processing completed successfully.")

        # 2. 一般的なWebサイトにHTTPアクセス
        print(f"Accessing web URL: {WEB_URL}")
        try:
            with urllib.request.urlopen(WEB_URL, timeout=5) as web_response:
                if web_response.status == 200:
                    print("Web access successful (200 OK)")
                else:
                    print(f"Web access failed with status code: {web_response.status}")
        except Exception as e:
            print(f"Web access error: {e}")

        # 3. API Gatewayエンドポイントにアクセス
        print(f"Accessing API Gateway URL: {API_GATEWAY_URL}")
        try:
            with urllib.request.urlopen(API_GATEWAY_URL, timeout=5) as api_response:
                if api_response.status == 200:
                    print("API Gateway access successful (200 OK)")
                else:
                    print(f"API Gateway access failed with status code: {api_response.status}")
        except Exception as e:
            print(f"API Gateway access error: {e}")

        return {
            'statusCode': 200,
            'body': 'Lambda function executed successfully.'
        }

    except ClientError as e:
        print(f"AWS ClientError: {e}")
        return {
            'statusCode': 500,
            'body': f"AWS ClientError: {str(e)}"
        }
    except Exception as e:
        print(f"Unexpected error: {e}")
        return {
            'statusCode': 500,
            'body': f"Unexpected error: {str(e)}"
        }

1.リージョン API へアクセスする Lambda 関数

バイパスなし

Lambda 関数の環境変数にHTTP_PROXYHTTPS_PROXYを設定して実行してみます。

  • HTTP_PROXY:http://10.0.0.72:3128
  • HTTPS_PROXY:http://10.0.0.72:3128

新プロキシ-S3パブリックAPIGatewayプロキシ経由

Lambda の実行ログ

START RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX Version: $LATEST
Downloading 8db33a7c-9428-4ff8-8cde-6713298b5685.csv from bucket XXXXXXX
Uploading to result_250525.csv in bucket XXXXXXX
S3 processing completed successfully.
Accessing web URL: https://www.google.com
Web access successful (200 OK)
Accessing API Gateway URL: https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111
API Gateway access successful (200 OK)
END RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX

Squid プロキシのアクセスログ

1748149505.823    135 10.1.143.211 TCP_TUNNEL/200 19109 CONNECT www.google.com:443 - HIER_DIRECT/172.217.31.164 -
1748149507.773   1948 10.1.143.211 TCP_TUNNEL/200 6185 CONNECT <api-id>.execute-api.ap-northeast-1.amazonaws.com:443 - HIER_DIRECT/13.113.254.144 -
1748149511.394   6284 10.1.143.211 TCP_TUNNEL/200 15024 CONNECT XXXXXXX.s3.ap-northeast-1.amazonaws.com:443 - HIER_DIRECT/3.5.158.253 -

結果
S3、インターネット、API Gateway(リージョンAPI エンドポイント/REST API)へのアクセスともにプロキシ経由で通信ができました。

バイパスあり(S3)

Lambda 関数の環境変数にHTTP_PROXYHTTPS_PROXYNO_PROXYAWS_ENDPOINT_URL_S3を設定して実行してみます。

  • HTTP_PROXY:http://10.0.0.72:3128
  • HTTPS_PROXY:http://10.0.0.72:3128
  • NO_PROXY:s3.ap-northeast-1.amazonaws.com
  • AWS_ENDPOINT_URL_S3:https://s3.ap-northeast-1.amazonaws.com

新プロキシパブリックAPIGatewayプロキシ経由

Lambda の実行ログ

START RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX Version: $LATEST
Downloading 8db33a7c-9428-4ff8-8cde-6713298b5685.csv from bucket XXXXXXX
Uploading to result_250525.csv in bucket XXXXXXX
S3 processing completed successfully.
Accessing web URL: https://www.google.com
Web access successful (200 OK)
Accessing API Gateway URL: https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111
API Gateway access successful (200 OK)
END RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX

Squid プロキシのアクセスログ

1748150102.047    150 10.1.143.211 TCP_TUNNEL/200 19169 CONNECT www.google.com:443 - HIER_DIRECT/142.250.207.4 -
1748150102.468    419 10.1.143.211 TCP_TUNNEL/200 6185 CONNECT <api-id>.execute-api.ap-northeast-1.amazonaws.com:443 - HIER_DIRECT/18.176.247.254 -

結果
インターネット、API Gateway(リージョンAPI エンドポイント/REST API)へのアクセスはプロキシ経由で通信ができました。
S3 はバイパスされおり、エンドポイント経由で通信が行えていることが確認できました。

2.プライベート API へアクセスする Lambda 関数

バイパスなし

Lambda 関数の環境変数にHTTP_PROXYHTTPS_PROXYを設定して実行してみます。

  • HTTP_PROXY:http://10.0.0.72:3128
  • HTTPS_PROXY:http://10.0.0.72:3128

新プロキシ-S3APIGatewayプロキシ経由

Lambda の実行ログ

START RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX Version: $LATEST
Downloading 8db33a7c-9428-4ff8-8cde-6713298b5685.csv from bucket XXXXXXX
Uploading to result_250525.csv in bucket XXXXXXX
S3 processing completed successfully.
Accessing web URL: https://www.google.com
Web access successful (200 OK)
Accessing API Gateway URL: https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111
API Gateway access error: <urlopen error Tunnel connection failed: 503 Service Unavailable>
END RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX

Squid プロキシのアクセスログ

1748148591.905    197 10.1.143.211 TCP_TUNNEL/200 19068 CONNECT www.google.com:443 - HIER_DIRECT/172.217.31.164 -
1748148591.910      2 10.1.143.211 TCP_TUNNEL/503 0 CONNECT <api-id>.execute-api.ap-northeast-1.amazonaws.com:443 - HIER_NONE/- -
1748148597.472   6323 10.1.143.211 TCP_TUNNEL/200 14960 CONNECT XXXXXXX.s3.ap-northeast-1.amazonaws.com:443 - HIER_DIRECT/52.219.16.67 -

結果
S3、インターネットアクセスはプロキシ経由で通信ができました。
プロキシサーバーではプライベート API の名前解決ができないため、API Gateway(プライベート API エンドポイント/REST API)は 503 エラーとなりました。

名前解決

curl "https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111"
curl: (6) Could not resolve host: <api-id>.execute-api.ap-northeast-1.amazonaws.com

バイパスあり(S3/API Gateway)

Lambda 関数の環境変数にHTTP_PROXYHTTPS_PROXYNO_PROXYAWS_ENDPOINT_URL_S3AWS_ENDPOINT_URL_API_GATEWAYを設定して実行してみます。

  • HTTP_PROXY:http://10.0.0.72:3128
  • HTTPS_PROXY:http://10.0.0.72:3128
  • NO_PROXY:s3.ap-northeast-1.amazonaws.com,execute-api.ap-northeast-1.amazonaws.com
  • AWS_ENDPOINT_URL_S3:https://s3.ap-northeast-1.amazonaws.com
  • AWS_ENDPOINT_URL_API_GATEWAY:https://execute-api.ap-northeast-1.amazonaws.com

新プロキシ-S3APIGatewayエンドポイント経由

Lambda の実行ログ

START RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX Version: $LATEST
Downloading 8db33a7c-9428-4ff8-8cde-6713298b5685.csv from bucket XXXXXXX
Uploading to result_250525.csv in bucket XXXXXXX
S3 processing completed successfully.
Accessing web URL: https://www.google.com
Web access successful (200 OK)
Accessing API Gateway URL: https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/data?id=111
API Gateway access successful (200 OK)
END RequestId: XXXXXX-XXXX-XXXX-XXXX-XXXXXX

Squid プロキシのアクセスログ

1748149096.716    152 10.1.143.211 TCP_TUNNEL/200 19162 CONNECT www.google.com:443 - HIER_DIRECT/172.217.31.164 -

結果
インターネットアクセスはプロキシ経由で通信ができました。
S3、API Gateway(プライベート API エンドポイント/REST API)のアクセスはバイパスされおり、エンドポイント経由で通信が行えていることが確認できました。

まとめ

Lambda でも環境変数を設定することでプロキシサーバを利用することができます。
さらに、NO_PROXYAWS_ENDPOINT_URLを設定することで AWS サービスへの通信はプロキシをバイパスして VPC エンドポイント経由でアクセスできることが確認できました。
同様の要件をお持ちの方の参考になれば幸いです。

参考

https://docs.aws.amazon.com/ja_jp/sdkref/latest/guide/feature-ss-endpoints.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.