○○ ができない! IAM ポリシーを確かめよう。実例から学ぶ原因と解決策 〜オペ部だより〜

こんにちは、札幌在住 AWS 事業本部 オペレーション部(通称オペ部)の池田です。オペ部ではクラスメソッドメンバーズにご加入いただいているお客様が直面されたお困りごとや疑問など、様々なお問い合わせに対して各種ドキュメントや技術検証結果のご案内をしたり、場合によっては AWS と連携してお客様が直面している問題解決の支援を行なっています。
本記事では、タイトルにある通り実際にいただいた「○○ ができない」といったお問い合わせの中から IAM ポリシーに原因があったいくつかの事例とその解決策をご紹介したいと思います(今回も全ての事例と原因を網羅できているわけではありませんが、調査方法の参考にしていただけると嬉しいです)。

RDS インスタンスが作成できない

事象

AdministratorAccess、PowerUserAccess 以外の IAM ユーザーで RDS インスタンスを新規作成しようとするとエラーが出る。
付与している権限は以下。

 AmazonRDSFullAccess
 IAMFullAccess
 AmazonVPCFullAccess

FullAccess を許可しているにも関わらず RDS インスタンスが作成できないという問い合わせ事例です。

確認のポイント

まずは対象ユーザーに割り当てられた(アタッチされた)ポリシーを確認しましょう。
例として、AWS ドキュメント Amazon RDS アイデンティティベースのポリシーの例に記載されている「AWS アカウントのユーザーによる DB インスタンスの作成を許可する」というポリシーが割り当てられていると仮定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCreateDBInstanceOnly",
            "Effect": "Allow",
            "Action": [
                "rds:CreateDBInstance"
            ],
            "Resource": [
                "arn:aws:rds:*:123456789012:db:test*",
                "arn:aws:rds:*:123456789012:og:default*",
                "arn:aws:rds:*:123456789012:pg:default*",
                "arn:aws:rds:*:123456789012:subgrp:default"
            ],
            "Condition": {
                "StringEquals": {
                    "rds:DatabaseEngine": "mysql",
                    "rds:DatabaseClass": "db.t2.micro"
                }
            }
        }
    ]
}

この状態でアカウント ID 123456789012 のユーザーが MySQL db.t2.micro インスタンスの作成ができない場合、いくつかの理由が考えられます。

1: DB インスタンス起動可能上限値に達している
2: 対象となる AZ においてキャパシティー不足が発生している
3: ポリシーにタイプミス(typo)がある
4: その他

通常、1 と 2 の場合はコンソールなどにその旨を示すメッセージが表示されるので気づくと思います。また、3 の場合も通常はポリシーエディタにおいて警告が表示されます。しかし今回は、以下のようなエラーが出ていました。

解決策

先のエラーは RDS インスタンスを作成しようとしたアカウントが iam:ListRoles の実行を許可されていないということを示しています。つまり今回の事象は、RDS に関するポリシーではなく IAM に関するポリシーに原因があるということです。さらに調査を進めようとこのアカウントにアタッチされている他のポリシーを確認してみると、このアカウントには「IAM への全ての操作を拒否する」ポリシーがアタッチされている(明示的な拒否がある)ことがわかりました。
IAM では「明示的な拒否」が存在するとそれが優先される仕組みとなっていますから、このポリシーが RDS インスタンスの作成を行う際に必要な iam:ListRoles の実行を拒否していたことが原因であると判明しました。

アカウント内でのリクエストの許可または拒否の決定

適用される明示的な拒否が 1 つでも見つかると、拒否の最終決定が返ります。明示的な拒否がない場合は、コードが続行されます

この「明示的に IAM への全ての操作を拒否する」ポリシーは、組織におけるセキュリティルールや誤操作によるトラブルを回避する目的で作成、アタッチされていたものと推測されます。もしも、適切な許可を付与しているのに目的の操作が実行できず、アクセス権に関するエラーメッセージが表示される場合には「明示的な拒否」がアタッチされていないかについても確認してみましょう。

ネットで見つけたハンズオン教材を安全に実行したい

事象

ネットで見つけた AWS IoT に関するハンズオン教材で学習をしたい。IAM で PowerUserAccess と IAMUserChangePassword のポリシーをアタッチしたが権限不足でエラーとなった。管理者権限は付与せずに、必要最小限の権限を付与したい。
行いたい操作に対して、適切なポリシーが何であるかを知りたいという問い合わせ事例です。「まずは動かしたい!」と管理者権限を付与すると操作ミスなどによる思わぬトラブルの原因につながりますから、権限の付与は慎重に行いたいですよね。

