課題
以下の構成でAWSリソースを作ろうとしています。
-
AWS CDK (typescript)
- AWS のリソースをコードで管理したい
-
Lambda
- FastAPI 製の API を提供したい
-
API Gateway
- API のエンドポイントとして提供したい
- Lambda で提供する機能をプロキシしたい
- API Key を設定して、アクセスを制限したい(Lambda 内でやってもいいが、できれば API Gateway で弾いておきたい…)
上記の構成を取りたい場合、以下の構成を取るのが自然です。
const mainApi = new RestApi(this, `Api`, {
// ...一部設定を省略
defaultCorsPreflightOptions: {
allowOrigins: Cors.ALL_ORIGINS,
allowMethods: Cors.ALL_METHODS,
allowHeaders: Cors.DEFAULT_HEADERS,
statusCode: 200,
},
});
const backendResource = mainApi.root.addResource("main");
const backendResourceProxy = backendResource.addProxy({
defaultIntegration: mainBackendIntegration, // FastAPI を mangum 経由で提供している Lambda
anyMethod: true,
defaultMethodOptions: { apiKeyRequired: true},
});
const apiKey = mainApi.addApiKey("ApiKey", {
apiKeyName: `example-api-key`,
});
const plan = mainApi.addUsagePlan("UsagePlan", {
name: `example-api-usageplan`,
});
plan.addApiKey(apiKey);
plan.addApiStage({ stage: mainApi.deploymentStage });
しかしながら、 apiKeyRequired: true
を指定しているため、OPTIONS もAPIキーが必須となってしまっています。
OPTIONS メソッドは認証を切っておかないと、CORS 検証時のプリフライトリクエストでコケるという話があります[1]。
実際、筆者も何度か同様の問題でハマってきました。
通常、API Gateway に関数を追加する場合、1つのメソッドに対して Lambda Integration を割り当てるというやり方をしますが、今回は裏側でリクエストを解釈したいため、どうしてもプロキシを通したいのです。
しかし、ドキュメントを見ても OPTIONS のみ apiKeyRequired
を切るというパラメータはありませんでした。
AWS の UI コンソール上で手動で切るとこの問題は解決するのですが…できれば取りたくない手段です。
解決策
anyMedhod: true
とせずに、一つ一つ必要なメソッドを追加することで解決できます。
const backendResourceProxy = backendResource.addProxy({
defaultIntegration: props.mainBackendIntegration,
anyMethod: false,
defaultMethodOptions: { apiKeyRequired: false},
});
backendResourceProxy.addMethod("GET", props.mainBackendIntegration, {apiKeyRequired: true})
backendResourceProxy.addMethod("POST", props.mainBackendIntegration, {apiKeyRequired: true})
今回は、API 内に GET と POST しかないので、2つのみを追加しました。
ドキュメントを眺めていたら、addProxy
メソッドで返される ProxyResource
に addMedhod
があることがわかり、これを使うことで GET も POST も FastAPI で設定したパスにリクエストを通すことができるようになりました。
また、OPTIONS の認証設定が外れたので、課題だった CORS のプリフライトリクエストが通らない問題も解決しました。
その他のメソッドが必要な場合も同様に追加していくことで対応できそうです。