VPC LambdaでHTTPプロキシとVPCエンドポイントを両立できるか試してみた
こんにちは。テクニカルサポートチームのShiinaです。
はじめに
企業のセキュリティポリシーによってインターネットへのアクセスが制限されている環境では、プロキシサーバを利用することがあります。
EC2 ではなく、AWS Lambda のようなサーバーレス環境でもプロキシサーバは利用できるのか気になったので試してみました。
さらに、S3 や API Gateway など AWS サービスへの通信はプロキシをバイパスして VPC エンドポイント経由でアクセスできるのかについても検証してみました。
セキュリティと利便性の両立に悩んでいる方の参考になれば嬉しいです。
結論
Lambda 関数の環境変数にHTTP_PROXY
、HTTPS_PROXY
を設定することで HTTP プロキシサーバを利用することができます。
HTTP_PROXY:http://<ProxyServerIP>:<Port>
HTTPS_PROXY:http://<ProxyServerIP>:<Port>
さらに、NO_PROXY
とAWS_ENDPOINT_URL_S3
、AWS_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 間はピアリング接続を行い、相互通信を可能にします。
構成図
※厳密には 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_PROXY
、HTTPS_PROXY
を設定して実行してみます。
HTTP_PROXY:http://10.0.0.72:3128
HTTPS_PROXY:http://10.0.0.72:3128
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_PROXY
、HTTPS_PROXY
、NO_PROXY
、AWS_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
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_PROXY
、HTTPS_PROXY
を設定して実行してみます。
HTTP_PROXY:http://10.0.0.72:3128
HTTPS_PROXY:http://10.0.0.72:3128
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_PROXY
、HTTPS_PROXY
、NO_PROXY
、AWS_ENDPOINT_URL_S3
、AWS_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
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_PROXY
とAWS_ENDPOINT_URL
を設定することで AWS サービスへの通信はプロキシをバイパスして VPC エンドポイント経由でアクセスできることが確認できました。
同様の要件をお持ちの方の参考になれば幸いです。
参考