Amazon SNS でプライベートエンドポイントに メッセージを送信してみた

AWS ナレッジセンターの内容をやってみました
2022.12.20

はじめに

アノテーション株式会社の hato です。

Amazon SNS から HTTP または HTTPS エンドポイントに送信されるメッセージは、パブリック IP アドレスが送信元となるため、プライベートエンドポイント(プライベートサブネット内のエンドポイント)にメッセージを送信したい場合は、 Lambda 関数などを経由する必要があります。

Lambda 関数を利用する方法は AWS ナレッジセンターにて公開されていますが、実際に構築したことはなかったのと、お問い合わせ頂いた際に備えて画面キャプチャを取得するため、やってみました。

なお、プライベートサブネット内から Amazon SNS にメッセージを送信する方法は次のブログとなります。

やってみた

前提

  • SNS トピックは作成済
  • メッセージ受信用にプライベートサブネットに EC2 を作成、受信アプリ配置済み

構成イメージ

手順

  1. セキュリティグループの作成
  2. IAM ロールの作成
  3. Lambda 関数のコード作成
  4. Lambda 関数の作成
  5. SNS トピックの作成
  6. テスト

セキュリティグループの作成

Lambda 関数に設定するセキュリティグループを作成します。
Amazon VPC コンソール のナビゲーションペインから「セキュリティグループ」を選択して、「セキュリティグループを作成」を選択します。

次の値を指定して「セキュリティグループを作成」を選択します。

  • セキュリティグループ名:任意の名前(例:LambdaSG
  • VPC:プライベートエンドポイントの VPC

セキュリティグループが正常に作成されたことを確認します。

IAM ロールの作成

Lambda に設定する IAM ロールを作成します。
VPC に接続する Lambda は通常の Lambda 関数の権限に加えて、追加の権限が必要となります。
今回は必要な権限をまとめた AWS 管理ポリシーAWSLambdaVPCAccessExecutionRoleを使用します。

IAM コンソール を開き、ロールから「ロールを作成」をクリックします。

信頼されたエンティティタイプに「AWS のサービス」、ユースケースに「Lambda」を選択して、「次へ」をクリックします。

許可ポリシーからAWSLambdaVPCAccessExecutionRoleを選択して、「次へ」をクリックします。

ロール名に任意の名前(例:lambda_vpc_basic_execution)を指定して、「ロールを作成」をクリックします。

IAM ロールが正常に作成されたことを確認します。

Lambda 関数のコード作成

Amazon SNS をトリガーに Lambda 関数が実行された場合に、プライベートエンドポイントにリクエストを送信するサンプルコードを作成します。

作業用のディレクトリを作成します。

$ mkdir my-sourcecode-function
$ cd my-sourcecode-function

エディタで次のサンプルコードを作成します。
※5行目はプライベートエンドポイントの URL に修正してください。

lambda_function.py

import json
import requests
 
def lambda_handler(event, context):
    url = "<PRIVATE_HTTP/S_ENDPOINT_URL>"
 
    sns_message_payload = event["Records"][0]["Sns"]
 
    sns_message_headers = {
        "x-amz-sns-message-id": sns_message_payload['MessageId'],
        "x-amz-sns-message-type": sns_message_payload["Type"],
        "x-amz-sns-subscription-arn" : event["Records"][0]["EventSubscriptionArn"],
        "x-amz-sns-topic-arn" : sns_message_payload["TopicArn"]
    }
 
    try:
        r = requests.post(url = url, data = json.dumps(sns_message_payload), headers = sns_message_headers)
    except Exceptions as e:
        print(e)
 
    print(r.content)
 
    return {
        'statusCode': 200,
        'body': json.dumps(r.content)
    }

pipで周辺モジュールをインストールして、ZIP圧縮します。

$ pip install --target ./package requests
...(中略)...
Successfully installed certifi-2022.12.7 charset-normalizer-2.1.1 idna-3.4 requests-2.28.1 urllib3-1.26.13

$ cd package
$ zip -r ../my-deployment-package.zip .
...(中略)...
  adding: urllib3/poolmanager.py (deflated 71%)
  adding: urllib3/_collections.py (deflated 69%)

$ cd ..
$ zip -g my-deployment-package.zip lambda_function.py
  adding: lambda_function.py (deflated 75%)

Lambda 関数の作成

プライベートエンドポイントにリクエストを送信する Lambda 関数を作成します。

Lambda コンソールを開き、関数から「関数の作成」をクリックします。

次の値を指定し、「▼詳細設定」を選択します。

  • 関数名:任意の名前(例:Private-endpoint-Amazon-SNS-topic-subscription
  • ランタイム:Python 3.8
  • デフォルトの実行ロールの変更:既存のロールを使用する
    • 作成した IAM ロールを指定(例:lambda_vpc_basic_execution

次の値を指定して「関数の作成」を選択します。

  • VPC を有効化:有効
    • VPC:プライベートエンドポイントの VPC
    • サブネット:プライベートサブネットを指定
    • セキュリティグループ:作成したセキュリティグループを指定(例:LambdaSG

Lambda 関数の作成中は設定変更ができないためしばらく待ちます。

Lambda 関数が正常に作成されたことを確認します。

作成したサンプルコードを設定します。 「アップロード元」から「.zipファイル」を選択

手順3で作成したサンプルコード(ZIP)を選択します。

コード変更の警告です。「OK」を選択します。

次の手順で必要になるため Lambda 関数の ARN をメモします。

エンドポイントのサブスクライブ

Amazon SNS コンソール のナビゲーションペインから「サブスクリプションの作成」を選択します。

次の値を指定して「サブスクリプションの作成」を選択します。

  • トピック ARN:関連付けを行う SNS トピックを選択
  • プロトコル:AWS Lambda
  • エンドポイント:Lambda 関数の ARN を指定

サブスクリプションが正常に作成されたことを確認します。

メッセージの通知確認

「メッセージの発行」を選択します。

テストメッセージを入力して「メッセージの発行」を選択します。

エンドポイントにメッセージが配信されました。

{
  "Type": "Notification",
  "MessageId" : "22b80b92-fdea-4c2c-8f9d-bdfb0c7bf324",
  "TopicArn" : "arn:aws:sns:ap-northeast-1:123456789012:hato-sns-topic",
  "Subject": "hato-test-title",
  "Message": "hato-test-Message",
  "Timestamp" : "2012-05-02T00:54:06.655Z",
  "SignatureVersion": "1",
  "Signature" : "EXAMPLEw6JRN...",
  "SigningCertURL" : "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-f3ecfb7224c7233fe7bb5f59f96de52f.pem",
  "UnsubscribeURL" : "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:123456789012:hato-sns-topic:d6a4f408-4021-4e66-82e3-920cb71bb5fe"
  "MessageAttributes": {}
}

最後に

この記事が誰かのお役にたてば幸いです。

参考資料

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。