アクセス拒否エラーメッセージにポリシータイプが記載されるようになったが VPC エンドポイントポリシーとクロスアカウントの場合はどうだ(メッセージに要注意)

「because no resource-based policy allows the xxx action」と表示された時、あなたが見るべきはリソースベースポリシーではないかも知れません。

コンバンハ、千葉(幸)です。

先日、一部の AWS サービスにおいてアクセス拒否エラーメッセージにエラー原因のポリシータイプが記載されるようになりました。興奮冷めやらない方も多いかと思います。

上記のエントリではアイデンティティ(ID)ベースポリシー、Permissions boundary、リソースベースポリシーが原因の場合のメッセージを確認しました。ドキュメントの記載から、 Organizations SCP も問題なく記載されそうです。

ここで気になっているのが VPC エンドポイントポリシーの場合はどうかという点です。また、クロスアカウントアクセスで許可不足の場合はどうなるのか、というのも気になります。

なので、今回はその 2 点を確認してみました。

まとめ

  • VPC エンドポイントポリシーが原因のアクセス拒否はきちんとその旨メッセージに記載される
  • クロスアカウントアクセスで許可が不足している場合、原因がアイデンティティベースポリシーであっても「リソースベースポリシーで許可がない」と記載されることがある

後者は #2 を表します。この状態でアイデンティティベースポリシーに許可があればアクションは成功しますが、エラーメッセージには「because no resource-based policy allows...」と記録されます。

# ID ベースポリシー リソースベースポリシー 結果 エラーメッセージに記載されるタイプ
1 許可あり 許可あり 許可 なし
2 許可 なし アカウント単位で許可 暗黙的な拒否 リソースベースポリシー
3 許可 なし IAMエンティティ単位で許可 暗黙的な拒否 ID ベースポリシー
4 許可あり 許可 なし 暗黙的な拒否 リソースベースポリシー
5 許可 なし 許可 なし 暗黙的な拒否 リソースベースポリシー
6 拒否 許可あり 明示的 な拒否 ID ベースポリシー
7 許可あり 拒否 明示的 な拒否 リソースベースポリシー
8 拒否 拒否 明示的 な拒否 ID ベースポリシー

アクセス拒否エラーメッセージにポリシータイプが記載される AWS サービス

現時点で公式の情報で「アクセス拒否エラーメッセージにポリシータイプが記載されるサービス」として確認できているのは以下です。

  • Amazon Sagemaker
  • AWS CodeCommit
  • AWS Secrets Manager

( AWS CodeBuild も対応していることはたまたま確認できました。他にも対応サービスはあるかと想像します。)

都合が良いことに VPC エンドポイントポリシーは AWS CodeCommit で、クロスアカウントアクセスは AWS Secrets Manager で対応しているのでそれぞれを用いて確認してみます。

VPC エンドポイントポリシーによる拒否の場合

今回はこういった構成で試してみます。

VPC 上の EC2 インスタンスに IAM ロール(インスタンスプロファイル)をアタッチし、 CodeCommit へのアクセスに必要な権限を与えます。CodeCommit 向けの VPC エンドポイントを作成し、そのエンドポイントポリシーでアクセス可否をコントロールします。

ちなみに、サービスが VPC エンドポイントに対応しているか・エンドポイントポリシーに対応しているかは以下から確認できます。(ゲートウェイ型を除く)

成功する場合

先に問題なく成功するパターンを見ておきます。VPC エンドポイントポリシーはフルアクセスを設定します。

sh-4.2$ aws codecommit get-repository --repository-name test-repo
{
    "repositoryMetadata": {
        "repositoryName": "test-repo",
        "cloneUrlSsh": "ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/test-repo",
        "lastModifiedDate": 1637664560.916,
        "repositoryId": "8bbc9f6d-ad0c-4896-8ad3-2bf4ca24b6d4",
        "cloneUrlHttp": "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/test-repo",
        "creationDate": 1637664560.916,
        "Arn": "arn:aws:codecommit:ap-northeast-1:000000000000:test-repo",
        "accountId": "000000000000"
    }
}

test-repoという CodeCommit レポジトリの情報を取得しています。

暗黙的な拒否の場合

VPC エンドポイントポリシーを以下のように設定します。

VPCエンドポイントポリシー

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "NotResource": "arn:aws:codecommit:ap-northeast-1:000000000000:test-repo",
            "Principal": "*"
        }
    ]
}

test-repoNotResource で指定しているため、当該レポジトリへの許可がない状態です。

この状態でアクションを実行するとアクセス拒否エラーが出ます。

sh-4.2$ aws codecommit get-repository --repository-name test-repo

An error occurred (AccessDeniedException) when calling the GetRepository operation: User: EC2 のロールセッション名 is not authorized to perform: codecommit:GetRepository on resource: arn:aws:codecommit:ap-northeast-1:000000000000:test-repo because no VPC endpoint policy allows the codecommit:GetRepository action

