S3のアクセスコントロールをよく理解していないのでまとめる。
日本語ドキュメントは更新されてない場合が多いので英語ドキュメントを参照することをお勧めする。
ただ、S3のアクセスコントロールについては枯れているので日本語ドキュメントでも問題ないと思う。
前提知識
大概のクラウドストレージサービスには意図せぬ公開のリスクがある。
S3も同様にワンクリックでカジュアルな情報漏えいが可能である。
CLIはともかく、コンソールでのバケット作成時に公開するのか/しないのか選択できてもいいのにと思う。
こちらの記事でS3うっかり公開の防止や発見について書いてあるので読んでおくこと。
Trusted Advisor、AWS Config、S3アクセスチェック、などについて書かれている。
意図せず公開しているS3バケットはありませんか?〜S3アクセス権限設定を見直そう〜
基礎知識
アクセスコントロールの種類
S3はアクセスコントロールのために3つの方法を提供している。
AWS全般のアクセスコントロールの種類やサービスごとの対応状況についてはIAMと連携するAWSサービスが参考になる。
- ACL(アクセスコントロールリスト)
- バケットポリシー
- IAMポリシー
アクセスコントロールタイプ | AWSアカウントレベルの制御 | IAMユーザレベルの制御 | 形式 |
---|---|---|---|
ACL | ○ | ☓ | XML |
バケットポリシー | ○ | ○ | JSON |
IAMポリシー | ☓ | ○ | JSON |
ACL
バケット/オブジェクトのサブリソースとしてXMLで定義する。
AWS Management Console からは、各バケット/オブジェクトの Properties > Permissions で設定できる。
ACLは設定でdisableに出来るようになった。
disableにした場合、ポリシーだけでアクセス制御を行うことになる。
Controlling ownership of objects and disabling ACLs for your bucket
※ 2022-01-31時点で日本語訳はない
バケットポリシー
バケット/オブジェクトのアクセス権をJSONで定義する。
AWS Management Console からは、バケットの Properties > Permissions > Add(Edit) Bucket Policy で設定できる。
IAMポリシー
IAMのリソースに紐づき、S3を含むAWSリソースへのアクセス権をJSONで定義する。
AWS Management Console からは、IAMのホームディレクトリでユーザ/グループ/ロールのポリシー設定ができる。
リクエストの認可
あとで書く。
Amazon S3 がリクエストを許可する方法
評価論理
許可/拒否を決めるルール。ここが1番重要な気がする。
基本は下記の通りで 明示的拒否 > 許可 > デフォルト拒否 の順に強い。
- デフォルト拒否 (ただし自分自身からのアクセスは除く)
- 許可 は デフォルト拒否 に優先する
- 明示的拒否 は 許可 に優先する
- ポリシーの評価順序は重要ではない
個人的に間違えそうなのが、デフォルト拒否/明示的拒否に、許可を組み合わせた場合。
条件Aに一致するリクエストが拒否される時、設定によってどういう評価になるかを表にしてみる。
条件 | 可否 | 評価 |
---|---|---|
NOT A | Allow(許可) | デフォルト拒否 |
A | Deny(拒否) | 明示的拒否 |
これに評価が許可になる条件Bを組み合わせると、
(NOT A) or B → デフォルト拒否 or 許可 → 許可
A or B → 明示的拒否 or 許可 → 拒否
となり、評価がデフォルト拒否になっているからといって、拒否設定した気になっていると、
他のポリシーとの組み合わせでうっかり許可になってしまう場合がある。
対象リソースの指定
バケットポリシーやIAMポリシーで、ある Action を許可/拒否する場合、対象 Resource を ARN で指定する。
バケットに対する Action は Resource としてバケットの ARN(arn:aws:s3:::bucket) を指定する。
オブジェクトに対する Action は Resource としてオブジェクトの ARN(arn:aws:s3:::bucket/*) を指定する。
AWS Management Console から特定のS3バケットの操作を許可する例。
{
"Statement":[
// S3ホームディレクトリでバケット一覧を表示するために必要
{
"Effect":"Allow",
"Action":[
"s3:ListAllMyBuckets"
],
"Resource":"arn:aws:s3:::*"
},
// バケットに対する操作を許可
{
"Effect":"Allow",
"Action":[
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource":"arn:aws:s3:::bucket"
},
// オブジェクトに対する操作を許可
{
"Effect":"Allow",
"Action":[
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource":"arn:aws:s3:::bucket/*"
}
]
}
AWS Account ID と Canonical User ID の確認方法
AWS Management Console に AWSアカウントでログイン後、
右上のメニュー > Security Credentials を開き Account Identifiers から確認できる。
ただし、AWSアカウントの管理者(rootユーザ)しか確認できない。
aws s3api get-bucket-acl --bucket <bucket-name>
で確認したほうが手っ取り早いかも。
AWS アカウント ID
ACL
ACLは設定でdisableに出来るようになった。
disableにした場合、ポリシーだけでアクセス制御を行うことになる。
Controlling ownership of objects and disabling ACLs for your bucket
※ 2022-01-31時点で日本語訳はない
アクセスコントロールリスト(ACL)は、各バケット/オブジェクトごとに付与され対象のアクセス権を制御できる。
バケット/オブジェクト作成時に、デフォルトで自分自身への FULL_CONTROL
が付与される。
最大100個まで権限を付与できる。
バケットごと公開したい時 AWS Management Console からマウス操作だけで簡単に設定できるし、オブジェクトごとに細かくアクセス制限したい時などに使えそう。
別アカウントのバケットにオブジェクトをアップロードする場合、そのアカウントの管理者に FULL_CONTROL
を与えたりする(CloudTrailなど)。
この場合ACL以外で許可する方法はない。バケットポリシーだけ設定したとしても許可はされない。
また、バケットポリシーは20KBの制限があるので、ACLを併用したほうがいいこともある。
アクセスポリシーのオプションを使用するためのガイドライン
被付与者(Grantee)
アクセス権を付与される人。
被付与者は、AWSアカウントに紐付いたメールアドレスor正規ユーザID(Canonical User ID)で指定する。
IAMユーザ単位のアクセス権は設定できない。たぶんIAMが実装される前からある機能だから。
S3には、あらかじめいくつかのグループが定義されており、グループに対してアクセス権を付与することもできる。
-
Authenticated Users
全AWSアカウント(自分以外のアカウントも含むので注意)。
リクエストは署名(認証)されている必要がある。
-
All Users
誰でも。リクエストの署名有無は問わない。
AWS Management Console の Permissions で選択できる Everyone は多分これ。
-
Log Delivery
S3のアクセスログ書き込み権限。アクセスログについては↓。
サーバーアクセスのロギング
アクセス許可(Permissions)
READ
、WRITE
、READ_ACP
、WRITE_ACP
、FULL_CONTROL
の5つのアクセス権がある。
*_ACP はアクセスコントロールリストへのアクセス権をあらわす。
アクセスコントロールリスト(ACL)の概要 - 付与できるアクセス許可
規定ACL(Canned ACL)
S3には、あらかじめ被付与者とアクセス許可のセットが定義されており、APIのパラメータとして使用することができる。
アクセスコントロールリスト(ACL)の概要 - 既定 ACL
-
private (バケット/オブジェクト)
デフォルトACL。所有者に
FULL_CONTROL
が付与される。 -
public-read (バケット/オブジェクト)
所有者に
FULL_CONTROL
、All Users にREAD
が付与される。 -
public-read-write (バケット/オブジェクト)
所有者に
FULL_CONTROL
、All Users にREAD
/WRITE
が付与される。 -
authenticated-read (バケット/オブジェクト)
所有者に
FULL_CONTROL
、Authenticated Users にREAD
が付与される。 -
bucket-owner-read (オブジェクト)
オブジェクト所有者に
FULL_CONTROL
、バケット所有者にREAD
が付与される。
バケット作成時に指定しても無視される。 -
bucket-owner-full-control (オブジェクト)
バケット所有者とオブジェクト所有者に
FULL_CONTROL
が付与される。
バケット作成時に指定しても無視される。 -
log-delivery-write (バケット)
Log Delivery グループに
WRITE
/READ_ACP
が付与される。
バケットポリシー
JSONの定義は、IAMポリシーの項を参照。
設定の参考例は↓。
バケットポリシーの例
- ポリシーを定義できるのはバケット所有者のみ
- バケット/オブジェクトレベルのアクセス権を設定できる
- オブジェクトに対するアクセス権設定は、バケット所有者とオブジェクト所有者が同一の場合のみ可能
- ACLと違い、IAMユーザレベルのアクセス権設定ができる
- IAMグループレベルのアクセス設定はできない。IAMグループのIAMポリシーで設定することはできる。
- 他AWSアカウントの管理者に許可を付与した場合、他AWSアカウントの管理者はそのIAMユーザに権限を譲渡することができる
- バケットポリシーのサイズは20KBまで
IAMポリシー
IAMポリシーとバケットポリシーはどちらでも同じようなアクセス権を設定できるが、
ユーザにアクセス権を設定したい場合はIAMポリシーを使い、
AWSアカウントやバケットにアクセス権を設定したい場合はバケットポリシーを使う、
という決まりを作ったほうが運用時に幸せになれそう。
IAMポリシーを使ったアクセス制御のチュートリアルが↓にあるので参考に。
チュートリアル例: ユーザーポリシーを使用したバケットへのアクセスの制御
リソース作成者のアクセス許可
AWSアカウントの管理者がバケット/オブジェクトを作成した場合、デフォルトで FULL_CONTROL
が付与される。
しかし、IAMユーザが作成した場合、デフォルトではアクセス権は設定されない。
なので、IAMポリシーでアクセス権を設定する必要がある。
ポリシーの要素
ポリシーの要素で気になったものだけ紹介。
要素の中には値としてポリシー変数(後述)を指定できるものもある。
IAM ポリシーエレメントの参照
Version
ポリシー言語のバージョンを表す。
ポリシー内にポリシー変数を含む場合は Version
要素を必ず指定する必要がある。
Version
要素のデフォルト値は 2008-10-17
なので、ポリシー変数がリテラル文字列として扱われるから。
2012-10-17
を指定することでポリシー変数として扱われるようになる。
"Version":"2012-10-17"
Principal
Principal とは、ポリシーにしたがってアクセス権限を付与または拒否される 1 人以上のユーザーです。
Principal
要素にはAWSアカウントID、正規ユーザID、IAMユーザのARNなどが指定できる。
NotPrincipal
要素を使うことで、特定アカウント/IAMユーザを明示的に拒否することもできる。
// AWSアカウント単位
"Principal":{"AWS":"123456789012"}
"Principal":{"AWS":"arn:aws:iam::123456789012:root"}
// IAMユーザ
"Principal":{"AWS":[
"arn:aws:iam::123456789012:user/Isono",
"arn:aws:iam::123456789012:user/Nakajima"
]}
// Webフェデレーションユーザ
"Principal":{"Federated":"www.amazon.com"}
Action
Action
要素にもワイルドカード(* or ?)が使える。
NotAction
要素を使うことで、特定アクション以外を明示的に拒否することもできる。
"Action":"iam:*AccessKey*"
S3の Action 一覧↓。
ポリシーでのアクセス許可の指定
Resource
取り扱う対象のオブジェクトをARNで指定する。
IAM をサポートする AWS サービス
"Resource":[
"arn:aws:dynamodb:ap-northeast-1:123456789012:table/table1",
"arn:aws:dynamodb:ap-northeast-1:123456789012:table/table2"
]
Condition
オプショナルな要素。ポリシーの実行条件を細かく指定できる。
色々できるので詳細は↓を参照のこと。
IAM ポリシーエレメントの参照 - 条件
ポリシー変数
ポリシー変数を使う場合は "Version":"2012-10-17"
をポリシーに含めること。
未指定の場合、デフォルトで旧バージョン(2008-10-17)が指定されたことになるのでポリシー変数は使えない。
その場合、ポリシー変数はリテラル文字列として扱われる。
IAM ポリシー変数の概要
変数の使用箇所
Resource
要素と Condition
要素で使える。
// Resource要素
"Resource":["arn:aws:s3:::bucket/home/${aws:username}/*"]
// Condition要素
"Condition": {
"StringLike": {
"sns:endpoint": "https://example.com/${aws:username}/*"
}
}
キーの種類
リクエストから取得されるキー
Condition
のキーとして指定する場合、大文字/小文字を区別するので注意。
-
aws:CurrentTime
日時条件
-
aws:EpochTime
日付をエポックつまり UNIX 時間で表したもの。日時条件で使用
-
aws:principaltype (※)
プリンシパルがアカウント、ユーザー、フェデレーション、または引き受けられたロールかどうかを示す値
-
aws:SecureTransport
リクエストが SSL を使用して送信されたかどうかを示すブール値
-
aws:SourceIp
IP アドレス条件で使用するための、リクエスタの IP アドレス
-
aws:UserAgent
文字列条件で使用するための、リクエスタのクライアントアプリケーションに関する情報
-
aws:userid (※)
現在のユーザーの一意の ID
-
aws:username (※)
現在のユーザーのフレンドリ名
※ プリンシパルごとの aws:username
aws:userid
aws:principaltype
の値を表にしたもの。
プリンシパル | aws:username | aws:userid | aws:principaltype |
---|---|---|---|
AWSアカウント | - | AWSアカウントID | Account |
IAMユーザ | IAMユーザ名 | 一意のID | User |
委任ユーザ | - | AWSアカウントID:発信者が指定した名前 | FederatedUser |
Webフェデレーションユーザ | - | - | AssumedRole |
SAMLフェデレーションユーザー | - | - | AssumedRole |
委任されたロール | - | ロールID:発信者が指定したロール名 | AssumedRole |
Amazon EC2 インスタンスに割り当てられたロール | - | ロールID:インスタンスID | AssumedRole |
匿名(SQS/SNS/S3のみ) | - | - | Anonymous |
IAM ポリシー変数の概要 - ポリシー変数に使用可能なリクエスト情報
Webフェデレーションユーザに関するキー
どのプロバイダでログインしたかは aws:FederatedUser
で取得できる。
-
aws:FederatedUser
- Amazonでのログイン認証時に
www.amazon.com
を返す - Facebookでのログイン認証時に
graph.facebook.com
を返す - Googleでのログイン認証時に
accounts.google.com
を返す
- Amazonでのログイン認証時に
アプリケーションIDとユーザIDも取得できる。
プロバイダごとのキーは下記の通り。
プロバイダ | アプリケーションIDのキー | ユーザIDのキー |
---|---|---|
Amazon | www.amazon.com:app_id | www.amazon.com:user_id |
graph.facebook.com:app_id | graph.facebook.com:id | |
accounts.google.com:aud | accounts.google.com:sub |
SAMLベースのフェデレーションユーザに関するキー
下のほうに一覧が書いてある。
IAM ポリシーエレメントの参照 - 条件
S3固有のキー
サービス固有のキーもある。S3で利用可能なキーは↓。
ポリシーでの条件の指定
クロスアカウント
このチュートリアルは順を追って関係者が増えて複雑になっていくので理解しやすい。
(例1はクロスアカウントではない)
チュートリアル例: Amazon S3 リソースへのアクセスの管理
とにかくIAMユーザ(子)はAWSアカウントの管理者であるrootユーザ(親)の許可がないとダメ。
クロスアカウントの場合、親であるAWSアカウントの管理者が2人になるので、子はそれぞれに親に許可を得る必要がある。