確認のポイント

まずは利用したい教材がどのような内容なのか、どの AWS サービスを利用するのかなどを把握する必要があります。その後、それぞれのサービスに対して適切な権限を付与していくことになります。
対象のウェブサイトに記載されている情報やサンプルコードから、この教材では主に以下のサービスを利用することがわかりました。

  • CloudFormation
  • DynamoDB
  • AWS IoT
  • S3
  • CloudWatch Logs

これらのサービスにおいて、どのようなポリシーがあり、どういった制御が行えるのかを確かめていく必要があります。このような場合にはこのドキュメント IAM と連携する AWS のサービスが役に立つでしょう。

解決策

上記ドキュメントおよびそのリンク先ドキュメントより、例えば CloudFormation であれば次のポリシーが必要とわかりました。

"cloudformation:CreateStack"
"cloudformation:GetStackPolicy"
"cloudformation:DeleteStack"
"cloudformation:DescribeStacks"
"cloudformation:DescribeStackEvents"
"cloudformation:DescribeStackResource"
"cloudformation:DescribeStackResources"
"cloudformation:GetTemplate"
"cloudformation:GetTemplateSummary"
"cloudformation:ListStackResources"
"cloudformation:ListStacks"

参考: AWS Identity and Access Management によるアクセスの制御 AWS CloudFormation API Reference
他のサービスについても同様にポリシーをピックアップし、目的の作業が問題なく実行できるか確認していく必要があります。利用するサービスや内容によっては、なかなかのボリュームになりますがきちんと確認していきましょう。

特定の Git リポジトリのみ利用可能な権限を付与したい

事象

AWS CodeCommit を利用して Git を使ったソース管理を行うためのリポジトリを作成した。特定の IAM ユーザーに対してこのリポジトリのみ自由に利用可能とするポリシーを作成したい。

確認のポイント

このケースは幸い下記 2つのドキュメントで紹介されている情報で解決しました。
AWS CodeCommit: AWS CodeCommit リポジトリへの Read アクセスをプログラムによりコンソールで許可する
AWS CodeCommit のアクセス権限のリファレンス

解決策

具体的には以下のポリシーをベースにします。

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Effect": "Allow",
             "Action": [
                 "codecommit:*"
             ],
             "Resource": "arn:aws:codecommit:<REGION>:<ACCOUNTNUMBER>:<REPO-NAME>"
         },
         {
             "Effect": "Allow",
             "Action": [
                 "codecommit:Get*",
                 "codecommit:BatchGetRepositories",
                 "codecommit:List*"
             ],
             "Resource": "*"
         }
     ]
 }
 

9行目 [Resource] の情報を「特定のリポジトリの ARN」に置き換えます。Action セクションは想定する利用方法に適した内容へ修正します。

特定のユーザーでのみ CloudFront の特定ディストリビューションに対してキャッシュクリアが出来るようにしたい

事象

AWS CLI を利用して CloudFront の特定ディストリビューションに対してキャッシュクリア(オブジェクトの無効化)操作を行うための専用ユーザーを作成し利用したい。

確認のポイント

このケースも対象サービスや実行したいことが明確ですから、素直に AWS ドキュメントを探します。
まず AWS CLI コマンド
ファイルの無効化
create-invalidation

aws cloudfront create-invalidation --distribution-id $CDN_DISTRIBUTION_ID --paths "/*"

次にポリシー
CloudFront でアイデンティティベースのポリシー (IAM ポリシー) を使用する

解決策

このケースでは最終的に以下のポリシーとすることで実現できました。

{ 
"Version": "2012-10-17", 
"Statement": [ 
{ 
"Effect": "Allow", 
"Action": [ 
"cloudfront:ListDistributions", 
"cloudfront:GetInvalidation", 
"cloudfront:CreateInvalidation" 
], 
"Resource": "*" 
} 
] 
}

IAM ポリシーに問題はないのに S3 バケットにアクセスできない

事象

CloudFormation の StackSets を実行したいがエラーとなり完了できなかった。
<エラー内容>

ResourceLogicalId:CFnStackTest, ResourceType:AWS::CloudFormation::Stack, ResourceStatusReason:S3 error: Access Denied For more information check http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html.

確認のポイント