because no VPC endpoint policy allows the codecommit:GetRepository actionというメッセージが含まれており、VPC エンドポイントポリシーが原因であることが読み取れます。

明示的な拒否の場合

VPC エンドポイントポリシーを以下のように変更し、test-repoへのアクセスを明示的に拒否します。

VPCエンドポイントポリシー

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": "*",
            "Principal": "*"
        },
        {
            "Action": "codecommit:Get*",
            "Effect": "Deny",
            "Resource": "arn:aws:codecommit:ap-northeast-1:000000000000:test-repo",
            "Principal": "*"
        }
    ]
}

この状態でアクションを実行すると明示的な拒否を表すメッセージが表示されます。

sh-4.2$ aws codecommit get-repository --repository-name test-repo

An error occurred (AccessDeniedException) when calling the GetRepository operation: User: EC2 のロールセッション名 is not authorized to perform: codecommit:GetRepository on resource: arn:aws:codecommit:ap-northeast-1:000000000000:test-repo with an explicit deny in a VPC endpoint policy

with an explicit deny in a VPC endpoint policyのメッセージより、VPC エンドポイントによる明示的な拒否であることが読み取れます。

VPC エンドポイントポリシーによる拒否の場合、エラーメッセージにきちんと表示されることが分かりました。

クロスアカウントアクセスでの拒否の場合

続いて以下の構成で、クロスアカウントアクセスにおけるエラーメッセージを確認します。

Secrets Manager access denied

クロスアカウントアクセスを可能とするためにはリソースベースポリシーを設定する必要があり、リソースベースポリシーを設定できるリソースを含むサービスは以下から確認できます。

EC2 インスタンスにアタッチした IAM ロール(インスタンスプロファイル)のアイデンティティベースポリシーと Secrets Manager シークレットのリソースベースポリシーの設定値を適宜変更しエラーメッセージを確認します。

今回は以下のパターンで試行します。

# ID ベースポリシー リソースベースポリシー 結果
1 許可あり 許可あり 許可
2 許可 なし アカウント単位で許可 暗黙的な拒否
3 許可 なし IAMエンティティ単位で許可 暗黙的な拒否
4 許可あり 許可 なし 暗黙的な拒否
5 許可 なし 許可 なし 暗黙的な拒否
6 拒否 許可あり 明示的 な拒否
7 許可あり 拒否 明示的 な拒否
8 拒否 拒否 明示的 な拒否

1. 両方で許可ありの場合

エラーメッセージの確認という主旨からは外れますが、成功するパターンを見ておきます。

シークレットのリソースベースポリシーは以下のように設定しました。

リソースベースポリシー

{
  "Version" : "2012-10-17",
  "Statement" : [ {
    "Effect" : "Allow",
    "Principal" : {
      "AWS" : "arn:aws:iam::000000000000:root"
    },
    "Action" : "secretsmanager:*",
    "Resource" : "*"
  } ]
}

今回は検証のため広めに許可していますが、実際に使用する場合には以下を参考に最小限の許可を検討してください。

必要な許可を持つ EC2 インスタンス上から AWS CLI でアクセスを試みると、問題なく内容を参照できました。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma
{
    "Name": "test-secret",
    "VersionIdsToStages": {
        "318122af-3e89-4d43-9fbb-214cda4a6fa4": [
            "AWSCURRENT"
        ]
    },
    "Tags": [],
    "LastChangedDate": 1637666381.449,
    "CreatedDate": 1637666037.494,
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma"
}

(ちなみにこのシークレットはデフォルト KMS キーで暗号化しているのですが、describe-secret ではそちらのキーポリシーは考慮しなくてよいことを初めて知りました。)

2. リソースベースポリシーでアカウント単位の許可の場合

今回の一番の注意ポイントです。

シークレットのポリシーは先ほどと同じ状態(アカウント全体を許可)で、IAM ロールからsecretsmanager:*の許可を取り除きます。

この状態でアクションを試みると……

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma because no resource-based policy allows the secretsmanager:DescribeSecret action

because no resource-based policy allows the secretsmanager:DescribeSecret actionとなり、アイデンティティベースポリシーが原因であるのにも関わらず「リソースベースポリシーで許可がない」と表示されています。

何も知らない状態でこのメッセージを見るとリソースベースポリシーばかりをチェックしてしまいそうですが、クロスアカウントアクセスの場合には原因がアイデンティティベースポリシーの場合もある、と覚えておくと役に立つかも知れません。

3. リソースベースポリシーで IAM エンティティ単位の許可の場合

IAM ポリシー側では許可がないままで、シークレットのポリシーを以下に変更します。

リソースベースポリシー

{
  "Version" : "2012-10-17",
  "Statement" : [ {
    "Effect" : "Allow",
    "Principal" : {
      "AWS" : "EC2のIAMロールのARN"
    },
    "Action" : "secretsmanager:*",
    "Resource" : "*"
  } ]
}

↑アカウント全体の許可ではなく、IAM ロールの ARN に絞って許可を与えます。

