VPoTの岩本 (iwamot) です。
この記事では、AWS Lambdaを使わずにサーバーレスな処理を実装する、いわゆる「Lambdaレス」な実装の例をご紹介します。具体的には「AWSサービスのIPレンジ変更を検知し、AWS WAFのIPセットを自動更新してみた」例です。
Lambdaレスな考え方は、AWS Summit Japan 2024のセッション「サーバーレス開発のベストプラクティス ~より効果的に、より賢く使いこなすために~」(動画、資料)で取り上げられ、注目されています。*1
いざ実装してみると、Lambda関数の保守がいらなくなるメリットが大きく感じられました。
Lambdaレス以前の実装例
AWSは、AWSサービスのIPレンジ変更を検知し、AWS WAFのIPセットを自動更新するサンプルとして、下記のGitHubリポジトリを公開しています。
いずれも、IPレンジ変更が通知されるSNSトピック (arn:aws:sns:us-east-1:806199016981:AmazonIpSpaceChanged
) にサブスクライブしたLambda関数で、IPセットを更新する実装です。
+-----------------+ +----------------+ | Lambda | | | | Execution Role | +--->+AWS WAF IPv4 Set| +--------+--------+ | | | | | +----------------+ | | +--------------------+ +--------+--------+ | |SNS Topic +--->+ Lambda function +----+ |AmazonIpSpaceChanged| +--------+--------+ | +--------------------+ | | +----------------+ | | | | v +--->+AWS WAF IPv6 Set| +--------+--------+ | | | CloudWatch Logs | +----------------+ +-----------------+
https://github.com/aws-samples/aws-waf-ipset-auto-update-aws-ip-ranges
+-----------------+ +---------------------+ | Lambda | | | | Execution Role | +--->+AWS WAF IPv4/IPv6 Set| +--------+--------+ | | | | | +---------------------+ | | +--------------------+ +--------+--------+ | |SNS Topic +--->+ Lambda function +----+ |AmazonIpSpaceChanged| +--------+--------+ | +--------------------+ | | +-------------------+ | | | | v +--->+AWS VPC Prefix List| +--------+--------+ | | | CloudWatch Logs | +-------------------+ +-----------------+
これらのサンプルを活用してもよいのですが、できればLambdaレスにして、保守の手間をなくしたいですよね。
Lambdaレスな実装例
どうしたらよいのか、ぼくなりに考えて出た答えが下記でした。
- IPセットの更新にStep Functionsを利用
- トリガーにSQSとEventBridge Pipesを利用
以下、説明します。
IPセットの更新にStep Functionsを利用
IPセットの更新は、AWS WAFのUpdateIPSet APIを呼び出して実行します。
Lambdaレスで呼び出す手段として、ぼくはStep FunctionsのAWS SDK統合を選びました。具体的なワークフローは下記の通りです。
{ "Comment": "Updates WAFv2 IP set with latest Route 53 health check IP ranges when AWS IP ranges change.", "StartAt": "Parallel", "States": { "Parallel": { "Branches": [ { "StartAt": "GetManagedPrefixListEntries", "States": { "GetManagedPrefixListEntries": { "End": true, "Parameters": { "PrefixListId": "pl-xxxxxxxxxxxxxxxxx" }, "Resource": "arn:aws:states:::aws-sdk:ec2:getManagedPrefixListEntries", "Type": "Task" } } }, { "StartAt": "GetIPSet", "States": { "GetIPSet": { "End": true, "Parameters": { "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "Name": "my-ip-set", "Scope": "CLOUDFRONT" }, "Resource": "arn:aws:states:::aws-sdk:wafv2:getIPSet", "Type": "Task" } } } ], "Next": "UpdateIPSet", "Type": "Parallel" }, "UpdateIPSet": { "End": true, "Parameters": { "Addresses.$": "$[0].Entries[*].Cidr", "Id.$": "$[1].IpSet.Id", "LockToken.$": "$[1].LockToken", "Name.$": "$[1].IpSet.Name", "Scope": "CLOUDFRONT" }, "Resource": "arn:aws:states:::aws-sdk:wafv2:updateIPSet", "Type": "Task" } } }
マネージドプレフィックスリストを参照しているのは、今回の要件が「Route 53ヘルスチェックで使われるIPv4レンジをIPセットとして提供すること」だったためです。pl-xxxxxxxxxxxxxxxxx
で com.amazonaws.<region>.route53-healthchecks
を参照し、エントリをAWS WAFのIPセットにコピーしています。
Step FunctionsではHTTPリクエストも可能です。今回は試していませんが、Lambdaレス以前の実装のように、https://ip-ranges.amazonaws.com/ip-ranges.json を参照するワークフローも可能でしょう。
ちなみに、UpdateIPSetの前にGetIPSetしているのは、その順で呼び出す仕様だからです。詳しくはUpdateIPSet APIのドキュメントをご覧ください。
トリガーにSQSとEventBridge Pipesを利用
ここまでできれば、あとはSNSとStep Functionsをつなぐだけです。SNSトピックに直接Step Functionsをサブスクライブできるとよいのですが、現時点ではできません。
今回は「SNS → SQS → EventBridge Pipes → Step Functions」とつないでみました。EventBridge Pipesは、まさにこのような統合に使えるサービスです。
https://aws.amazon.com/jp/eventbridge/pipes/
おわりに
以上、Lambdaレスな実装例をご紹介しました。Lambdaを「SQS → EventBridge Pipes → Step Functions」で置き換えているため複雑に見えるかもしれませんが、実際にはワークフローを組み立ててサービスをつないでいくだけです。
実装してみて、Lambda関数の保守がいらなくなるメリットが大きく感じられました。今後も、Lambdaレスな実装をまず考えるようにします。
*1:2024年8月23日から24日にかけて開催されるイベント「JAWS PANKRATION 2024」でも、AWSコミュニティビルダーの鈴木さんが「What is "Lambdaless" serverless?」を発表予定です。