TORIPIYO DIARY

recent events, IoT, programming, security topics

SNSとSQSのクロスアカウント設定(KMSで暗号化)

SNSからメッセージをAWSの別アカウントSQSに送ってKMSで暗号化する設定をしたのでやり方を紹介します。

どういうことか分かりやすく図で書くと、以下のようになります。 AWSアカウントA(111111111111)のSNS(simple-sns)から、AWSアカウントB(222222222222)のSQS(simple-sqs)に対してメッセージを送ってKMS(simple-kms)でメッセージを暗号化してSQSで保持するようにします。

f:id:ha107chan:20210409225546p:plain
Account AのSNSからAccount BのSQSにメッセージを送る

手順

アカウントを跨いだクロスアカウントの設定では、権限設定が複雑になり、各リソース(SNS, SQS, KMS)に対してリソースポリシーを設定する必要があります。各リソースに設定するリソースポリシーの説明も手順と合わせて紹介します。

1. SNSトピックを作成 @AWSアカウントA

AWSコンソールからSNSトピックを作成します。

  • 今回は、standardで作成をしました。FIFOでも大丈夫だとは思いますが、検証はしていません。
  • SNS(simple-topic)のリソースポリシーに設定するstatementは以下です。
    • AWSアカウントB(222222222222) から、simple-sns に対する SNS:Subscribe の許可を設定(余談ですが、SNS:Receive は不要かもしれません。コンソールでポリシーを自動作成した時に付与されたのですが、SNSのドキュメントを見ても SNS:Receive の説明はありませんでした。)
{
  "Sid": "__console_sub_0",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::222222222222:root"
  },
  "Action": [
    "SNS:Subscribe",
    "SNS:Receive"
  ],
  "Resource": "arn:aws:sns:ap-northeast-1:111111111111:simple-sns"
}

2. KMSを作成 @AWSアカウントB

今度は、AWSアカウントBにログインして、SQSでデータ暗号化の時に利用するKMSを作成します。AWS managed keysでも aws/sqs というエイリアス名でSQSのためのKMSがありますがこれは利用しません。なぜなら、AWS managed keysのリソースポリシーは変更することが出来ないので、SNSがKMSを利用できるように設定できないからです。Customer managed keysを使えば、SNSサービスがSQSのデータを暗号化できるポリシーを設定できます。

  • 適当なエイリアス名でCustomer managed keyを作成して、Key policyには以下のstatementを追加しておきます。
    • このstatementによって、SNSはSQSのデータ暗号化(ViaService)をするときに限ってKMSのGenerateDataKey, Decryptアクションを利用できるようになります。
{
    "Sid": "SnsStatement",
    "Effect": "Allow",
    "Principal": {
        "Service": "sns.amazonaws.com"
    },
    "Action": [
        "kms:GenerateDataKey",
        "kms:Decrypt"
    ],
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "kms:ViaService": "sqs.ap-northeast-1.amazonaws.com"
        }
    }
}

3. SQSキューを作成 @AWSアカウントB

AWSアカウントAからのメッセージを受け取るSQSを、AWSアカウントBのコンソールから作成します。

  • sqsの名前は、simple-sqsとします。
  • タイプはスタンダードです。
  • この作成時には、Access policyはデフォルトのままにして変更はしません。後で設定します。
  • Encryptionでは、先ほど作成した Customer managed key の エイリアスを指定します。

4. SQS側でSNSをサブスクライブするように設定 @AWSアカウントB

AWSアカウントBのコンソールから、SNSをサブスクライブするようにSQSを設定します。

  1. SQSの設定画面から、"SNS subscriptions" をクリック
  2. "Subscribe to Amazon SNS topic" をクリック
  3. AWSアカウントAのSNSリソース(simple-sns)のARNを入力

    f:id:ha107chan:20210409225947p:plain
    Account A(111111111111)のSNSのARNを設定

  4. "Save" をクリック

    • Subscribed successfully to topic arn:aws:sns:ap-northeast-1:111111111111:simple-sns と緑色の背景で表示されれば成功です。
    • SQSのAccess Policyには以下のStatementが追加されます。
      • SQSのAccess Policyが変更されていることからわかるように、コンソールでの作業ではSQSの操作権限が必要になります。権限エラーになった場合はより強いSQSの捜査権限をもつIAMユーザで作業するか、権限を付与してもらってください。
{
  "Sid": "topic-subscription-arn:aws:sns:ap-northeast-1:111111111111:simple-sns",
  "Effect": "Allow",
  "Principal": {
    "AWS": "*"
  },
  "Action": "SQS:SendMessage",
  "Resource": "arn:aws:sqs:ap-northeast-1:222222222222:simple-sqs",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:sns:ap-northeast-1:111111111111:simple-sns"
    }
  }
}

5. SNSからメッセージの送信テスト @AWSアカウントA

  • SNSから適当にテストメッセージを作成して送信します。

f:id:ha107chan:20210409230359p:plain
メッセージの送信

6. SQSからメッセージの受信確認 @AWSアカウントB

  • SQSからPoll for messagesを実行してアカウントAのSNSからメッセージが届いていることを確認します。

f:id:ha107chan:20210409230431p:plain
メッセージの受信


正直、各サービスのリソースポリシーにはどんな権限を付与すれば良いのか混乱すると思います。落ち着いてポリシーをよく見ながら設定してみてください。

参考