ツー

日常の記録

CloudFront+lambda@edgeでオンデマンドで画像のリサイズしてくれるやつを作る

だいたいはAWSの公式ブログの通り。

上記に書いてなくてハマったことが2点。

bucket policyにGetObjectだけじゃなくてListObjectがないと403が出て混乱する

上記のAWSブログにあるやつを実装してみると404かどうかをチェックしてリサイズの処理を走らせている。

s3のファイルは GetObject だけしかしてないからそれだけ権限あればいいやろーーとs3のbucket policyにそういう設定をすると

data "aws_iam_policy_document" "bucket-policy" {
  statement {
    sid    = "1"
    effect = "Allow"
    actions = [
      "s3:GetObject"
    ]
    resources = [
      "arn:aws:s3:::${var.appid}",
    ]
    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.oai.iam_arn]
    }
  }
}

確実にないファイルを指定しているのにリサイズが動作しない。

なんでやと調べてみるとだいたいクラメソさんが用意してくれてる。たすかる。

ListObject がないとファイルあるかわからんとなって 404 じゃなくて 403 になるらしい。

というわけで下記のように修正。

data "aws_iam_policy_document" "bucket-policy" {
  statement {
    sid    = "1"
    effect = "Allow"
    actions = [
      "s3:GetObject",
      "s3:ListBucket"
    ]
    resources = [
      "arn:aws:s3:::${var.appid}",
      "arn:aws:s3:::${var.appid}/*"
    ]
    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.oai.iam_arn]
    }
  }
}

ちゃんと 404 が出るようになって、スクリプトも動くようになったのでOK。

CloudFormationでlambda@edgeを作ると関数が更新できない

lambda@edgeを使うには、普通にlambdaを作ったうえでCloudFrontのconfigにlambdaのARNを指定するという形になる。なおバージョンを指定しないとだめなので、lambdaを更新するたびにversionを作成してCloudFrontに登録しなおさないといけない。普通のlambdaみたいにdeployして適当に動かすみたいなのができない。

最初はlambda@edgeを作るのにserverless frameworkを使っていたが、lambdaを更新してもversionをアップデートしてCloudFrontを更新してくれない。

で、ドキュメントを見たら

Updates are not supported for this property.

サポートしてないんかい!!

というわけでterraformで書き直した。

terraformでlambdaというと地獄そのものみたいなイメージがあったけど、試してみたら今はそうでもなくなってたっぽい。

data "archive_file" "viewer-request" {
  type        = "zip"
  source_dir  = "../lambda/viewer-request/src"
  output_path = "../lambda/viewer-request/viewer-request.zip"
}

resource "aws_lambda_function" "viewer-request" {
  filename         = data.archive_file.viewer-request.output_path
  function_name    = "${var.appid}-viewer-request"
  role             = aws_iam_role.lambda.arn
  handler          = "handler.viewer_request"
  runtime          = "nodejs14.x"
  memory_size      = 128
  timeout          = 5
  source_code_hash = data.archive_file.viewer-request.output_base64sha256
  publish          = true
}

archive_file というのができてて、パスを指定すればよしなにzipファイルを作ってくれるやつなので terraform apply 以外にやることがなくて楽。ケースによるけどserverless frameworkよりも楽なのでは。

web上の記事ではlambdaの関数作成のみterraformで行って更新はlambrollなどで行うパターンはよく見る。会社等で属人性をなくすのであればそういうことも必要かもしれないけれど、lambda@edgeの関数はそうそう更新しないだろうし、terraformで一括管理でいい気がする。CIとかは必要になったら考えましょう。

まとめ

やっぱり実際やってみるといろいろハマりどころはある。