本記事は 夏休みクラウド自由研究 8/3付の記事です。 |
こんにちは、SCSK齋藤です。
今回は、SQSキューポリシーに明示的な拒否を設定しましたが、考えが甘かったせいで、SQSにアクセスできなくなったお話を書いていきます。
そして、その教訓からIAMのポリシー定義について、再び学びを深めてみたいと思います。
何が起こったか?
SQS→Lambdaへと連携するようなサーバレスアーキテクチャを開発している時に、SQSに次の2点のアクセス制御を実施したいと考えました。
- SQSへメッセージを送受信するリソースを、特定のLambdaのみにしたい
- 人手による運用が入るのを考慮し、マネジメントコンソール経由で全IAMユーザーからのアクセスは許可したい。
そのため、実際に定義したキューポリシーは下記の通りです。
# # ------------------------------------------------------------# # # SQSQueuePolicy # # ------------------------------------------------------------# SQSPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: - !Ref SQS PolicyDocument: Version: "2012-10-17" Statement: #IAMユーザと必要リソース以外のアクセスを拒否 - Effect: Deny Principal: "*" Action: "sqs:*" Resource: !GetAtt SampleSQS.Arn Condition: StringNotEquals: aws:UserAgent: - aws-internal-console ArnNotLike: aws:SourceArn: - !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:sample-lambda-*"
上記ポリシーを設定し、SQSをSAMテンプレートから作成してみましたが、管理者権限を持ったIAMユーザーからでは、マネジメントコンソール上に作成したSQSが表示されません。
なお、CloudShellを開き、SQSのリストをAWS CLIで表示してみたら、リストの一覧には出てきました。
AWS CLI上だけ見えるのも変だと思いながらも、そのままAWS CLIで削除コマンドを実施しましたが、Access Deniedになり、削除できませんでした。
まさしく、八方塞がりな状態でした。。。
暫定対処
上記の状態に陥ったので、ひとまずキューを削除する方法を考えました。
① 特定のLambdaのみからアクセスできるようにする意図で、キューポリシーを書いていたので、そのLambdaからキューを削除することができないか?
→実際に試してみましたが、こちらもAccess Deniedされてしまいました。。なぜだ。。。。
② ルートユーザーから削除できないか?
→こちらは成功いたしました。やはり最後の頼みの綱は、ルートユーザーなんだなと感じました。
キューポリシーを振り返る
一旦削除はできたので、改めて定義したキューポリシーの何がいけなかったのかを考察していきます。
ポイントは、2つです。
IAMユーザーからマネジメントコンソールで閲覧させる権限の記述の誤り
ポリシーの中の、下記が問題でした。
StringNotEquals: aws:UserAgent: - aws-internal-console
こちらを書いた意図としては、IAMユーザーがマネジメントコンソール経由でSQSの操作ができるようにするために記載しました。
元々は、PrincipalをNotPrincipalにする下記の記載方式を検討していましたが、NotPrincipal内ではuserに*は使えないとのことで作成ができませんでした。
NotPrincipal: arn:aws:iam::111122223333:user/*
また、事後調査でわかりましたが、下記のようなドキュメントも見つけたので、NotPrincipalとDenyはそもそも相性が悪いんだということもわかりました。
そのため、チャット式の生成AIに聞いたら、aws:UserAgentを用いた書き方を提案されたので、今回のような書き方をしました。。。
しかし、インターネットで調べてもこのような書き方は出てこないので、嘘情報だったのではと思います。
実際、今回記載した内容は「aws-internal-console」というアプリケーションからのHTTPリクエストという意味になるそうです。
マネジメントコンソール上でHTTPヘッダーを確認しましたが、aws-internal-consoleという情報は出てこなかったです。
これでは、マネジメントコンソールからアクセスできませんね。。。
Denyステートメント内でのLambdaへの権限の記述誤り
Lambdaについては、下記のように記載していました。
ArnNotLike: aws:SourceArn: - !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:sample-lambda-*"
これは、LambdaのARNを指定して、Denyから回避しようとしてました。
しかし、正しくはLambdaにアタッチされているIAMロールをNotとして回避させてあげないといけません。
あくまでLambdaからSQSへ操作する実行主体は、IAMロールなので、それに対する権限の記載をしないといけなかったという訳です。
正しい記載は何か?
いろいろ調査した結果、正しい記載は下記ではないかと考えられます。
{ “Version”: “2012-10-17", “Statement”: [ { “Effect”: “Deny”, “Principal”: “*”, “Action”: “sqs:*“, “Resource”: “arn:aws:sqs:ap-northeast-1:${AWS::AccountId}:SampleQueue”, “Condition”: { “ArnNotEquals”: { “aws:PrincipalArn”: [ “arn:aws:iam::${AWS::AccountId}:user/*“, “arn:aws:iam::${AWS::AccountId}:role/service-role/example-role” ] } } } ] }
ArnNotEqualsの中身は、aws:PrincipalArnで統一をします。
その中で、下記2つを記載して、それぞれのことを実現します。
- “arn:aws:iam::${AWS::AccountId}:user/*“・・・そのアカウント内の全IAMユーザーへのアクセス制御を実現。
- “arn:aws:iam::${AWS::AccountId}:role/service-role/example-role”・・・Lambdaに付与しているIAMロールへのアクセス制御を実現。
今回の教訓
今回アクセス拒否されてしまった事象の教訓としては、下記がございます。
- Lambdaへのアクセス制御は、付与しているIAMロールへのアクセス制御が必要。
・実行権限を付与する主体が何なのかは、今後権限付与する際にしっかり調査する必要があると感じました。 - NotPrincipalとDenyはそもそも相性が悪い。
・AWS側も非推奨としているので、DenyをするならConditionの中にaws:PrincipalArnを書く方法を採用すべきですね。 - ポリシー作成後に検証して動作確認するとはいえ、安易に生成AIのいうことを聞いてはいけない。
・今回は明示的な拒否のため、アクセスできなくなるリスクが孕んでおり、そういう場合には慎重に調査をすべきと感じました。
まとめ
今回は、SQSへのアクセスができなくなった事象についてまとめました。
IAMの記述方式は複雑であり、非常に奥が深いことを再実感しました。
正しい仕様を理解することはやはり重要ですね。