~~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 実践的}}