🐕‍🦺

[AWS]LambdaからWAFのデフォルトアクションの変更にはLockTokenが必要だった

2025/01/06に公開

概要

AWS Lambdaを実行して、AWS WAFのWeb ACLsのデフォルトアクションをAllowからBlockに変更する関数を作成していた時に発生した。

エラー内容

下記のエラーがLambdaログに出力されていた。
※一部抜粋

"errorMessage": "Parameter validation failed:\nMissing required parameter in input: \"LockToken\"",
"errorType": "ParamValidationError",
File \"/var/task/lambda_function.py\", line 9, in lambda_handler\n    wafv2.update_web_acl

wafv2.update_web_aclを使用する時にパラメータLockTokenが足りないらしい。

エラー調査

AWSのドキュメントを確認。

  • getlistリクエストに対して、リクエスト時のエンティティの状態を示すトークンを返す
  • エンティティの変更には、トークンが必要
  • トークンを使用して、トークンを取得したときから変更がないか確認する
  • 変更があった場合は WAFOptimisticLockException エラーが出力される

https://docs.aws.amazon.com/waf/latest/APIReference/API_UpdateWebACL.html

トークンの取得方法

getリクエスト時にトークンを取得することができるため、get_web_aclを使用する。
LambdaでランタイムPython3.13を使用

import json
import boto3
import os

def lambda_handler(event, context):
    wafv2 = boto3.client('wafv2', region_name='us-east-1') 
    current_acl = wafv2.get_web_acl(Name=os.environ['WEB_ACL_NAME'], Scope='CLOUDFRONT', Id=os.environ['WEB_ACL_ID'])

    print(current_acl)

Lambdaを実行すると、トークンが標準出力されている。
結果を一部抜粋

'LockToken': '0bc7e9ee-40eb-46f9-9834-36bdce01b7b1'

Web ACL更新実装

import json
import boto3
import os

def lambda_handler(event, context):
    wafv2 = boto3.client('wafv2', region_name='us-east-1') 
    current_acl = wafv2.get_web_acl(Name=os.environ['WEB_ACL_NAME'], Scope='CLOUDFRONT', Id=os.environ['WEB_ACL_ID'])

    wafv2.update_web_acl(
        Name=os.environ['WEB_ACL_NAME'],
        Scope='CLOUDFRONT',
        Id=os.environ['WEB_ACL_ID'],
        DefaultAction={'Block': {}},
        VisibilityConfig=current_acl['WebACL']['VisibilityConfig'],
        LockToken=current_acl['LockToken'],
        Description=current_acl['WebACL'].get('Description', ''),
        Rules=current_acl['WebACL']['Rules']
    )

実行ロールには下記ポリシーをアタッチした。
ログ出力のためマネージドポリシー AWSLambdaExecute を別途使用している。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "wafv2:UpdateWebACL",
                "wafv2:GetWebACL"
            ],
            "Resource": "*"
        }
    ]
}

下記二行を記載しない場合は設定したルール、説明がすべて設定なしの状態になるので注意

Description=current_acl['WebACL'].get('Description', ''),
Rules=current_acl['WebACL']['Rules']

Discussion