背景
多くのSaaSサービスはセキュリティのため、接続元IPアドレス制限を設けています。
通常はEC2など固定IPを持つリソースから接続することで対応できますが、VPC Lambdaは送信元IPを固定できないという課題があります。
今回、Athenaカスタムコネクタ(Lambda)からSaaSに接続する必要がありましたが、接続元IPを固定できないため通常の方法ではアクセスが許可されません。
今回対応した要件、設計方針、構成図、実装をまとめましたのでご参考になればと思います。
要件
- 接続先のSaaSは、接続元IPアドレスによる制御を前提にしている
- LambdaからSaaSへ接続する(今回はAthenaカスタムコネクタのLambdaを使用しました)
- 通信経路はプロキシサーバー(Squid)を経由する
設計方針
通常であればEC2からアクセスに対して、Squidで IPアドレスを条件にしたACL(アクセスコントロールリスト) を設定します。
しかし、Lambda単体ではIPが固定できない問題があります。
NAT Gatewayを経由することでLambdaのIPを固定させる方法もありますが、今回はLambdaのIPを固定するではなく、Squidのアクセス制御機能を利用するように設計しました。
Squidで最も知られているACLはIPアドレスフィルターですが、アクセス制御機能の中には、リクエストヘッダに含めた固有文字列を条件にアクセス制御を行う方法もあります。以下、概要図です。
- Lambda側
リクエスト送信時に、固有の文字列を特定ヘッダーに付与するようにコードを追加します。文字列はSquid側と一致する文字列であれば何でも可能ですが、今回の例では、"X-Lambda-Test": "test"で設定します。 - Squid側
squid.conf内でそのヘッダを検知し、条件に一致した場合のみホワイトリストを適用し、SaaSエンドポイントへアクセスを許可します。 - SaaS側
プロキシサーバーのGlobal IPに対して接続許可するよう設定します。そうすることでLambdaからのアクセスを許可します。
これにより、接続元IPが固定されていなくても固有リクエストヘッダの有無でアクセスを制御できます。
全体構成図
実装する機能は、Amazon AthenaのカスタムコネクタであるLambdaからSquidプロキシサーバーを経由してSaaSに接続し、データを取得してS3に格納する機能です。
この記事は、Lambdaに対するSquidのアクセス制御がメインとなるため、下記の実装コードはその部分を中心に記載します。
実装
Lambda側(pythonコード)
一般的なLambdaやAthenaカスタムコネクタからのHTTPリクエスト送信となります。
import urllib3
import json
PROXY_URL = "http://プロキシCLBのFQDN:80"
PROXY_HEADERS = {
"X-Lambda-Test": "test"
}
TARGET_URL = "https://SaaS側のAPIエンドポイント"
def lambda_handler(event, context):
http = urllib3.ProxyManager(proxy_url=PROXY_URL, proxy_headers=PROXY_HEADERS)
response = http.request("GET", TARGET_URL)
以下省略
上記コードを既存のLambdaコードに追加して、responseを加工(statusCodeやbodyから中身を取得)すればよいです。
ポイントとしては、
- 全体構成図でも確認できますが、今回プロキシサーバーはCLB配下2台構成となっているため、PROXY_URLはCLBのFQDN(xxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com)に指定する必要があります。
- 固有ヘッダーをPROXY_HEADERSに付与し、TARGET_URL(SaaSエンドポイント)へリクエスト送信する流れとなります。
- 上記コードはわかりやすく解説するためコードの中にヘッダ値を直書きしていますが、本来であれば環境変数やSecrets Managerで管理することを推奨します。
Squid側
Lambdaからの通信を受け、固有ヘッダを検知した場合のみSaaS宛通信を許可します。設定する内容は、SquidプロキシサーバーのSquid.conf、whitelistに記述します。
/etc/squid/squid.conf
# Lambdaが付与するカスタムヘッダをACLに登録
acl allowed_lambda_header req_header X-Lambda-Test test
http_access allow allowed_lambda_header
proxy_protocol_access allow allowed_lambda_header
# ホワイトリストの設定
acl whitelist_lambda dstdomain "/etc/squid/whitelist_lambda"
http_access allow whitelist_lambda
/etc/squid/whitelist
# 接続先のSaaS側のドメイン名を入力。以下は例です。
.microsoft.com
.windows.com
.windowsupdate.com
上記設定を既存のSquid設定に加えます。
ポイントとしては、
- req_headerを利用し、Lambdaからのリクエストに固有ヘッダ(X-Lambda-Test: test)が含まれる場合のみ通信を許可します。
- whitelist_lambdaに定義したドメイン名のみ通信を許可します。そうすることで許可されたドメイン宛(SaaSエンドポイントなど)のみ通信することができます。
- 固有ヘッダー+ドメインホワイトリストの組み合わせで、不要なアクセスや不正利用を防止できます。
まとめ
- VPC Lambdaは送信元IPを固定できないため、SaaSのIP制限に直接対応できない
- NAT GatewayでIP固定する方法もあるが、今回は Squidのヘッダベースアクセス制御 を活用
- 固有リクエストヘッダ + ドメインホワイトリストの二段階制御により、安全かつ柔軟にSaaS接続が可能
おわりに
今回紹介した方法は、
- 「LambdaからSaaSへ安全に接続したい」
- 「IPアドレス制御だけに頼れない環境でアクセス制御したい」
といったケースに応用できます。
特に、複数Lambdaやマルチアカウント構成でNAT Gatewayを増やしたくない場合にも有効だと考えます。
今後も、クラウドアーキテクチャの工夫や実践的なTipsを発信していきますので、同じような課題を持つ方の参考になれば嬉しいです。