AmazonSNS でクロスアカウントパブリッシュしてみる

記事タイトルとURLをコピーする

はじめに

最近、巷でマルチアカウント構成が流行ってるということで、マルチアカウント環境を前提とした SNS のクロスアカウントパブリッシュを試します。

前提条件

マルチアカウント環境を前提とします。本記事では便宜上、各アカウントを以下呼称とします。

  • MasterAccount
  • MemberAccount

SNS クロスアカウントパブリッシュの仕組み

SNS に対する操作権限は以下2つのポリシーで制御します。

  • パブリッシャ―の IAM ポリシー
  • SNS アクセスコントロールポリシー

両方でアクションが許可されている時に、SNSのクロスアカウント操作が可能となります。 図で表すと以下です。

f:id:swx-sugaya:20220131193944p:plain

今回は、 SNS でパブリッシュを行うので、2つのポリシーで "SNS:Publish" アクションを許可する必要があります。

トピックへの AWS アカウント アクセスの付与 [中略] これは、Amazon SNS API アクション AddPermission を使用して実行できます。 引用元: https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-access-policy-use-cases.html

検証の構成

上記の仕組みを検証するために、以下の構成でクロスアカウントパブリッシュを試します。

f:id:swx-sugaya:20220131193957p:plain

①Cfnテンプレートを使用して、SNSトピックを作成します。

②CloudshellからCLIをたたいて、SNSトピックへメッセージのパブリッシュを行います。このとき、CloudShell実行IAMユーザが SNS:Publish API コールをできる必要があります。

③SNS が、あらかじめ設定された Eメールエンドポイントへメッセージをサブスクライブします。
このとき、SNS AccessControl Policy がCloudShell実行IAMユーザのSNS:Publish API コールを許可する必要があります。

セットアップ

①SNSトピック作成

本記事の "付録" > "SNS Topic用 Cfnテンプレート" の Cfn テンプレートを使用して、MasterAccount に SNS トピックを作成します。

Cfnコンソールでは、下記テンプレートパラメータを更新してください。

  • CrossAccountAccessID: SNSトピックのパブリッシュを許可する AWS アカウントのカンマ区切りのリスト
  • EndpointEmailAddress: サブスクライブする E メールアドレス

なお、今回作成される SNS AccessControl Policy は、"CrossAccountAccessID" アカウント内の全ての IAM オブジェクトに対して、テンプレート内で作成される SNS トピックをパブリッシュ可能です。

②サブスクリプション有効化

サブスクリプションに登録したメールアドレスでサブスクリプションを有効化にします。

"EndpointEmailAddress" で入力したメールアドレスに SNS からサブスクリプション確認メールが来るので、"Confirm subscription" を押して、サブスクリプションを有効にします。

  • 件名: AWS Notification - Subscription Confirmation

有効になると、SNS コンソール > サブスクリプションタブ > サブスクリプションステータスが "確認済み" になります。

③(オプション)CloudShell用IAMユーザ作成

必要に応じて、以下条件の IAM ユーザを、MemberAccount に作成します。

  • SNS:Publish 権限がある
  • CloudShell の操作権限がある
  • コンソールログイン可能


細かい手順は割愛します。

動作確認

MemberAccount の CloudShell を使って、クロスアカウントパブリッシュのテストを行います。

① SNS:Publish API コールをできる IAM ユーザにより、MemberAccount の CloudSell へログインします。

②ログイン後、以下コマンドを実行します。
{{SNS_TOPIC_ARN}} は、
"Cfn Stack" > "出力タブ" > "OutputsArnforVerifyCrossAccontPublishTopic" から取得した SNS Topic の ARNに置き換えます。

$ aws sns publish --target-arn {{SNS_TOPIC_ARN}} --message "こんにちは、世界!"

参考: https://docs.aws.amazon.com/cli/latest/reference/sns/publish.html

IAM ユーザの権限が足りない場合は、 "Tips" > "パブリッシャー IAM ポリシーの権限不足エラー" のエラーが出ます。

③"EndpointEmailAddress" で入力したメールアドレスにメールが来ていれば完了です。

メールが届かない場合は、本記事の "Tips" > "メール通知のトラシュ" を参考にしてください。

Tips

メール通知のトラシュ

①CW Metrics により、メール通知メトリクスを確認できます。メールが来ない時に確認してください。

  • NumberOfMessagesPublished
  • NumberOfNotificationsFailed など

参考: https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-monitoring-using-cloudwatch.html

②CloudTrail を使ったデバックも可能です

https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-logging-using-cloudtrail.html

パブリッシャー IAM ポリシーの権限不足エラー

パブリッシャーにIAM が設定されていない場合、以下エラーが表示されます。

An error occurred (AuthorizationError) when calling the Publish operation: User: arn:aws:iam::xxxx is not authorized to perform: SNS:Publish on resource: arn:aws:sns:xxx because no resource-based policy allows the SNS:Publish action

付録

SNS Topic用 Cfnテンプレート

作成されるリソース:

  • SNS Topic
  • SNS AccessControl Policy
Parameters:
  EndpointEmailAddress:
    Description: Input distination email address.
    Type: String
  CrossAccountAccessID:
    Description: Input AWS Account ID you want to allow access to. e.g. 12345678xxxx, 23456789xxxx
    Type: CommaDelimitedList

Resources:
  VerifyCrossAccontPublishTopic:
    Type: AWS::SNS::Topic
    Properties: 
      Subscription: 
        - Endpoint: !Ref EndpointEmailAddress
          Protocol: EMAIL
      TopicName: !Sub topic-verify-crossaccount-publish-${AWS::AccountId}
      Tags:
        - Key: Use
          Value: Verify
        - Key: CfnStackName
          Value: !Ref AWS::StackName
  VerifyCrossAccontPublishTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties: 
      PolicyDocument: 
        Statement: 
          - Sid: crossAccountAccess
            Effect: Allow
            Principal:
              AWS: !Ref CrossAccountAccessID
            Action:
              - sns:Publish
            Resource: !Ref VerifyCrossAccontPublishTopic
      Topics: 
      - !Ref VerifyCrossAccontPublishTopic

Outputs:
  OutputsNameforVerifyCrossAccontPublishTopic:
    Value: !GetAtt VerifyCrossAccontPublishTopic.TopicName
  OutputsArnforVerifyCrossAccontPublishTopic:
    Value: !Ref VerifyCrossAccontPublishTopic

参考:

AWS::SNS::Topic - AWS CloudFormation

AWS::SNS::TopicPolicy - AWS CloudFormation

菅谷 歩 (記事一覧)