この状態でアクションを実行します。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:114186211244:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma because no identity-based policy allows the secretsmanager:DescribeSecret action

because no identity-based policy allows the secretsmanager:DescribeSecret actionとなり、アイデンティティベースポリシーが原因であるとされます。

クロスアカウントアクセスにおいてはアカウント単位の許可でも IAM エンティティ単位の許可でも評価論理には差異がないですが、エラーメッセージには差異が現れてくるのが面白いところです。

4. リソースベースポリシーの許可なしの場合

アイデンティティベースポリシー側で必要な許可を設定し直し、リソースベースポリシーを削除します。

その状態でアクセスを試みると、#2 と同じエラーメッセージが表示されました。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma because no resource-based policy allows the secretsmanager:DescribeSecret action

5. 両方で許可なしの場合

アイデンティティベースポリシー側でも許可を取り除き、どちらでも許可がない状態でアクセスを試みます。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma because no resource-based policy allows the secretsmanager:DescribeSecret action

こちらも #2 と同じメッセージが表示されました。

クロスアカウントアクセスにおける暗黙的な拒否はどちらかと言うと「リソースベースポリシー側の許可なし」に寄せてメッセージが表示されるようです。

6. アイデンティティベースポリシーで明示的な拒否の場合

流石に明示的な拒否の場合はきちんと原因を教えてくれるだろうということで、IAM ロールに以下のポリシーを追加でアタッチします。

アイデンティティベースポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "secretsmanager:*",
            "Resource": "*"
        }
    ]
}

シークレット側のリソースベースポリシーは許可を与えるよう設定を戻しています。

その状態で再度アクションを実行します。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma with an explicit deny in an identity-based policy

with an explicit deny in an identity-based policyというメッセージが返され、アイデンティティベースポリシーによる明示的な拒否であることがきちんとわかりました。

7. リソースベースポリシーで明示的な拒否の場合

続いてリソースベースポリシー側での拒否を行います。以下に変更しました。

リソースベースポリシー

{
  "Version" : "2012-10-17",
  "Statement" : [ {
    "Effect" : "Deny",
    "Principal" : {
      "AWS" : "arn:aws:iam::000000000000:root"
    },
    "Action" : "secretsmanager:*",
    "Resource" : "*"
  } ]
}

アイデンティティベースポリシー側の明示的の拒否は外し、許可を与え直しています。その状態でアクションを実行します。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma with an explicit deny in a resource-based policy

with an explicit deny in a resource-based policyとなり、リソースベースポリシーが原因であることがきちんと示されています。

ちなみにアイデンティティベースポリシー側で許可がない(アイデンティティベースポリシーとしては暗黙的な拒否)の場合でも上記のメッセージが表示されます。エラーメッセージにおいても明示的な拒否の方が優先されるということのようです。

8. 両方で拒否の場合

最後に、明示的な拒否をアイデンティティベースポリシーとリソースベースポリシー両方で設定するとどうなるか?という確認です。

sh-4.2$ aws secretsmanager describe-secret --secret-id arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma

An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: EC2 のロールセッション名 is not authorized to perform: secretsmanager:DescribeSecret on resource: arn:aws:secretsmanager:ap-northeast-1:99999999999:secret:test-secret-ngu7Ma with an explicit deny in an identity-based policy

with an explicit deny in an identity-based policyが表示されました。アイデンティティベースポリシーが勝ちました!


冒頭のまとめに記載した通り、各パターンでのエラーメッセージの表示は以下のようになりました。

# ID ベースポリシー リソースベースポリシー 結果 エラーメッセージに記載されるタイプ
1 許可あり 許可あり 許可 なし
2 許可 なし アカウント単位で許可 暗黙的な拒否 リソースベースポリシー
3 許可 なし IAMエンティティ単位で許可 暗黙的な拒否 アイデンティティベースポリシー
4 許可あり 許可 なし 暗黙的な拒否 リソースベースポリシー
5 許可 なし 許可 なし 暗黙的な拒否 リソースベースポリシー
6 拒否 許可あり 明示的 な拒否 ID ベースポリシー
7 許可あり 拒否 明示的 な拒否 リソースベースポリシー
8 拒否 拒否 明示的 な拒否 ID ベースポリシー

終わりに

アクセス拒否エラー発生時のエラーメッセージに記録されるポリシータイプについて確認してみました。

個人的には VPC エンドポイントポリシーがきちんと記録されるのが意外でした。大きな括りではリソースベースポリシーに属しており、以下のポリシータイプで独立して定義されているわけではないからです。

きちんとメッセージに表示してくれるのは嬉しいですね。

そしてクロスアカウントの場合はなかなか難しい挙動でした。#2、#5 の場合はリソースベースポリシーが原因であると記載されますが、アイデンティティベースポリシーが(あるいは「も」)原因です。

この仕様が今後も、あるいは他のサービスでも同様であるかは分かりませんが、メッセージをそのまま信じてはいけないと覚えておくと役立つかもしれません。

以上、 チバユキ (@batchicchi) がお送りしました。