PrincipalにAWSアカウントを指定したら「許可」じゃなくて「委譲」だった件

#aws #iam #terraform

TL;DR

  • AWSのポリシーってむずいよな
  • よく使うポリシーにはリソースベースアイデンティティベースの2種類があるで
  • 単一のアカウント内であれば、どちらか一方で許可されていたらアクセスは許可されるで
  • 明示的な拒否がある場合は直ちにアクセスが拒否されるで
  • リソースベースのポリシーのPrincipalにアカウントを指定しても、アカウント全体を無条件に許可するわけじゃないで

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

アイデンティティベースのポリシーとは、IAMユーザーやIAMロールにアタッチするポリシーのこと。

例えると・・・ 山田くん(IAMユーザーまたはロール)に対して、社員証(IAMポリシー)を渡す(アタッチする)と、山田くんはオフィス(リソース)に入る(アクセスする)ことができる

S3のmy-bucketの読み取りを許可するIAMポリシーの例

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]
    }
  ]
}

リソースベースのポリシー

リソースベースのポリシーとは、S3やSQSといったリソースにアタッチするポリシーのこと。

例えると・・・ オフィス(リソース)のドアに許可リスト(リソースポリシー)を貼っておくと、リストに載っている山田くん(プリンシパル)はオフィスに入る(アクセスする)ことができる

S3バケットにアタッチするバケットポリシーの例

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/yamada"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

で、アクセスできるかどうかはどう決まるん?

AWSのドキュメントの目立たないところに以下のように載ってました。 ただし、こちらは単一アカウント内の場合の記述であることに注意してください。

アイデンティティベースのポリシーとリソースベースのポリシーはいずれも、アクセス許可ポリシーであり、一緒に評価されます。アクセス許可ポリシーのみが適用されるリクエストの場合、AWS はすべてのポリシーで Deny がないかチェックします。存在する場合、リクエストは拒否されます。AWS によって、それぞれの Allow がないかどうか確認されます。1 つ以上のポリシーステートメントで、リクエストのアクションが許可されている場合、そのリクエストは許可されます。Allow がアイデンティティベースのポリシーか、リソースベースのポリシーであるかは関係ありません。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_identity-vs-resource.html

つまり、単一アカウントの場合、どっちかで許可されてたらOKで、どこかで拒否されてたら即NG

ここから実話(事件発生)

「ほんなら、SQSのリソースポリシーのPrincipalを以下のようにしておいたら、とりあえずアカウント内の他のリソースからアクセスできるんやな!」

TerraformのSQSモジュールのvariableのデフォルト値を以下のようにセット。

"Principal": { "AWS": "arn:aws:iam::123456789012:root" }

「よっしゃ、これでECSからSQSにメッセージ入れて〜」

「・・・」

「あれ?ECSからSQSへのsendMessageが403になってる!?」

「SQSのリソースポリシーでアカウント全体からのアクセスを許可したつもりやが!?」

よく見てみると・・・

リソースベースのポリシーにある Principal 要素か、プリンシパルをサポートする条件キーで、AWS アカウント の識別子を指定できます。これにより、権限がアカウントに委譲されます。別のアカウントへのアクセスを許可する場合、そのアカウントの管理者が、そのアカウントの ID (IAM ユーザーまたはロール) へのアクセス許可を付与する必要があります。AWS アカウント を指定するときは、アカウント ARN (aarn:aws:iam::account-ID:root、または "AWS": プレフィックスの後に ID を付けた短縮形を使用できます。

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-accounts

ん?権限がアカウントに委譲されるやと?委譲ってあの委譲?

(委譲の定義を一応調べる)

権利・権限などを他の人・機関に譲って任せること。

つまり、あの書き方はアカウント全体からのアクセスを許可しているみたいな顔をしておきながら、アカウントに責任をなすり付けているだけだったんです!

イメージこんな感じ。

SQS「君んとこの管理者が『アクセスしてええで』って言ってくれてるなら、アクセスしてええよ〜」

つまり僕は、ECSのタスクロールにIAMポリシーをアタッチする必要があったということでした。

教訓

  • Principal:root を指定 = 「許可」ではなく「委譲」
  • 結局アイデンティティ側にもポリシーが必要
  • AWSのドキュメントは隅々まで読もう(自戒)

めでたしめでたし。