特定GCSバケットのオブジェクトに特定個人しかアクセスできないようにする方法

# 背景

普通にGCSバケットのアクセス制御をやろうとすると、Project Owner / Editor / Reader な人たちは、そのプロジェクト内のバケットひいてはバケット内のオブジェクト全てにアクセスできてしまう。

さらにいうと Organization 横断ユーザ(例: セキュリティ監査チーム、GSuites管理者)などもいるので、アクセスできるユーザはもっと広い。

この状態から、機微情報を持つような特定のバケットへのアクセス許可を特定個人(例: インフラチームリーダーとPOのみ)に厳密に絞りたくなった場合にどうすれば良いか。

# 回答

バケット個別に権限付与する機能では、Project Owner などのアクセスを塞ぐことはできない。

オブジェクト単位でアクセス制御を行う[ACL](https://cloud.google.com/storage/docs/access-control/lists)を使うと塞ぐことができる。

# 定義済み ACLs

新しく作られたバケットはデフォルトでは `project-private` という Predefined ACL が設定されているようだ。このACLは Project Owner / Editor / Reader にバケットへのアクセス権限を与える。

オブジェクトの ACL を `private` に変更すると、明示的にオブジェクト OWNER になった者だけが OWNER 権限を持てるようになる。

その他詳細は[Predefined ACLs](https://cloud.google.com/storage/docs/access-control/lists#predefined-acl)を参照。

# バケットのアクセス制御

> すべてのバケットはプロジェクト オーナー グループによって所有されます。プロジェクト オーナーには、各自のプロジェクト内のすべてのバケットに対する OWNER 権限が自動的に付与されます。プロジェクトを作成すると、自動的にプロジェクト オーナーとして追加されます。

ref. https://cloud.google.com/storage/docs/access-control/lists#defaultbuckets

バケット自体は `private` ACL に変更しても Project Owners がバケット Owner になってしまう。

```
$ gsutil acl set private gs://example-bucket
$ gsutil acl get gs://example-bucket
[
  {
    "entity": "project-owners-xxxxxx",
    "projectTeam": {
      "projectNumber": "xxxxxx",
      "team": "owners"
    },
    "role": "OWNER"
  }
]
```

なので、オブジェクト単位で ACL を設定して Project Owners がアクセスできないようにする。

# デフォルトオブジェクト ACL を変更

オブジェクト作成ごとに ACL 指定することももちろんできるが、それが面倒な場合(一般的にそうかと思われる)はデフォルトオブジェクトACLを設定する。　

デフォルト状態 (`project-private` がついている状態)

```
$ gsutil defacl get gs://example-bucket
[
  {
    "entity": "project-owners-xxxxxx",
    "projectTeam": {
      "projectNumber": "xxxxxx",
      "team": "owners"
    },
    "role": "OWNER"
  },
  {
    "entity": "project-editors-xxxxxx",
    "projectTeam": {
      "projectNumber": "xxxxxx",
      "team": "editors"
    },
    "role": "OWNER"
  },
  {
    "entity": "project-viewers-xxxxxx",
    "projectTeam": {
      "projectNumber": "xxxxxx",
      "team": "viewers"
    },
    "role": "READER"
  }
]
```

設定

```
$ gstuil defacl set private gs://example-bucket
```

確認

```
$ gsutil defacl get gs://example-bucket
No default object ACL present for gs://example-bucket. This could occur if the default object ACL is private, in which case objects created in this bucket will be readable only by their creators. It could also mean you do not have OWNER permission on gs://example-bucket and therefore do not have permission to read the default object ACL. It could also mean that gs://example-bucket has Bucket Policy Only enabled and therefore object ACLs and default object ACLs are disabled (see https://cloud.google.com/storage/docs/bucket-policy-only).
[]
```

デフォルトオブジェクト ACL に 個人OWNER および グループOWNER を追加する

```
$ gsutil defacl ch -u sonots@example.com:OWNER gs://example-bucket
$ gsutil defacl ch -g sonots-group@googlegroups.com:OWNER gs://example-bucket
```

確認

```
$ gsutil defacl get gs://example-bucket
[
  {
    "email": "sonots@example.com",
    "entity": "user-sonots@example.com",
    "role": "OWNER"
  },
  {
    "email": "sonots-group@googlegroups.com",
    "entity": "group-sonots-group@googlegroups.com",
    "role": "OWNER"
  }
]
```

オブジェクトを作成する

```
$ gsutil cp hoge.md gs://example-bucket/hoge.md
```

オブジェクトの ACL を確認する

```
$ gsutil acl get gs://example-bucket/hoge.md
[
  {
    "email": "sonots@example.com",
    "entity": "user-sonots@example.com",
    "role": "OWNER"
  },
  {
    "email": "sonots-group@googlegroups.com",
    "entity": "group-sonots-group@googlegroups.com",
    "role": "OWNER"
  }
]
```

これで sonots@example.com と sonots-group@example.com グループのユーザしかこのオブジェクトを参照できなくなる。Project Owners のユーザでも参照できない。

# オブジェクト ACL を変更

すでにあるオブジェクトに対しては、デフォルトオブジェクトACLを変更しても反映されないので、あとから変更する場合は全オブジェクトに対して変更反映する必要がある。

```
$ gsutil acl ch -u sonots@example.com:OWNER 'gs://example-bucket/*'
```

グループ(GCPのIAMにはグループ機能はなく、googlegroupsを使う)で管理しておくと、このオペレーションがなくなるのでよさそう。

# オブジェクト作成者をオブジェクトOWNERから外す

オブジェクトを作成したユーザは、オブジェクトのOWNER権限を必ず持つので外せない。困る。。。

ref. https://cloud.google.com/storage/docs/access-control/lists#defaultobjects

> You (the person who uploaded the object) are listed as the object owner. Object ownership cannot be changed by modifying ACLs. You can change object ownership only by overwriting an object.

> You (the object owner) are granted OWNER permission on the object. If you attempt to give less than OWNER permission to the owner, Cloud Storage automatically escalates the permission to OWNER.

# 削除権限について

オブジェクトACLは、オブジェクトの参照(READER)およびパーミッション変更などのメタデータ変更(OWNER)に対する制御しかできない。

オブジェクトの作成や削除についてはバケットのアクセス権限が使われる。

バケットからは Project Owners を外せないため、Project Owners でもオブジェクトの作成や削除をできないように制御することはできない。

# おまけ: IPアドレス制限

GCSバケットのIPアドレスによるアクセス制限はまだできない (2019.10.15)