Tech Racho エンジニアの「?」を「!」に。
  • インフラ

Lambda@Edgeを使うとき、デフォルトで作成されるIAMロールは権限が足りないので注意

PoCを作るのにマネジメントコンソールからLambda@Edgeを設定したら、しょうもないところでハマったので記録を残しておきます。

TL;DR

デフォルトで作成されるIAMロールにはus-east-1だけのCloudWatchLogs権限が許可されますが、Lambda@Edgeで使うなら他のリージョンも許可する必要がありました。

こんなことをやりました

Lambda関数の作成

Lambda@Edgeで使うときは東京に作ってはダメで、バージニアに作るんですよね、知ってる知ってる。

デフォルトで適切な権限のIAMロールを作ってくれそうなのでおまかせします。

できたので関数の中身は適当に書きます。console.log()でログだけは出しておきます。書いたらバージョンを発行するのを忘れない。

CloudFrontディストリビューションへの紐づけ

適当にディストリビューションを作成し、オリジン設定で作成したLambdaを紐づけます。バージョン付き(末尾が:1とか)のARNを記載しないとエラーになります。

おや、エラーがでました。先程のLambdaと一緒に作成されたIAMロールがlambda用になっているので、edgelambdaを追加しろと言っています。

Lambdaのページを開いて、そこからロール設定を開きます。

信頼ポリシーを書き換えます。

変更前

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
      }
  ]
}

変更後

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "Service": [
                  "lambda.amazonaws.com",
                  "edgelambda.amazonaws.com"
              ]
          },
          "Action": "sts:AssumeRole"
      }
  ]
}

これで無事にディストリビューションは作成できました。

問題

実行してみるとエラーが起きたり、(オリジンやらどこにLambda@Edgeを設定するかなどの状況によっては)エラーは起きないけどログが保存されなかったりします。

原因と対応

Lambda@Edgeは、アクセスしたユーザの最寄りのエッジロケーションで実行され、ログは近いリージョンのCloudWatch Logsに転送されます。

僕は日本にいるので、東京リージョンにログを保存したいけど、先程自動生成されたIAMロールをよく見るとバージニアにしか保存できないようになっていました。

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Action": "logs:CreateLogGroup",
          "Resource": "arn:aws:logs:us-east-1:(アカウントID):*"
      },
      {
          "Effect": "Allow",
          "Action": [
              "logs:CreateLogStream",
              "logs:PutLogEvents"
          ],
          "Resource": [
              "arn:aws:logs:us-east-1:(アカウントID):log-group:/aws/lambda/mytest:*"
          ]
      }
  ]
}

これが原因でログが保存されなかったりエラーになっているようです。

ということで、以下のようにResource制限を緩めたら無事に動作し、東京リージョンのCloudWatch Logsでログも見られるようになりました。ロググループ名が他リージョンでは /aws/lambda/us-east-1.関数名 といった感じのプレフィックスがついたものになるので、リージョン部分を * にするだけでは足りないという点に注意してください。

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Action": "logs:CreateLogGroup",
          "Resource": "arn:aws:logs:*:(アカウントID):*"
      },
      {
          "Effect": "Allow",
          "Action": [
              "logs:CreateLogStream",
              "logs:PutLogEvents"
          ],
          "Resource": [
              "arn:aws:logs:us-east-1:(アカウントID):log-group:/aws/lambda/mytest:*"
              "arn:aws:logs:*:(アカウントID):log-group:/aws/lambda/us-east-1.mytest:*"
          ]
      }
  ]
}

初歩的なことなのですが、最近のAWSはずいぶんと親切になっているので、デフォルトおまかせでそれなりに動くだろうと思ったらここはちょっと不親切でした。通常Lambdaのロールとしては完全に正しいのですが、最初にLambdaを作るときに、「これはLambda@Edge用です」みたいなチェックボックスを入れたら全リージョンに保存できるIAMロールが自動生成される...とかだと初見の人により優しくなりそうですね。今後に期待。

関連記事

S3 Static Website Hostingで重複スラッシュがあると404になる挙動をnginxで再現する

AWS SDK Rubyで標準出力へログが出るのを抑制する


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。