【ABAC】S3でタグベース制御を行う(制限あり)

2021.07.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

S3における ABAC(Attribute-based access control) の実現方法を 2つ紹介します。

[前提] S3のABAC

S3でタグベース制御が可能かどうかは以下ページで分かります。

img

S3は上図のとおり [部分的※] となっています。この注釈には以下のように書かれています。

Amazon S3 はオブジェクトリソースに対してのみタグベースの認証をサポートしています。

つまり S3バケット単位のタグベース制御はできません

[方法1] オブジェクトに対して ABAC

前述の通り S3の「オブジェクト」に対してはタグベース制御が可能です。 以下 2項目を確認してみましょう。

img

適当な S3オブジェクトにタグを付けています。

aws s3 ls s3://$BUCKET/test.txt
# 2021-07-12 08:49:08          5 test.txt

aws s3api get-object-tagging --bucket $BUCKET --key test.txt --output yaml
# TagSet:
# - Key: Project
#   Value: XXX

各ロールにはタグの値で GetObject の許可を判別するポリシーのみ付与しています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/Project": "${aws:PrincipalTag/Project}"
        }          
      }
    }
  ]
}

【確認1】GetObject できること

ロールXには以下のようなタグ付を行っています。

aws iam tag-role --role-name $ROLEX --tags Key=Project,Value=XXX
aws iam list-role-tags --role-name $ROLEX --output yaml
# IsTruncated: false
# Tags:
# - Key: Project
#   Value: XXX

以下のように、GetObject できていること確認できました。

aws --profile role-x s3api get-object --bucket $BUCKET --key test.txt test-from-rolex.txt
# AcceptRanges: bytes
# ContentLength: 5
# ContentType: text/plain
# ETag: '"d8e8fca2dc0f896fd7cb4cb0031ba249"'
# LastModified: '2021-07-11T23:49:08+00:00'
# Metadata: {}
# ServerSideEncryption: AES256
# TagCount: 1

cat test-from-rolex.txt
# test

【確認2】GetObject できないこと

ロールYには以下のようなタグ付を行っています。

aws iam tag-role --role-name $ROLEY --tags Key=Project,Value=YYY
aws iam list-role-tags --role-name $ROLEY --output yaml
# IsTruncated: false
# Tags:
# - Key: Project
#   Value: YYY

こちらは GetObject ができません。想定通り Access Denied となりました。

aws s3api get-object --bucket $BUCKET --key test.txt test-from-roley.txt
# An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

[方法2] パスで ABAC

IAMのポリシー変数 を使って、 S3バケットのパス単位でABACが可能 です。 以下 2項目を試してみます。

img

  • プロジェクト XXX 用のデータ (text-xxx.txt)
  • プロジェクト YYY 用のデータ (text-yyy.txt)

を以下のようにプレフィクスを分けて保存します。

aws s3 ls s3://$BUCKET/project/XXX/
# 2021-07-13 14:55:33         13 test-xxx.txt

aws s3 ls s3://$BUCKET/project/YYY/
# 2021-07-13 14:55:42         13 test-yyy.txt

ロールには タグの値で「アクセスできるリソース」を分ける ようなポリシーをアタッチします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::BUCKET/project/${aws:PrincipalTag/Project}/*"
    }
  ]
}    
# ※ "BUCKET" は対象バケット名

また、ロールへのタグ付けも行います。

aws iam tag-role --role-name $ROLEX --tags Key=Project,Value=XXX
aws iam list-role-tags --role-name $ROLEX --output yaml
# IsTruncated: false
# Tags:
# - Key: Project
#   Value: XXX

【確認1】GetObject できること

/project/XXX/ 配下のオブジェクトにはアクセスできます。

aws s3api get-object --bucket $BUCKET \
--key project/XXX/test-xxx.txt test-xxx.txt
# AcceptRanges: bytes
# ContentLength: 13
# ContentType: text/plain
# ETag: '"53d49e003e2cea063e680fc65cddf659"'
# LastModified: '2021-07-13T05:55:33+00:00'
# Metadata: {}
# ServerSideEncryption: AES256

cat test-xxx.txt
# test for XXX

【確認2】GetObject できないこと

/project/YYY/ 配下のオブジェクトには アクセスできません

aws s3api get-object --bucket $BUCKET \
--key project/YYY/test-yyy.txt test-yyy.txt
# An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

おわりに

S3のタグベース制御例を紹介しました。 紹介した方法で ABAC が実現できますが、やはり運用管理はちゃんと考える必要があります。 タグによる分類を行う前に、 バケット/アカウントを分離して対応できないか 十分に検討しましょう。

また、 [方法2] パスでABAC のポリシー変数を活用するところは、 ABACでなくても活用できると思います。 例えば aws:username を使って、 ユーザー単位でアクセスできるパスを制御する活用もアリでしょう。

参考