API Gateway+Lambdaでsnsのunsuscribe linkを無効化する === [TOC] ## Lambda関数の作成 API Gateway経由でブラウザのurlから入力されたパラメータをパースしてunsubscribe無効化コマンドを実行 エラーハンドリングとレスポンス本文どこまでこだわるか ### 関数名:ConfirmSubscription ```python= import boto3 import json import logging import re logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): # TODO implement logger.info(json.dumps(event)) url = event['queryStringParameters']['url'] m = re.match(r'https://sns\.(.*?)\..*TopicArn=(.*)', url) if m is None: logger.info('url parameter is wrong. please copy and paste "Confirm subscription" Link URL.') region = m.group(1) topicarn = m.group(2) token = event['queryStringParameters']['Token'] sns = boto3.client('sns', region_name=region) r = sns.confirm_subscription( TopicArn=topicarn, Token=token, AuthenticateOnUnsubscribe='true' ) return { 'statusCode': 200, 'body': json.dumps(r) } ``` ## API Gatewayの作成 ### 初期構築 #### API作成 - 「APIの作成」>「リソース」>「アクション」>「リソースの作成」 API名:DisableUnsubscribingSNSTopic API名:ConfirmSubscription API名:ExecLambda ⇒apiをたたく時のパスを作成 /sns/confirm-subscription?url= - 「APIの作成」>「リソース」>「アクション」>「メソッドの作成」 ⇒apiをたたいた時の処理内容を作成 - GETを選択 ⇒ブラウザのURLバーからのリクエストを想定しているため - メソッドリクエスト 統合タイプ:Lambda関数 Lambdaプロキシ統合の使用:チェックボックスにチェック Lambdaリージョン:ap-northeast-1 Lambda関数:DisableUnsubscribingSNSTopic デフォルトタイムアウトの使用:チェックボックスにチェック リクエストの検証⇒クエリ文字列パラメータおよびヘッダーの検証 URLクエリ文字列パラメータ⇒名前:url、必須:チェックボックスにチェック ⇒GETパラメータ(?url="unsubscribeリンク")がないとエラーにする ARNに表示されるrest-api-id(=lbq0kv0d85)をメモ ARN: arn:aws:execute-api:ap-northeast-1:305017457084:lbq0kv0d85/*/GET/sns - リソースポリシー作成 リクエスト元IP制限を定義 ```json= { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "execute-api:Invoke", "Resource": "arn:aws:execute-api:ap-northeast-1:"awsaccoundid":"rest-api-id"/*", "Condition": { "IpAddress": { "aws:SourceIp": ["111.89.79.227/32", "XXXX"] } } } ] } ``` - APIデプロイ 「APIの作成」>「リソース」>「アクション」>「APIのデプロイ」 デプロイされるステージ:新しいステージ ステージ名:stage ステージの説明:sgate デプロイメントの説明:自由に **※リソースの設定変更やリソースポリシー等の変更を行ったあと、このデプロイをしないと反映されないため注意!!!!!!!!!!!!** - ステージ作成(必要に応じて) 商用環境: prod stage ⇒stageはAPI変更時の試験用 検証環境: dev ⇒後段のlambdaがsnsのapiをたたく時に商用と検証それぞれ分けないといけないから、検証環境用にdevを作成しておく ※API(メソッドリクエストのAPIデプロイ) #### 試験 - メソッドの動作確認 「リソース」>「GET」>「クライアント」のテストを押下 クエリ文字列:url=https://aaa?Topic=cccc&Token=bbbb&Endpoinst=dddd を入力して「テスト」を押下する ⇒Lambda関数にリクエストがいくことを確認 - APIの動作確認 snsトピックを作成し、認証リンクを右クリック>コピー 任意のブラウザのURLバーで以下を入力 ``` https://"rest-api-id".execute-api.ap-northeast-1.amazonaws.com/"stage"/sns/confirm-subscription?url="認証リンク" ``` ⇒正常応答が返ってくることを確認 ※APIの呼び出しURLは「ステージ」エディターの上部に記載されている - エラー応答原因例 {"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1:*:lbq0kv0d85/v3/GET/sns with an explicit deny"} ⇒ポリシーのIP制限でdenyされている {"message":"Missing Authentication Token"} ⇒URLが間違っている(ステージング名のあとにAPIリソース名をいれたらダメ) ⇒APIのデプロイができていない ※リソースポリシー修正後にデプロイした? ※APIに対して想定外のアクセスが来たときは大体このメッセージになる。クライアント証明書を使ってないからとかは関係ない https://qiita.com/akatsukaha/items/08b524e20f7cc5cd8f2d {"message": "Internal server error"} ⇒lambda関数で500エラー、confirm済みのtopicに対してリクエスト投げた時とか ### 維持 #### おれおれhtmlで簡易動作確認ページ作成 ```htmlmixed= <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>takaishi tool v0</title> </head> <body> <h1>検証環境用</h1> <h2>sns email topicの認証&unsubscribeリンクの無効化</h2> <form action="https://lbq0kv0d85.execute-api.ap-northeast-1.amazonaws.com/v1/sns" method="get"> <p>SNS Topinのsubscribeリンクをコピー&ペーストしてください<br> <input type="text" name="url"></p> <button>認証</button> </form> <h2>コンテンツ出し分け動作確認</h2> <form action="https://dddd" method="POST"> <button>曜日別出し分け機能</button> <button>セグメント別出し分け機能</button> <p>セグメント別出し分け機能</p> </form> <h1>商用環境</h1> </body> </html> ```