2022/06/10

S3のアクセスコントロールについて

こんにちは、ばんがです。

今回はS3についての話です。
インフラをAWSで構築してるなら大体S3も使うと思うんですが、
S3のアクセス管理ってなにやら設定が多くてわからない...、正直よく理解しないまま使っている部分多い...という状態だったので、少し調査や挙動の確認などをしてみることにしました。

アクセスポリシー

S3のアクセス制御は大まかに2種類のアクセスポリシーを介して行われます。

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

リソース(バケットやオブジェクト)にアタッチするポリシーのことで、主に
・ACL(バケットACL、オブジェクトACL)
・バケットポリシー
があります。

ACL

・AWSアカウントや、アカウントをまとめたグループ単位でアクセス制御を行う
・バケットポリシーに比べて柔軟な設定はできない
ACLでサポートされているアクション

昔からある方法で、特殊な場合を除き現在は推奨されていないようです。
オブジェクト単位でのアクセス制御が必要な場合や、バケットの所有者がオブジェクトを所有していない場合に、そのオブジェクトのアクセス制御を行う時などに利用するようです。

バケットポリシー

・S3に関する全てのアクションを制御できる
・バケット所有者が所有する全てのオブジェクトのアクセス制御が一括管理できる
・後述するオブジェクト所有者の設定によって、バケット所有者がどのオブジェクトを所有するかが変わってきます

上記のようにバケットポリシーの方がACLより柔軟な設定ができ管理も簡潔になることと、ほとんどのユースケースではバケットポリシーで十分対応できるため現在ACLよりもバケットポリシー(あるいはユーザーポリシー)の利用が推奨されています。

ユーザーベースのポリシー

IAMユーザー・グループ・ロールなどにアタッチするアクセスポリシーのことです。
・AWSアカウント内のユーザーごとにアクセス制御を管理したい場合はこちらを使います
最近はACLを無効にするのが一般的。

ポリシーの評価

設定したポリシーは全て評価されるので、IAMユーザーやロールの場合、バケットポリシー、ユーザーポリシーともにアクセスが許可されていないと弾かれてしまいます。
IAMではない匿名ユーザーの場合は、バケットポリシーで評価されますが、こちらは後述するブロックパブリックアクセス設定でもアクセスが許可されている必要があります。

挙動を見てみる

例えば以下のようなバケットポリシーの場合、任意のユーザーが任意のリソースに対してGetObjectが実行できます。

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


何の権限も持たない iamuserを利用しても、ファイルのダウンロードができました。

aws --profile iamuser s3 cp s3://bucket-name/jojo.jpg ./
-> download: s3://bucket-name/jojo.jpg to ./jojo.jpg


ただし、匿名のユーザーの場合は失敗します。

aws --no-sign-request s3 cp s3://bucket-name/jojo.jpg ./
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden


これは、以下のようにブロックパブリックアクセス設定によって匿名アクセスがブロックされているからです。
この場合は、バケットポリシーで任意のプリンシパルを許可するようにしていてもアクセスはブロックされてしまいます。


試しにパブリックアクセスを許可するようにしてみましょう。


今度は匿名ユーザーでもエラーが出ずダウンロードができました。
ブロックパブリックアクセス設定については後ほど詳しく見てみましょう。

aws --no-sign-request s3 cp s3://test-acstudy-bucket/jojo.jpg ./
download: s3://test-acstudy-bucket/jojo.jpg to ./jojo.jpg   


試しにパブリックアクセスを許可したままバケットポリシーでprincipalをiamuserに指定してみます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "iamuserのarn"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-name/*"
        }
    ]
}


aws --no-sign-request s3 cp s3://test-acstudy-bucket/jojo.jpg ./
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden


匿名ユーザーのアクセスがブロックされるようになりました。
ブロックパブリックアクセス設定でパブリックアクセスを許可していてもバケットポリシーが有効なことがわかります。

わかりにくい設定

S3バケットのアクセス管理にはいろんな設定があるので正直わかりにくいし、あまり理解せずに使っていました...。
特に以下の項目がわかりにくかったので調べてみました。

オブジェクトの所有者



はい、これです。
読んで時のごとく、バケット内のオブジェクトの所有権をどう扱うか、ということの設定です。
そもそもACLについてはっきり理解していなかったのでわからなかった設定です。

ACL無効(推奨)

この設定にすると、バケット内のオブジェクトはすべてバケットの所有者(そのバケットが存在するAWSアカウント)が所有することになります。

また、この設定にすることでACLが無効になります。
ACLを考慮することがないので、S3へのアクセスは、バケットポリシー ユーザーポリシーのみ考慮すれば良いので、アクセスコントロールが容易になるというメリットがあります。

基本的なS3のユースケースはこの設定で十分対応できるので、現在はACL無効の設定が推奨されているようです。

ACL有効



こちらはACLが有効になります。
まあ説明文に書いてある通りなんですが、この設定ではバケット内のオブジェクトの所有者がこのバケットの所有者ではない場合があり、その場合そのオブジェクトのアクセスコントロールはバケットポリシーではなくACLが適用されますよ、ということです。

希望するバケット所有者

アップロード時、オブジェクトのACLにbucket-owner-full-controlを指定すると、バケットの所有者がオブジェクトの所有者になり、指定しないとオブジェクトライター(アップロードしたアカウント、IAMユーザー)が所有者になります。

オブジェクトライター

そのまま。アップロードユーザーが所有者になります。

複数アカウントで同じバケットを利用する場合はこの辺の考慮が必要になりそうですね。

ブロックパブリックアクセス

先ほども少し話しましたが以下の設定です。
パブリックアクセス、つまり匿名ユーザーのアクセスをどう扱うか、に関する設定です。



(日本語がわかりにくい.....)

英語で説明を読んだ方がわかりやすいかもしれない。
https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html#access-control-block-public-access-options

上2つと下2つは対象がACLか、ポリシーかの違いだけなので、今回はポリシー対象の設定についてだけ見ていきます。

新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする

これだけ読むと、この設定ONで匿名アクセスがブロックされるのかと思いました。
ですが、説明をみると少しわかりやすいです。

S3 は、バケットとオブジェクトへのパブリックアクセスを許可する新しいバケットポリシーおよびアクセスポイントポリシーをブロックします。この設定は、S3 リソースへのパブリックアクセスを許可する既存のポリシーを変更しません。


つまり、新しくバケットポリシーなどで、匿名アクセスを許可するようなポリシーを作成したり追加したりするのをブロックする、ということです。
実際、この設定をONにして、principal: "*"のように匿名アクセスを許可する変更を入れようとすると、以下のように変更が弾かれます。

また、ポリシーの変更をブロックするだけなので、この設定によって現在許可されている匿名アクセスがブロックされることはありません。

任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする


こちらはもっとシンプルです。
単純に、現在匿名アクセスを許可しているポリシーを無視して匿名アクセスをブロックする設定です。

つまりこの設定をONにすると匿名でのアクセスはできず、AWSアカウントやIAMユーザー・ロールでのアクセスのみをバケットポリシー等で管理することになります。

まとめ

複数アカウントでバケットを利用するなどのユースケースでなければ、バケット所有者を強制してACL無効で管理が良さそうです。
また、ブロックパブリックアクセス設定も、設定の変更を禁止するか、パブリックアクセスを禁止するか、とわかってしまえば単純だったので、今後は設定に悩むことはなさそうです。

今後クロスアカウントのアクセス管理などをする機会が出て来れば、ACL周りについてより詳しく勉強してみようと思います。