はじめに
CloudFrontのOrigin Access ControlでLambda Function URLを保護できるようになりました。
Lambda Function URLのアクセス制御は、PublicもしくはIAMによる認証しか選択できないため、この変更によりCloudFront + WAFでより細かくアクセス制御・保護が可能になります。
本記事ではこの設定をTerraformで作成します。
できたもの
variable "stage" { type = string }
variable "prefix" { type = string }
variable "generate_lambda_name" { type = string }
variable "generate_lambda_url" { type = string }
resource "aws_cloudfront_cache_policy" "lambda_origin" {
name = "${var.prefix}-cache-policy-${var.stage}"
min_ttl = 1
max_ttl = 100
default_ttl = 50
parameters_in_cache_key_and_forwarded_to_origin {
cookies_config {
cookie_behavior = "none"
}
headers_config {
header_behavior = "none"
}
query_strings_config {
query_string_behavior = "all"
}
}
}
resource "aws_cloudfront_origin_access_control" "lambda_origin" {
name = "${var.prefix}-oac-${var.stage}"
signing_protocol = "sigv4"
signing_behavior = "always"
origin_access_control_origin_type = "lambda"
}
resource "aws_cloudfront_distribution" "lambda_origin" {
origin {
domain_name = replace(replace(var.lambda_function_url, "https://", ""), "/", "")
origin_id = "LambdaOrigin"
origin_access_control_id = aws_cloudfront_origin_access_control.lambda_origin.id
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
enabled = true
is_ipv6_enabled = true
default_cache_behavior {
target_origin_id = "LambdaOrigin"
viewer_protocol_policy = "allow-all"
allowed_methods = ["HEAD", "DELETE", "POST", "GET", "OPTIONS", "PUT", "PATCH"]
cached_methods = ["HEAD", "GET", "OPTIONS"]
cache_policy_id = aws_cloudfront_cache_policy.lambda_origin.id
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
resource "aws_lambda_permission" "allow_cloudfront" {
statement_id = "AllowCloudFrontServicePrincipal"
action = "lambda:InvokeFunctionUrl"
function_name = var.lambda_name
principal = "cloudfront.amazonaws.com"
source_arn = aws_cloudfront_distribution.lambda_origin.arn
}
ポイントなど
domain_name
について
Lambda Function URLは
https://xxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
の形式で取得できるので、domain_name
にはこれを整形して、
xxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
を渡します。
PUT, POSTメソッドについて
Lambda Function URLでPUT, POSTリクエストを行う際は、x-amz-content-sha256
ヘッダーにペイロードのsha256ハッシュ値を含める必要があります。
(IAM認証情報を使った署名は必要ありません:参考)
今回のようにCloudFront経由でリクエストを行う際も、CloudFrontへのリクエストに同様のヘッダーを含める必要があります。
これがないと以下のように怒られます。
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
}
API Gatewayと最大timeoutについて
今回このCloudFront + Lambda Function URLの構成を検討したきっかけとして、Lambdaの処理時間が長い場合にAPI Gatewayのtimeout制限を手っ取り早く回避したいというものがありました。
最大timeoutはそれぞれ
- Lambda:900秒
- API Gateway:30秒
- CloudFront:60秒(リクエストで180秒まで引き上げ可能)
です。
CloudFrontのクォータはコンソールの「Service Quotas」からは引き上げリクエストできないので、サポートに問い合わせる必要があります。
CloudFrontのクォータ引き上げ時の最大timeoutの180秒について、これを明記しているドキュメントは見当たらなかったのですが、引き上げリクエスト時にサポートに聞いたら180秒がhard limitであると回答をもらいました。