📝

Lambda Function URL で簡単に Slack の bot 作成

2023/12/18に公開

シンプルフォームのエンジニアの杉です。本記事は SimpleForm Advent Calendar 2023 の 18 日目の記事です。

この記事では AWS の Lambda 関数で使用することのできる Lambda Function URL について書きたいと思います。

Lambda Function URL とは

Slack などのサービスから簡単に Lambda 関数を invoke したいと思ったことはないでしょうか?このような場面で便利なものが Lambda Function URL です。

今までは、 Lambda 関数の AWS 認証なしの HTTPS 経由で実行をするには、Lambda 関数の前段に Amazon API Gateway を設置する必要がありました。この構造でも不便はないのですが、より簡単に実装できるようになったものが Lambda Function URL です。

Lambda Function URL は特定の URL を叩くだけで Lambda 関数を動かすことができます。

実装方法

Terraform を用いて設定をする場合は、こちらのドキュメントを参考にします。 Lambda 関数を作成する際に以下のものを追加するだけで可能です。

resource "aws_lambda_function_url" "default" {
  function_name      = aws_lambda_function.default.function_name
  authorization_type = "NONE"
}

authorization_type は "NONE" を指定するとパブリックな URL になります。誰でも叩けてしまう URL となってしまうため、機密性の高いものなどには使用しないようにしましょう。
もし、認証された IAM ユーザのみにアクセスを制限する場合には "AWS_IAM" を指定します。

作成された URL はコンソール上から確認することができます。この URL を使用することで簡単に Lambda を invoke することが可能になります。

Slack との組み合わせ例

この Lambda Function URL を用いた活用方法として、 Slack との組み合わせがあります。例えば、投稿された内容に対して何かしら反応をする bot などを実現することが可能になります。

また、 Slack には Slash command というメッセージ投稿フォームからアプリを呼び出すことができる機能があります。authorization_type を "NONE" にすることでパブリックな URL になってしまいますが、Slash commandには Slack API からのリクエストであるかの検証をする仕組みが存在します。こちらを利用することで、想定外のリクエストなどは弾くことが可能になります。詳細につきましてはぜひこちらを一読していただければと思います。

Python で実装をする場合は、以下のような処理を行うことで検証が可能です。

def verify_slack_request(event: dict, slack_signing_secret: str) -> bool:
    """
    Slackからのリクエストかどうかを検証する
    """
    timestamp = event["headers"]["x-slack-request-timestamp"]
    body = event["body"]
    if event["isBase64Encoded"]:
        body = base64.b64decode(body).decode("utf-8")

    sig_basestring = f"v0:{timestamp}:{body}".encode("utf-8")
    slack_signing_secret = bytes(slack_signing_secret, "utf-8")

    my_signature = "v0=" + hmac.new(
        slack_signing_secret, sig_basestring, hashlib.sha256
    ).hexdigest()

    result = hmac.compare_digest(my_signature, event["headers"]["x-slack-signature"])
    return result

これを用いることで Slack からのリクエストであるということが判定できました。
以下のように実装をすることで、リクエストの検証ができた場合のみにおうむ返しでテキストを投稿するということが実現できます。

def handler(event, context):
    body = b64decode(event.get("body")).decode()
    request_body = parse.parse_qs(body)
    response_url = request_body["response_url"][0]
    text = request_body["text"][0]

    if verify_slack_request(event, SLACK_KEY):
        payload = {
            "text": text,
            "color": "good",
            "response_type": "in_channel",
        }
        requests.post(response_url, data=json.dumps(payload))

さいごに

今回は、Lambda を invoke する手段のひとつとして Lambda Function URL をご紹介しました。簡単な bot などを作ってみたい時にぜひ試してみてください。

最後まで読んでいただきありがとうございます。明日以降も SimpleForm Advent Calendar は続きますのでよろしくお願いします。

また、シンプルフォーム株式会社では大規模言語モデルに関する輪読会も開催をしています。気になった方は覗いてみてください!

大規模言語モデル入門・輪読会 #1

シンプルフォーム株式会社 の全ての求人一覧

SimpleForm 採用お問い合わせフォーム

SimpleForm カジュアル面談お申込みフォーム

Discussion