S3のブロックパブリックアクセスを試して理解する
記事の内容
Amazon S3は低コストが特徴のストレージサービスです。
S3はその汎用性の高さから様々な活用例が考えられるのですが、活用場面において気にするのが「アクセス許可」です。
なんかたくさん設定欄ある。。。とりあえず設定したけど、次に設定するときは忘れてしまう。そんなことにならないよう備忘録をつけようと思います。
今回はアクセス許可の中で、ブロックパブリックアクセスにフォーカスをおいてみます。
関係する技術・ツール
- Amazon S3
- AWS CLI 2.9.x
S3を作成する
S3をマネージメントコンソールから作成します。
この時、たくさん入力欄がありますが、入力するのはバケット名だけです。その他は、いったん既定値で作成します。access-test-bucket-20230629という名前で作成してみます。
すると下記のように作成されます。(2023/6/29現在)
- アクセス許可の概要: 非公開のバケットとオブジェクト
- ブロックパブリックアクセス (バケット設定): オン
- バケットポリシー: 空白
- オブジェクト所有者: バケット所有者の強制
- アクセスコントロールリスト (ACL): 無効
- Cross-Origin Resource Sharing (CORS): 空白
「アクセス許可の概要」が、バケットへのアクセスに関するおおよその状態を表現するようです。
いきなりですが、この状態で試してみます。
バケットを所有するアカウント、とそうでないアカウントでcpコマンドを実行します。
aws s3 cp test.csv s3://access-test-bucket-20230629/
すると、
upload failed: ./test.csv to s3://access-test-bucket-20230629/test.csv An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
バケット所有者でないアカウントではコピーできませんでした。
なるほど。非公開という通り所有者アカウントでのみアクセスできる状態のようです。
所有者 | 所有者でない |
---|---|
○ | × |
この状態から確認していきたいと思います。
ブロックパブリックアクセス (バケット設定)
マネージメントコンソールに沿ってみていくと、この項目がまず目に付きます。
既定値では、「すべてブロック」になっていると思います。これをオフにしてみます。
すると、下記のようにアイコンが⚠️となりました。なんかやばそうですね。外部の人がアクセスできてしまうのではないか、そんな気がしてなりません。
この状態で、再度cpコマンドを実行してみます。確認しやすいために、既にバケットに同名のファイルがある場合はあらかじめ削除しておきます。
aws s3 cp test.csv s3://access-test-bucket-20230629/
すると、
upload failed: ./test.csv to s3://access-test-bucket-20230629/test.csv An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
となり、所有者でないアカウントではアクセスできません。
所有者 | 所有者でない |
---|---|
○ | × |
どうやら、ブロックパブリックアクセスをオフにしたからといって直ちに誰でもアクセスできるわけではないようです。
もう少し掘り下げていきたいと思います。
ブロックパブリックアクセスには下記の4つのオプションが存在します。
- 新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- 任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- 新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- 任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする
次はこれらを確認していきます。
4つのうち、「アクセスコントロールリスト (ACL)」と「バケットポリシー」というワードが気になります。どちらも名前的にアクセスを制御するもので、本記事のポイントになります。
アクセスコントロールリスト (ACL)とは
ACLというものが出てきました。これは何なのでしょう。
Amazon S3 のアクセスコントロールリスト (ACL) では、バケットとオブジェクトへのアクセスを管理できます。各バケットとオブジェクトには、サブリソースとして ACL がアタッチされています。これにより、アクセスが許可される AWS アカウントまたはグループと、アクセスの種類が定義されます。リソースに対するリクエストを受け取ると、Amazon S3 は該当する ACL を確認して、リクエスタに必要なアクセス許可があることを確かめます。
どうやら、「バケット」と「オブジェクト」単位でアクセスをコントロールできる設定のようです。名前そのままです。
ACLはマネージメントコンソールの「アクセス許可」タブをスクロールしていくとあります。
ACLは既定値では無効です。これを有効にしてみたいと思います。
オブジェクト所有者は「希望するバケット所有者」です。
⚠️が2つも出てきます。不安でたまりませんが試してみましょう。
有効にするとACLによってアクセス許可ができるようになります。では試してみましょう。
ACLにはグループという概念があります。
グループにはAWS事前定義済みのグループと、任意でグループを追加できます。このグループは、誰に対してのアクセス権であるかを意味します。
ただし、任意のグループに指定できるのはAWSアカウントに限られます。
今回は事前定義済みグループのAuthenticated Users グループ (AWS アカウントを持つすべてのユーザー)を変更してみます。リストを許可します。
リストを許可したので、list-objects-v2コマンドでリストを取得してみます。
aws s3api list-objects-v2 --bucket access-test-bucket-20230629
{ "Contents": [ { "Key": "test.csv", "LastModified": "2023-06-29T00:43:32+00:00", "ETag": "\"7bb7a05b0bfb9333e8626aa5df9c8608\"", "Size": 18, "StorageClass": "STANDARD" } ] }
すると、バケット所有者でないAWSアカウントでオブジェクト一覧が取得できました。もちろん所有者も取得できます。
所有者 | 所有者でない |
---|---|
○ | ○ |
つまり、ACLによってアクセスのコントロールができていることがわかります。
新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
では、本題のオプションを確認していきます。
ここでいう「新しいアクセスコントロールリスト (ACL)を介して」とはそのままですが、新しくACLを追加することをブロックすることを意味していると思われます。
確認してみましょう。
上記[アクセスコントロールリスト (ACL)とは](#アクセスコントロールリスト (ACL)とは)で有効にしたリストは不許可に戻しておきます。
次に、このオプションをオンにしてみます。
そして、再度ACLから、Authenticated Users グループ (AWS アカウントを持つすべてのユーザー)にリストを許可してみます。
すると、エラーとなりました。
つまり、このオプションは新しくACLを新しく追加したり、更新したりすることを禁止とするオプションだということがわかります。マネージメントコンソールで操作しているのはバケット所有者のアカウントですが、これは例えバケットの所有者であっても同様です。
もし、ACLが変更できてしまえばACLの意味がなく無法地帯です。アクセス権がなければ作ってしまえば突破できてしまいます。
上記のことから、オンにしておいたほうがよいオプションと言えそうです。
任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
ここでいう「任意のアクセスコントロールリスト (ACL)を介して」ですが、意味合い的にはACLでアクセスできることを禁止とするように考えられます。今回はオブジェクト単位で確認していきたいと思います。
バケット所有者アカウントでファイルをアップロードしてみます。このとき--acl authenticated-read
オプションを指定します。
authenticated-readは、既定のグループAuthenticated Usersへreadの権限のみ許可するaclを与えています。
aws s3 cp test.csv s3://access-test-bucket-20230629/ --acl authenticated-read
アップロードしたオブジェクトをマネージメントコンソールから選択して、「アクセス許可」タブで確認します。
すると下記のように読み込みが許可されていることがわかります。
この状態でバケット所有者でないアカウントからオブジェクトを取得してみます。
aws s3api get-object --bucket access-test-bucket-20230629 --key test.csv test-get.csv
するとオブジェクトが取得できました。
{ "AcceptRanges": "bytes", "LastModified": "2023-06-29T05:05:49+00:00", "ContentLength": 18, "ETag": "\"7bb7a05b0bfb9333e8626aa5df9c8608\"", "ContentType": "text/csv", "ServerSideEncryption": "AES256", "Metadata": {} }
所有者 | 所有者でない |
---|---|
○ | ○ |
これでオブジェクトにauthenticated-readのaclを設定すると、バケット所有者でなくともオブジェクト取得できることが確認できました。
では、ここで改めてこのオプションをオンにしてみます。
すると、先ほどオブジェクトから「アクセス許可」を確認した画面では読み込みが許可の表示が消えました。
この状態で同じくオブジェクトを取得してみます。
aws s3api get-object --bucket access-test-bucket-20230629 --key test.csv test-get.csv
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
今度はアクセス拒否となりました。
このことから、このオプションはバケットまたはオブジェクトに設定されたACLを無効にすることがわかります。
ACLは削除されたわけでなく、あくまで無効な状態であり、このオプションをオフにするとACLは再び有効になります。
また注意点として、このオプションは既定のAllUsersとAuthenticatedUsersグループにのみ有効です。
つまり、上記2つ以外の既定グループや任意で設定したグループには適用されません。
バブリックなアクセスは禁止にするが、任意のグループ(アカウント)には許可したい、そんなケースに使えそうです。
所有者 | 所有者でない | 所有者でないが指定したアカウント |
---|---|---|
○ | × | ○ |
上記のことから、こちらのオプションも基本的にオンにしておいたほうがよいと言えそうです。
バケットポリシー
残る2つも確認していきます。
今度はバケットポリシーが関係するようです。バケットポリシーは下記のように説明されています。
バケットポリシーは、Amazon S3 バケットとその中のオブジェクトへのアクセス許可を付与できるリソースベースのポリシーです。バケット所有者のみが、ポリシーをバケットに関連付けることができます。バケットに添付された許可は、バケット所有者が所有するバケットのすべてのオブジェクトに適用されます。これらの許可は、他の AWS アカウント が所有するオブジェクトには適用されません。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucket-policies.html
jsonで記述します。IAMポリシーとほぼ同じような記述ですね。
よくAWSで開発していると見慣れているかと思います。
例として、access-test-bucket-20230629のオブジェクトに対して誰でも、全てのアクセスができるバケットポリシーは下記のようになります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "arn:aws:s3:::access-test-bucket-20230629/*"
}
]
}
試しに、このポリシーをバケットに付与してみます。パブリックアクセスは全てオンにしています。
aws s3api put-bucket-policy --bucket access-test-bucket-20230629 --policy file://policy.json
すると、赤い枠線で「パブリックにアクセス可能」と表示されました。なんかやばそうですね。誰でもアクセスできてしまうのでしょうか。またバケット所有者でないアカウントで確認してみましょう。
この状態で、ファイルをアップロードしてみます。
aws s3 cp test.csv s3://access-test-bucket-20230629/
upload: ./test.csv to s3://access-test-bucket-20230629/test.csv
アップロードできました。ついでにオブジェクトの取得もしてみます。
aws s3api get-object --bucket access-test-bucket-20230629 --key test.csv test-get.csv
{
"AcceptRanges": "bytes",
"LastModified": "2023-06-29T06:14:35+00:00",
"ContentLength": 18,
"ETag": "\"7bb7a05b0bfb9333e8626aa5df9c8608\"",
"ContentType": "text/csv",
"ServerSideEncryption": "AES256",
"Metadata": {}
}
取得もできました。
つまり、バケットポリシーでアクセスのコントロールができていることがわかります。
所有者 | 所有者でない |
---|---|
○ | ○ |
新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
では、本題のオプションを確認していきます。
「新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して」とありますが、この記事ではバケットポリシーにフォーカスしてみます。
ここでいう「新しいパブリックバケットポリシー」とは、ACLのときと同様に新しくバケットポリシーを設定できないことを意味していると考えられます。
この試しにオプションをオンにしてみましょう。オプションをオンにしても、いまだ「パブリックにアクセス可能」と表示されています。
この状態で、バケットポリシーの変更をしてみます。バケット所有者のアカウントで行います。
aws s3api put-bucket-policy --bucket access-test-bucket-20230629 --policy file://policy.json
An error occurred (AccessDenied) when calling the PutBucketPolicy operation: Access Denied
するとアクセス拒否されました。
たしかに、バケットポリシーの変更はできないようです。
これはあくまで変更できないだけで、既に設定しているバケットポリシーにはなんら影響は与えません。そのため、コンソールに「パブリックにアクセス可能」と表示されているわけですね。
例えば、このポリシーのPrincipal
に特定のアカウントを設定すれば、そのアカウントではアクセスできることが確認できます。この場合「パブリックにアクセス可能」の表示も消えました。
もし、バケットポリシーが変更出来てしまえばこれも無法地帯です。挙動として、ACLで確認した「新しいアクセスコントロールリスト・・・」と似ており、これのバケットポリシー版のようです。
上記のことから、こちらも「新しいアクセスコントロールリスト・・・」同様、オンにしておいたほうがよいオプションと言えそうです。
任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする
最後にこちらの確認オプションを確認していきましょう。
「任意のパブリックバケットポリシー」とありますが、ここまでの流れ的にバケットポリシーを無効にするものなのでしょう。試してみたいと思います。
例として、現在のバケットポリシーは下記の通りです。全てのユーザーがアクセス出来ます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "arn:aws:s3:::access-test-bucket-20230629/*"
}
]
}
この状態で、オプションをオンにします。するとバケットポリシーの記述では、全てのユーザーがアクセスできるものの、赤枠で「パブリックにアクセス可能」という表示はなく、「このアカウントの認証ユーザーのみ」と表示されます。どうやら、アクセスは制限されているようです。
この状態でファイルをアップロードしてみます。バケットの所有者でないアカウントで行います。
aws s3 cp test.csv s3://access-test-bucket-20230629/
upload failed: ./test.csv to s3://access-test-bucket-20230629/test.csv An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
予想通りアクセス拒否となりました。
さらに試しに、今度はPrincipal
に特定のアカウントを指定してみます。すると、今度は指定したアカウントはアクセスできることが確認できます。
所有者 | 所有者でない | 所有者でないが指定したアカウント |
---|---|---|
○ | × | ○ |
このことから、バケットポリシーの"*"は無効となっているが、任意のアカウントではアクセスできることは確認できます。この挙動は「任意のアクセスコントロールリスト・・・」と似た挙動ですね。これはバブリックなアクセスは禁止にするが、任意のアカウントには許可したい、そんなケースに使えそうです。
上記のことから、こちらのオプションも基本的にオンにしておいたほうがよいと言えそうです。
まとめ
- 新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- ACLの作成、更新はできない
- 任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- ACL(AllUsersとAuthenticatedUsersグループ)のアクセスを禁止する
- 指定したアカウントはアクセスできる
- 新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
- バケットポリシーの作成、更新はできない - 任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする
- バケットポリシーの"*"でのアクセスを禁止する
- 指定したアカウントはアクセスできる
このような結果になりました。
S3は既定ではブロックパブリックアクセスは全てオンですが、これは合理的と言えそうです。
なんでも自由にアクセスはセキュリティ的にまずいのもちろん、ACLやバケットポリシーだけに頼ると思わぬセキュリティホールを産みかねません。
ですので、明確な要件ない限りこの既定値でよいでしょう。ブロックパブリックアクセスは「全てオン」で基本的に差し支えないのかと思います。
以上、ブロックパブリックアクセスの調査でした。
NCDC株式会社( ncdc.co.jp/ )のエンジニアチームです。 募集中のエンジニアのポジションや、採用している技術スタックの紹介などはこちら( github.com/ncdcdev/recruitment )をご覧ください! ※エンジニア以外も記事を投稿することがあります
Discussion
ふわっと理解してるつもりでしたが、順序立てて実際に操作したときにどうなるのかというのが表されていて参考になりました。
文章もウィットに富んでいて、フフッとなっちゃいました。
ありがとうございます。励みになります!
AWSの記事は定期的に作っているのでよかったらご覧ください。