SNSデッドレターキュー(DLQ)にSQSを設定した際に権限エラーがコンソール上で起こる

Amazon SNSにデッドレターキューとしてSQSを設定できるのですが、SQSに対して謎の(?)権限エラーが出たので調査してみました。


現象

Amazon SNSのデッドレターキューとしてSQSを指定し、SQSにはアクセスポリシーを適切に設定したにも関わらず、SNSコンソール上で「デッドレターキュー(Redrive ポリシー)アクセス許可」という権限エラーが出る。



Amazon SNS デッドレターキュー (DLQ)とは

Lambda, SQSなどにもデッドレターキューは設定できますが、要は正常に動作しないときのメッセージを送信し貯めておくキュー といったものです。

docs.aws.amazon.com


SNSでは、トピックからサブスクリプション(サブスクライバ)に対して、(指定した回数のリトライを通して)正常にメッセージが送れなかった場合の送信先として指定できます。


SNS デッドレターキューの設定手順

  1. SNSトピックを作成する
  2. LambdaやSQSをSNSサブスクリプションとして登録する
  3. その際に指定できるサブスクリプションデッドレターキューにSQSを指定する
    • SNSRedrive ポリシー (デッドレターキュー)にSQSのARNを指定する
  4. そのSQSには、SNSからアクセスできるように適切なアクセスポリシーを設定する

SNSのデッドレターキューは、サブスクリプションごとの設定になります。


SQS アクセスポリシー

SQSであったりLambdaやCloudWatch LogsにS3、様々なリソースに対してアクセス権限を設定することができます。

これらのように、リソースに対して設定する権限(ポリシー)のことを、「リソースベースポリシー」といいます。

このリソースに対して、「誰(アクター)が」「何ができる」といった権限設定になります。

※「誰が」に関して、プリンシパルという呼び方が正しいかもしれませんが、ここではわかりやすくアクターと呼んでいます。


一方で、リソースに対してではなく、アクターに対して設定する権限(ポリシー)をアイデンティティベースポリシー」といいます。

こちらは恐らくAWSを触っているとほとんどの方が触れているであろうIAMポリシーなどが該当します。

このアクターは、「何(リソース)に」「何ができる」といった権限設定になります。


SQSに対して設定するポリシー、すなわちSQSにおける「リソースベースポリシー」は、「アクセスポリシー」と呼ばれます。


「アクセスポリシー」は、IAMポリシードキュメントなどと同じように以下のようなjsonで表します。

(※CloudFormationなどで作成する場合はyamlでも記入できますが、コンソール上ではjsonで出力されます。)

{
  "Version": "2012-10-17",
  "Id": "TestGotoTopicToDLQPolicy",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "sns.amazonaws.com"
      },
      "Action": "SQS:SendMessage",
      "Resource": "arn:aws:sqs:ap-northeast-1:123456789012:test-goto-dlq",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:sns:ap-northeast-1:123456789012:test-goto-topic"
        }
      }
    }
  ]
}


AWSによるSNSのデッドレターキューの公式ドキュメントにも、上記の記入のような例が挙げられています。

docs.aws.amazon.com


要は以下のような許可ポリシーになります。

  • SNSsns.amazonaws.com)が(=Principal)
  • このSQSに対して(=Resource)
  • SQS:SendMessageが行える(=Action)
  • このような条件下で
    • アクセスされる際のソースのARNが指定したSNSトピックのARNのとき


しかし・・・

上記のように、公式ドキュメントに沿ったアクセスポリシーを付与したSQSを、SNSサブスクリプションデッドレターキューに指定したにも関わらず、SNSのコンソール上のサブスクリプションページにて以下のようなエラーが出力されます。


デッドレターキュー (Redrive ポリシー) アクセス許可

Amazon SQS キューのアクセス許可を確認できませんでした。キューが存在し、アカウントにキューの属性を読み取るアクセス許可があることを確認してください。Amazon SNS トピックが Amazon SQS キューにメッセージを送信できるようにするには、Amazon SQS キューポリシーを作成する必要があります。


何度もポリシーを確認してミスがないことを確認したり、少しずつポリシーを変えたりして試しても、一向にエラーメッセージは消えません。


動作させてみると・・・

「もう全然わからん!」となって、試しにデッドレターキューのSQSにメッセージがいくかどうかのテストをしてみました。


具体的には、SNSサブスクリプションとして登録した Lambdaのリソースベースポリシーを空にし(今まではSNSからアクセスできるようにしていた)、わざとSNSからLambdaへのアクセスを失敗させて、デッドレターキューのSQSにメッセージがいくようにしました。

その状態でSNSトピックにメッセージを発行すると、デッドレターキューに指定したSQSまでメッセージが伝達されます(アクセスポリシーが正しければ)。


上記のような設定をしてSNSにメッセージを発行しました。

すると、、、


デッドレターキューのSQSにメッセージが到達しました!!!


どうやら

上記の通り、SQSのアクセスポリシーに関するエラーが表示されていても動作はするようです。

つまり、気にしなくていい?特に間違った設定はしていない?ということになるのでしょうか。


まあそこで色々と調べてみたら、案の定同じ現象に陥った方がいらっしゃって、さらにはAWSのサポートにまで問い合わせて下さっている方がいました。

I've reached out to AWS Support, and it's a known UI issue. And as of now, there is still no ETA confirmed for the fix.


どうやら、既知のUIの問題(修正予定のない)だそうです。

amazon web services - AWS SNS Topic Sub: Dead-letter queue (redrive policy) permissions denied - Stack Overflow

amazon web services - How to add a Redrive policy to an SNS with an encrypted DLQ - Stack Overflow


また、エラーが出なくなるための方法も載っておりました。

"Principal": {
  "Service": "sns.amazonaws.com"
},

こちらを

"Principal": "*",

こうか

"Principal": {
  "AWS": "*"
},

こうすると良いそうです。


エラーが出なくなった!!

上記の通りにアクセスポリシーを書き換えてみると、確かにエラーメッセージが出なくなりました!!

どちらのパターンでもエラーが出なくなり、そこから元のポリシーに戻すと再度エラーが出るようになることを確認しました。


最後に

こういった些細なエラーで、かつ修正されないようなものも、割とAWSのような大規模なサービスでも(むしろだからこそ?)あるようです。

確かに公式ドキュメントの些細なミスとかも、指摘をしても中々直してもらえなかったりとかはありますね・・・


とりあえず今回の件は動作はできるので、そのままでいってみることにします。

(実は今回これらのリソースはserverless frameworkで生成していてSQSのアクセスポリシーが自動で生成されていて、手を加えて余計なポリシーリソースを増やしたくなかったため。。。)