StackSets は、複数の AWS アカウント、リージョンに対し CloudFormation のスタックを作成できる機能です。このケースでは他の AWS アカウント(ターゲットアカウント)に対してスタックを作成しようとしていました。
エラーメッセージによると S3 に対するアクセスが拒否されたことが読み取れます。そのため、S3 へのアクセスがどこで発生しているのかを知るために使用するテンプレートの内容を確認します。すると、別のテンプレートを呼び出す(ネストしている)構成となっていることがわかりました。
バケットポリシーはリソースベースの AWS Identity and Access Management (IAM) ポリシーです。これによってバケットやバケット内のオブジェクトに対するアクセス制御を行なっています。今回の状況からこのバケットポリシーが原因ではないかと推測されました。

解決策

それぞれのテンプレートが格納されている S3 バケットのバケットポリシーを確認したところ、ターゲットアカウントに対してネストされたテンプレート(S3 オブジェクト)の読み取り許可を付与していないことがわかりました。
StackSets を実行するアカウント A(ID: 123456789012)が所有するバケット 123456789012-CFnStackSets に対して、ターゲットアカウント B(ID: 210987654321)が読み取りアクセス(Get アクション)可能とするには以下のようなバケットポリシーが必要でした。

{
    "Sid": "sample",
    "Effect": "Allow",
    "Principal": {
        "AWS": "210987654321"
    },
    "Action": "s3:Get*",
    "Resource": "arn:aws:s3:::123456789012-CFnStackSets/*"
}

番外編

事象

特定の EC2 でだけ S3 オブジェクトに対するアクセスが拒否される。
他の EC2 と同じ仕組みでファイルをアップロード/ダウンロードするようにしているが、該当オブジェクトのみダウンロードできなかった。

確認のポイント

アクセス拒否されていると判断した根拠は下記エラーが表示されたため。

An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

この時点ではアクセスが拒否されたユーザーや、どのような仕組みを利用しているのかなどは不明です。しかし、他の EC2 では問題が起きていないとのことですから、まずは対象の S3 オブジェクトのバケットポリシーを確認してみます。

解決策

結果として、対象のバケットは次のような状況であることがわかりました。

  • バケットポリシーは、アカウント認証が不要で書込み可能としている
  • 対象のオブジェクトには「所有者」での読み出し許可も無い(所有者が設定されていない)
  • このオブジェクトをダウンロードしようとしているユーザーが所有するオブジェクトとして書き込まれておらず、書込の際に権限の設定もしていなかった
  • そのため、対象のオブジェクトはバケット所有者でも読み出す事ができなくなっていた(削除は可能)

S3 へアップロードするときに ACL を指定することで事象の回避が可能となる。

aws s3 mv 〜/file s3://mybucket/file --acl bucket-owner-full-control

このようなご案内を行いましたが、お客様より追加で次のような連絡がありました。

問題のインスタンスについて、クレデンシャル(別AWSアカウントのIAM情報)が保存されておりました。

なるほど、インスタンスに保存されているクレデンシャルが本来利用したかったアカウントのものではなかったことが原因とのことでした。これは AWS CLI を EC2 インスタンス上で利用する際に実行した aws configure で指定された認証情報を指しています。複数の AWS アカウントを利用している場合にはここも確認する必要があるという気付きをくれた事例でした。
参考: 設定ファイルと認証情報ファイル

<追記>
この問題については下記ブログ記事が参考になると思います。ぜひご参照ください。

AWS CLIで使える認証情報とオプションの設定方法まとめ

おわりに

アクセス制御に関わる要素は、利用目的やセキュリティ要件などによって必要な項目は大きく異なります。そのため、昨日公開した記事同様に本記事の内容が役に立たない場面も多数あるものとは認識しています。
ですが、AWS に限らず様々な IT 技術やサービスを利用していく上でアクセス制御や割り当てる権限などは必要不可欠な要素となっています。そのためにも IAM ポリシーは「とりあえずフルアクセス」や「とりあえず Administrator 権限」を付与するようなことはせずに、しっかりドキュメントを確かめて必要最小限の権限付与とするようにしましょう。
本記事内で触れているように IAM ポリシーで制御できる項目は非常に多く、闇雲に調べても目的の権限にたどり着くのは難しいかもしれません。まずは「どのサービスでどんな操作を行いたいか/出来ていないのか」を整理した上でエラーメッセージをしっかり読み、ドキュメントを調査しながら、最初は一番狭い範囲の権限から動作確認を行なって、徐々に権限を追加していく。という方が結果的には近道になるかもしれません。
それでもわからない/エラーが解消できない場合などは、遠慮なくサポートへ問い合わせると良いでしょう。私たちクラスメソッドも、AWS も多くの事例から得たノウハウにより、適切な回答を提供できるはずです。