~~NOCACHE~~
## プライベートAPIGatewayを異なるアカウントから呼び出す
サーバーレスを勉強中に、[[https://dev.classmethod.jp/articles/private-api-is-not-private-for-you/|classmethod]]さんの記事を見て、え?そうなの?と思って試してみた。
イメージは以下の感じで、プライベートAPIGatewayを作成したアカウントAからは勿論、異なるアカウントBからもアクセスさせたい。
ついでにLambdaからのプライベートAPIGateway呼び出しも試してみた
{{:Aws:APIGateway:pasted:20210509-223334.png?direct 900x0}}
アカウントBのRoute53にアカウントAで作成したAPIGatewayのエンドポイントを、ホストゾーンとレコード追加して
アカウントBで作成したVPCエンドポイントのDNS名と紐づけることで、アカウントBからアカウントAで作成したプライベートAPIGatewayの呼び出しが可能となりました。
VPCエンドポイントで「*.execute-api.ap-northeast-1.amazonaws.com」がワイルドカードで登録されるので
Route53を登録しなくてもプライベートAPIGatewayのURL形式であればエンドポイントに接続されました。
### アカウントAでの環境準備
各リソースの作成手順は割愛します、重要な設定値のみです。
#### APIGatewayの作成
以下の設定値でAPIGatewayを作成。
・エンドポイントタイプ:プライベート
・ID:xxxx
・メソッド:GET
・タイプ:Lambda関数
・ドメイン:https://xxxx.execute-api.ap-northeast-1.amazonaws.com
・ステージ:test
・リソースポリシー:下記の通りvpcidを指定してアクセス許可を設定(参考:https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-vpc-endpoint-policies.html)
事前にアカウントBのVPCIDも登録しています。
※プライベートAPI Gatewayの送信先IPアドレス制限は意味がない(0.0.0.0/0をDenyしてもリクエストできます。)→VPCで送信元偽れますもんね、よく考えたらそらそうか・・・。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:ap-northeast-1:1234567890:xxxx/*"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:ap-northeast-1:1234567890:xxxx/*",
"Condition": {
"StringNotEquals": {
"aws:SourceVpc": [
"vpc-xxxxa",
"vpc-xxxxb"
]
}
}
}
]
}
#### APIGatewayから呼び出されるLambda関数
def lambda_handler(event, context):
return {
'isBase64Encoded': False,
'statusCode': 200,
'headers': {},
'body': {"message": "Hello from AWS Lambda"}
}
#### APIGatewayを呼び出すLambda関数
エンドポイント経由でアクセスするため、VPC、サブネット、セキュリティグループを指定して作成します。
指定したリソースは下記として説明します。
・VPC:vpc-xxxxa
・サブネット:Lambda-subnet
・セキュリティグループ:Lambda-sg
import urllib.request
import json
def lambda_handler(event, context):
url = "https://xxxx.execute-api.ap-northeast-1.amazonaws.com/test/"
response = urllib.request.urlopen(url)
content = json.loads(response.read().decode('utf8'))
return content
#### VPCエンドポイントの作成
VPCに設置したLambdaがプライベートAPIGatewayに到達できるようにVPCエンドポイントを作成します。
VPCエンドポイントは、Lambdaからhttpsのインバウンドを許可する必要があります。
指定したリソースは下記になります。
・サービス名:com.amazonaws.ap-northeast-1.execute-api
・VPC:vpc-xxxxa
・サブネット:Lambda-subnet
・セキュリティグループ:Vpcendpoint-sg(Lambda-sgをソースとしたhttpsのインバウンドを許可する)
#### アカウントAでの実行結果
以上でアカウントAの環境は整ったので、「APIGatewayを呼び出すLambda関数」を実行します。
実行結果は以下の通りで、LambdaからAPIGatewayが呼び出せました。
{{:Aws:APIGateway:pasted:20210511-172054.png?direct}}
### アカウントBでの環境準備
各リソースの作成手順は割愛します、重要な設定値のみです。
#### APIGatewayを呼び出すLambda関数
これかアカウントAとソースコードは変わりません。
指定したリソースは下記として説明します。
・VPC:vpc-xxxxb
・サブネット:Lambda-subnet
・セキュリティグループ:Lambda-sg
import urllib.request
import json
def lambda_handler(event, context):
url = "https://xxxx.execute-api.ap-northeast-1.amazonaws.com/test/"
response = urllib.request.urlopen(url)
content = json.loads(response.read().decode('utf8'))
return content
#### VPCエンドポイントの作成
VPCに設置したLambdaがプライベートAPIGatewayに到達できるようにVPCエンドポイントを作成します。
VPCエンドポイントは、Lambdaからhttpsのインバウンドを許可する必要があります。
指定したリソースは下記になります。
・サービス名:com.amazonaws.ap-northeast-1.execute-api
・VPC:vpc-xxxxb
・サブネット:Lambda-subnet
・セキュリティグループ:Vpcendpoint-sg(Lambda-sgをソースとしたhttpsのインバウンドを許可する)
#### アカウントBでの実行結果
以上でアカウントBの環境は整ったので、「APIGatewayを呼び出すLambda関数」を実行します。
実行結果は以下の通りで、アカウントAと同様にLambdaからAPIGatewayが呼び出せました。
{{:Aws:APIGateway:pasted:20210511-172137.png?direct}}
### まとめ
[[https://dev.classmethod.jp/articles/private-api-is-not-private-for-you/|classmethod]]さんの記事は正しかった。
AWS のプライベートネットワーク内においては特に制限をしない限り、誰でもアクセスできる API Gateway です。←まさにこれでした。
### その他
LambdaからAPIGatewayの呼出し方は下記のスクリプトでも良いかもメモ
import urllib3
import json
def lambda_handler(event, context):
url = "https://xxxx.execute-api.ap-northeast-1.amazonaws.com/test"
http = urllib3.PoolManager()
response = http.request("GET",url)
content = json.loads(response.data.decode("utf-8"))
return content
{{tag>AWS APIGateway 実践的}}