AWSは、複数の環境を運用する際に、マルチアカウントをベストプラクティスとしています。
そして、マルチアカウントにおいては、AWS OrganizationsでAWSアカウントを取りまとめた上、SCPを利用して権限移譲を行うことをベストプラクティスとしています。しかし強く推奨しているにも関わらずAWS Organizationsを利用できない場合、権限移譲を行おうとするとPermissions Boundaryを利用することになります。
SCPを利用する場合、使い方は2通りあります:許可リスト方式と拒否リスト方式です。こちらについて、公式ドキュメントに詳細が記載されています:
文字の説明だけだと分かりにくいので、図で整理するとこちらになります:
Permissions Boundaryも、複数のポリシーを1つのアイデンティティに紐づけできないものの、SCPと同様に記述がない場合暗黙的拒否となっているため、理論上、拒否リスト方式と許可リスト方式の2つの使い方があるはずです。では、実際はどうでしょうか?
例えば、S3の「MYBUCKET」というバケットの内容に対して、読み取り(GET)のみ許可しようとします。SCPの拒否リスト方式、許可リスト方式、Permissions Boundaryの拒否リスト方式、許可リスト方式の合計4パターンでポリシーを作成してみます。
SCP:拒否リスト方式
SCPの拒否リスト方式を利用する場合、明示的許可ポリシーとして、「FullAWSAccess」というポリシーがデフォルトで作成されているため、追加で明示的拒否ポリシーを対象OU、もしくは対象アカウントにアタッチすればいいです。例えば以下のようなポリシーを作成し、アタッチします:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": "s3:Get*",
"Resource": "arn:aws:s3:::MYBUCKET/*"
}
]
}
SCP:許可リスト方式
SCPの許可リスト方式を利用するには、まずデフォルトの「FullAWSAccess」をいったんデタッチします。そして、許可したいアクセスを記載したポリシーを、対象OUもしくは対象アカウントにアタッチします。例えば:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "*"
}
]
}
※このポリシーは、「SCP:拒否リスト方式」での例と同一ではありません。拒否リストの例の場合、MYBUCKET以外のバケットへのアクセスや、EC2/RDSなど他のAWSサービスへのアクセスは可能になっています。しかし、この例では、すべてのS3バケットへの読み取りのみ可能です。S3以外のすべてのサービスへのアクセスはできません。
※SCPの場合、EffectがAllowの場合、Resourceの値は「*」にのみ設定可能です。
Permissions Boundary:拒否リスト方式
Permissions Boundaryは、SCPと異なりプリンシパル毎に1つしか設定できないため、まずすべて許可した上、不要な部分を拒否する書き方になります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
},
{
"Effect": "Deny",
"NotAction": "s3:Get*",
"Resource": "arn:aws:s3:::MYBUCKET/*"
}
]
}
Permissions Boundary:許可リスト方式
最後は、Permissions Boundaryの許可リスト方式です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:List*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:Get*",
"Resource": "arn:aws:s3:::MYBUCKET/*"
}
]
}
ざっくり見た感じだと、SCPでもPermissions Boundaryでも結果は一緒のようです。しかし、SCPとPermissions Boundaryは、一つ致命的な違いがあります。この違いを確認するために、対象S3バケットのバケットポリシーを追加します。そうすると再度アクセスを評価すると以下の表の結果になります。
S3バケットポリシーなし | S3バケットポリシーあり | |
---|---|---|
SCP:拒否リスト方式 | Get:〇 / Put:× | Get:〇 / Put:× |
SCP:許可リスト方式 | Get:〇 / Put:× | Get:〇 / Put:× |
Permissions Boundary:拒否リスト方式 | Get:〇 / Put:× | Get:〇 / Put:× |
Permissions Boundary:許可リスト方式 | Get:〇 / Put:× | Get:〇 / Put:△ |
なぜこのような動きになっているでしょうか?公式ドキュメントのポリシー評価ロジックを確認すれば分かるように、SCPもPermissions Boundaryの評価方法はまったく同じですが、評価する順序が異なります。SCPはDeny評価を除き、一番最初に評価されるのに対して、Permissions Boundaryはリソースベースポリシーの後に評価されるのが分かります。つまり、バケットポリシーのようなリソースベースポリシーが優先されるということになります。
さらに、リソースベースポリシーの評価結果として、「Allow」が出現する際の最終結果は、「Allow」の対象次第です。例えば「Permissions Boundary:許可リスト方式」の場合、S3のバケットポリシーを以下の2パターンで記述するとします:
【パターン1】プリンシパルがロールの場合
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/OrganizationAccountAccessRole"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::MYBUCKET/*"
}
]
}
【パターン2】プリンシパルがロールセッションの場合
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:sts::123456789012:assumed-role/OrganizationAccountAccessRole/admin"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::MYBUCKET/*"
}
]
}
パターン1の場合、OrganizationAccountAccessRoleというロールをAssumeしMYBUCKETにアクセスした場合、読み取りのみ可能となります。しかし、パターン2の場合、当該ロールをAssumeしMYBUCKETにアクセスした場合、S3のフルアクセスが可能になります。
まとめ
権限移譲のシナリオにおいて、SCPもPermissions Boundaryも利用可能です。しかし、上記のような動作の違いがあるため、Permissions Boundaryは必ず拒否リスト方式で利用しましょう。