GCP VPC Service Controls を試す

## はじめに
GCP のクラウドサービスのデータ制御をする VPC Service Controls がある。
初めて使用するので、前半に内容把握を、後半に実際に軽く試した内容を記載する。

## VPC Service Controls とは

ざっくり言うと下記な感じ。

- サービス境界(Perimeter)を作成して GCP サービスのデータ (API) に対して境界外向けのアクセスをブロックできる
- リスク低減には VPC Service Controls と IAM との併用が推奨
- アクセスレベルを設けるとサービス境界外からのアクセスを許可できる

以下、ドキュメントの内容を元に調査・まとめた学習メモとなる。

### 概要

下記、項目別に[VPC Service Controls の概要 ドキュメント](https://cloud.google.com/vpc-service-controls/docs/overview?hl=ja)の内容をまとめた。
ほぼドキュメント内容のままだが、正確にはドキュメント先を参照してください。

#### VPC Service Controls の保護でできること
VPC Service Controls を使用することで、境界線内外でのアクセスをコントロールすることができる

| 保護項目 | 内容 |
|:--|:--|
| クライアントアクセスを限定 | Google Cloud またはオンプレミスで限定公開の Google アクセスを使用して、承認済みの VPC ネットワーク内のクライアントからのみアクセスを限定 |
| 未承認リソースへのアクセス遮断 | 境界内でリソースへのプライベートアクセスが許可されているクライアントへの、境界外の未承認のリソース（公開される可能性があるリソース）へのアクセス遮断 |
| 未承認リソースへのデータコピーの遮断 | gsutil cp や bq mk などのサービス オペレーションによる、境界外の未承認リソースへのデータコピーの遮断 |
| インターネットアクセスのホワイトリスト化 | 有効にした場合、境界内のリソースに対するインターネット アクセスは、ホワイトリストに登録された IPv4 または IPv6 の範囲を限定される |


#### IAM との違い
IAM との制御の違いは下記の通り

 - IAM から独立している Google Cloud サービスに対するセキュリティが強化可能
 - IAM では詳細な ID ベースのアクセス制御が可能だが、VPC Service Controls では、境界全体での外向きデータの制御など、コンテキストベースの境界セキュリティが可能

**多層的な防御を行うため、VPC Service Controls と IAM の併用が推奨**されている


#### セキュリティ上の利点
Google Cloud リソースへの直接的なプライベートアクセスのパフォーマンス上の利点を犠牲にすることなく、次のセキュリティリスクを緩和する

| セキュリティリスク | VPC Service Controls での利点 |
|:--|:--|
| 盗まれた認証情報を使用した不正なネットワークからのアクセス | ・VPC Service Controls は、承認済みの VPC ネットワークからのプライベート アクセスのみを許可<br>・これにより、OAuth やサービス アカウントの認証情報の盗難を防ぐ |
| 悪意のある関係者や感染コードによるデータ漏洩 | ・VPC Service Controls では、下り（外向き）ネットワーク内のクライアントは境界外にある Google マネージド サービスのリソースにアクセスできない<br>・これにより、下り（外向き）ネットワークの制御が強化される |
| IAM ポリシーの誤構成による非公開データの開示 | ・VPC Service Controls では、IAM ポリシーの誤った構成が原因で非公開データが開示されている場合でも、未承認のネットワークからのアクセスを拒否することでセキュリティをさらに強化できる<br>・IAM で Access Context Manager ポリシー管理者のロールを割り当てることで、IAM ポリシー管理者以外のユーザーも VPC Service Controls を構成できるようになる |

VPC Service Controls を使用すると、**Google Cloud 組織で境界内の保護リソースに一貫したポリシーを作成し、適用できる**
境界内では、データの処理、変換、コピーを柔軟に行うことができる
セキュリティ制御は、境界内に新しく作成されたリソースに自動的に適用される

#### サービスに対するアクセスのモニタリング
VPC Service Controls はサービスへのアクセスのモニタリングにも利用できる

 - [ドライランモード](https://cloud.google.com/vpc-service-controls/docs/dry-run-mode?hl=ja)で境界を使用すると、VPC Service Controls を利用して、保護されたサービスへのリクエストを、アクセスを妨げることなくモニタリングできる
 -  VPC Service Controls を使用すると、リクエストをモニタリングしてプロジェクトに対するリクエスト トラフィックをより深く理解できます
 -  また、Honeypot 境界を作成して、アクセス可能なサービスを探ろうとする予期しないまたは悪意のある試行を特定する方法を提供する

#### メタデータへの未サポート
VPC Service Controls はメタデータを対象にするように設計されておらず、メタデータ制御は IAM ロールでの制御が推奨されている

「データ」と「メタデータ」の定義

| 名称 | 定義 | 対象例 | VPC Service Controls 対応 |
|:--|:--|:--|:--|
| データ | Google Cloud リソースに格納されているコンテンツとして定義される|Cloud Storage オブジェクトのコンテンツなど | 対応|
| メタデータ | リソースまたはその親の属性として定義される|Cloud Storage のバケット名などがメタデータ | 非対応 |

メタデータに対する VPC Service Controls

| 項目 | 内容 |
|:--|:--|
| 設計 | **メタデータの移動を包括的に制御するようには設計されていない** |
| 目的 | サービス境界を超える**データの移動をサポートされているサービスで制御**することを基本的な目的としている |
| メタデータ制御 | ほとんどの場合、VPC Service Controls はメタデータへのアクセスも制御しますが、VPC Service Controls のポリシーチェックを行わずに**メタデータをコピーしてアクセスできる場合もある** |
| メタデータへの適切制御をするためには | カスタムロールを含む **IAM を使用することを推奨** |


### 機能

- セキュリティポリシーの定義をする機能を提供する
    - 信頼できる境界の外部にある Google マネージド サービスへのアクセスを禁止
    - 信頼できない場所からのデータへのアクセスをブロック
- 効果
    - データ漏洩のリスクを軽減

下記が VPC Service Controls で提供する機能を項目ごとにある程度まとめた表となる

| 機能 | 内容 |
|:--|:--|
| サービス境界 (Service Perimeter) | Google マネージド リソースのセキュリティ境界<br>境界内では自由に通信できるが、境界を越える通信はデフォルトでブロックされる |
| サービス境界の機能 | ・Google Cloud リソースのセキュリティ境界を作成する<br>・仮想マシン（VM）から Google Cloud サービス（API）への通信や Google Cloud サービス間の通信を制御できる<br>・サービス境界を設定すると、境界内では自由に通信できるが、境界を越える通信はすべてデフォルトでブロックされる |
| VPN / Cloud Interconnect への境界拡張 | ・プライベート IP で接続された VPN / Cloud Interconnect をサービス境界の内側に含めることができる<br>・オンプレミス側からアクセスするには制限付き VIP を使用<br>・[詳細](https://cloud.google.com/vpc-service-controls/docs/private-connectivity?hl=ja) |
| 制限付き VIP / 限定公開 Google アクセス | ・VPC Service Controls でサポートされるプロダクトと API にプライベートなネットワーク ルートを提供<br>・これらのプロダクトが使用するデータやリソースは、インターネットからアクセスできない<br>・`restricted.googleapis.com` は `199.36.153.4/30` として解決され、インターネットにこのアドレスは公開されない |
| インターネットからのアクセス制御 | (デフォルト)インターネットからサービス境界内のマネージドリソースへのアクセスを拒否<br>アクセスレベルを作成してインターネットからのアクセスを許可可能  |
| アクセスレベル | ・送信元 IP 範囲、クライアント デバイス、位置情報など、複数の属性に基づくインターネット上のリクエストを分類<br>・リクエストに関連付けられたアクセスレベルに基づいてインターネットからのアクセスを許可<br>・アクセスレベルは、Access Context Manager サービスによって決定 |
| Access Context Manager | 送信元 IP アドレスなど、クライアントの特定の属性に基づいてリクエストをアクセスレベルに関連付けるコンテキスト認識のリクエスト分類サービス |
| Cloud Console | Cloud Console を使用して境界内のリソースにアクセスするには下記を２つでアクセスレベルを構成する<br>・1 つ以上の IPv4 または IPv6 の範囲からのアクセス<br>・特定のユーザー アカウントへのアクセス |
| サービス境界ブリッジ | ・異なるセキュリティ境界のプロジェクト間で通信を可能にできる<br>・境界ブリッジは双方向<br>・各サービス境界のプロジェクトは、ブリッジのスコープ内で同等にアクセス可能 |

上記機能を概要図にまとめてみたのが下記となる

![ServicePerimeter_Absut1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/5aa4bffa-4347-cad6-c43c-0239a57ed3c5.png)


### 必要な IAM のロール

権限別の必要なロールは下記

| 権限 | Role |
|:--|:--|
| Access Context Manager 管理者 | roles/accesscontextmanager.policyAdmin |
| Access Context Manager 編集者 | roles/accesscontextmanager.policyEditor |
| Access Context Manager 読み取り | roles/accesscontextmanager.policyReader |
| Resource Manager 組織閲覧者<br>(Google Cloud Console から VPC Service Controls を管理する場合は追加で必要) | roles/resourcemanager.organizationViewer |

### 共有VPC使用時の注意点

- 共有 VPC ネットワークに属するプロジェクトを含むサービス境界
    - **そのネットワークをホストするプロジェクトも含まれる必要**がある
    - ホストプロジェクトと同じ境界にない場合、**サービスは期待どおりに動作しない**か、**完全にブロックされる**可能性がある

参照：https://cloud.google.com/vpc-service-controls/docs/troubleshooting?hl=ja#shared_vpc

### 対応サービス
対応しているプロダクトと対応状況については[ドキュメント](https://cloud.google.com/vpc-service-controls/docs/supported-products?hl=ja)を参照

### ファイアウォールとの違い

ファイアウォールは VPC ネットワークに対して制御し、VPC Service Controls は Google の API に対して制限を行う
VPC ネットワークに属さない Google サービスに対して VPC Servcie Controls を使用することで、サービス境界によって保護することができる

下記表は [Google Cloud Next ’19 in Tokyo 実例から学ぶ、VPC Service Control Deep Dive](https://cloud.withgoogle.com/next/19/tokyo/sessions?session=D1-7-S01) を参照した。

| 項目 | VPC Firewall | VPC Service Controls |
|:--|:--|:--|
| コントロールパス | インターネット ←→ VM <br>VM ←→ VM <br>オンプレミス ←→ VM | インターネット → GCP サービス <br>VM → GCP サービス <br>オンプレミス → GCP サービス <br>GCP サービス ←→ GCP サービス |
| コントロールに使える条件 | 5-tuple (src/dst IP/port & protocol) <br>VM タグ, VM サービスアカウント | GCP プロジェクト, VPC ネットワーク <br>インターネットの IP アドレス <br>サービスアカウント|
| ポリシーの適用対象 | VPC ネットワーク <br>タグで定義される VM のグループ <br>サービスアカウントで定義される VM のグループ | プロジェクトごとの API ベースのリソース |

## VPC Service Controls 設定テスト

### テスト内容
VM インスタンスから GCS (Google Cloud Storage) へのアクセスのコントロールをする VPC Service Controls を、下記構成でテストしていく

![TEST_VPCSC_01_ teisei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/1db45f0c-95b0-b884-c252-e3da8332bf44.png)


### 実施手順
1. 対象 GCS の作成
2. 設定アカウントへの IAM のロール 付与
3. サービス境界の作成
4. 反映確認

### 1. 対象 GCS の作成
制御対象とする GCS を作成する
作成したことがなかったので、作成の仕方から記載する

GCS の無料枠とするために下記で作成する

- GCS 無料枠
    - ストレージクラス (`-c`)
        - STANDARD
    - リージョン (`-l`)
        - 次の 3つのみ US-WEST1、US-CENTRAL1、US-EAST1
- その他
    - プロジェクト (`-p`)
        - GCS を作成するサービスプロジェクト名を入れる
    - バケットの均一なバケットレベルのアクセスを有効化 (`-b on`)

```sh:サービスプロジェクトのユーザアカウントでログイン
gcloud config set accout SERVICEPROJECT_USERACCOUNT
```


```sh:gsutil_create
$ gsutil mb -p SERVICE-PROJECT-NAME -c STANDARD -l us-west1 -b on gs://my-serviceproject-bucket/

Creating gs://my-serviceproject-bucket/...
```

作成したバケットへ画像を試しにUploadする

```sh:gsutil_upload
$ gsutil cp Pictures/neko.png gs://my-serviceproject-bucket/
Copying file://Pictures/neko.png [Content-Type=image/png]...
/ [1 files][  5.9 KiB/  5.9 KiB]                                                
Operation completed over 1 objects/5.9 KiB.  
```

バケットの中身を表示する

```sh:gsutil_ls
% gsutil ls -l gs://my-serviceproject-bucket/ 

      6046  2020-10-11T10:50:52Z  gs://my-serviceproject-bucket/neko.png
TOTAL: 1 objects, 6046 bytes (5.9 KiB)
```

全ユーザに読み取り権限を付与する

```
gsutil iam ch allUsers:objectViewer gs://my-serviceproject-bucket
```

他のサービスプロジェクトの VM インスタンスにログインして、バケット中身が表示できることを確認する

```
$ gsutil ls -l gs://my-serviceproject-bucket/ 
      6046  2020-10-11T10:50:52Z  gs://my-serviceproject-bucket/neko.png
TOTAL: 1 objects, 6046 bytes (5.9 KiB)
```

インターネットからも画像見れるようになっていることを確認する

https://storage.googleapis.com/my-serviceproject-bucket/neko.png

![スクリーンショット 2020-10-12 0.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/bb5806d7-9e52-447b-8943-2cd77e70d464.png)


※権限削除は以下でできる。(このタイミングではしない)

```
gsutil iam ch -d allUsers:objectViewer gs://my-serviceproject-bucket
```

### 2. 設定アカウントへの IAM のロール 付与
今回は管理者となり、Google Cloud Console からも管理するため、下記2つを付与する

```sh:組織管理者のユーザアカウントでログイン
gcloud config set accout ORGANIZATION_USERACCOUNT
```

```sh:組織IDの表示
gcloud organizations list
```

上記で表示できたORGANIZATION_IDを下記で使用して、付与したアカウントメンバーを指定して付与する

```sh:gcloudでのVPCSC管理者role付与
gcloud organizations add-iam-policy-binding ORGANIZATION_ID \
  --member="user:example@customer.org" \
  --role="roles/accesscontextmanager.policyAdmin"
gcloud organizations add-iam-policy-binding ORGANIZATION_ID \
  --member="user:example@customer.org" \
  --role="roles/resourcemanager.organizationViewer"
```

### 3.サービス境界の作成

サービス境界作成にはプロジェクト番号(`PROJECT_NUMBER`)が必要になるので、下記で表示する

```sh:サービスプロジェクトのユーザアカウントでログイン
gcloud config set account SERVICEPROJECT_USERACCOUNT
```

必要な API の有効化を実施する

```sh:AccessContextManagerAPI有効化
$ gcloud services list --available | grep context               
accesscontextmanager.googleapis.com                   Access Context Manager API

$ gcloud services enable accesscontextmanager.googleapis.com 
$ gcloud services enable cloudresourcemanager.googleapis.com
```

下記からプロジェクト番号をメモする(サービス境界作成時のxxxxxx箇所に使用する)
プロジェクトをホスト・サービスに分けている場合は、ホストプロジェクトも一緒にサービス境界に含めないとうまくいかないのでそちらもメモする(サービス境界作成時のyyyyy箇所に使用する)

```
gcloud projects list
```

アクセスポリシーを作成する

```
gcloud access-context-manager policies create \
--organization ORGANIZATION_ID --title ServiceProd
```

作成したアクセスポリシーを表示する

```
gcloud access-context-manager policies list \
    --organization ORGANIZATION_ID
```

上記で表示した NAME を使用して下記でサービス境界を作成する

```
gcloud access-context-manager perimeters create ServiceProdPerimeter \
--title="Service Production Perimeter" \
--resources=projects/xxxxxx,projects/yyyyy \
--restricted-services=storage.googleapis.com \
--policy=NAME
```

```sh:サービス境界線一覧表示
gcloud access-context-manager perimeters list
```

```sh:詳細表示
% gcloud access-context-manager perimeters describe ServiceProdPerimeter 
name: accessPolicies/[NAME]/servicePerimeters/ServiceProdPerimeter
status:
  resources:
  - projects/xxxxx,projects/yyyyy
  restrictedServices:
  - storage.googleapis.com
title: Service Production Perimeter
```

※削除は下記で可能 (このタイミングではしない)

```
gcloud access-context-manager perimeters delete ServiceProdPerimeter
```


### 4. 反映確認

他プロジェクトの VM インスタンスにログインして、バケット中身が表示でなくなったことを確認する

```
$ gsutil ls -l gs://my-serviceproject-bucket/ 
AccessDeniedException: 403 Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier: xxxxxx
```

インターネットからも見れなくなっていることを確認できる

https://storage.googleapis.com/my-serviceproject-bucket/neko.png

![スクリーンショット 2020-10-12 1.05.04のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/88b8ada1-928b-104c-c003-398c046e0208.png)

サービスプロジェクト内の VM インスタンスからは問題なくアクセスできる

```
$ gsutil ls -l gs://my-serviceproject-bucket/ 
      6046  2020-10-11T10:50:52Z  gs://my-serviceproject-bucket/neko.png
TOTAL: 1 objects, 6046 bytes (5.9 KiB)
```


Cloud Console からも見れなくなっていることが確認できる
![スクリーンショット 2020-10-12 1.56.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/c13514e4-de4a-6836-e04f-fe5219b93d45.png)


## おわりに
VPC Service Controls の内容を把握して、軽く試すことまでできた
今後は追加の設定試験や、限定公開 Google アクセスをする方法を調査・構築をしていく予定

## 参考
VPC Service Controls の概要
https://cloud.google.com/vpc-service-controls/docs/overview?hl=ja
サポートされているプロダクトと制限事項
https://cloud.google.com/vpc-service-controls/docs/supported-products?hl=ja
VPC Service Controls の管理に必要な IAM のロール
https://cloud.google.com/vpc-service-controls/docs/access-control?hl=ja
ストレージ バケットの作成
https://cloud.google.com/storage/docs/creating-buckets?hl=ja#storage-create-bucket-gsutil
Cloud Storage の Always Free の使用量上限
https://cloud.google.com/storage/pricing?hl=ja#cloud-storage-always-free
アクセス ポリシーの作成
https://cloud.google.com/access-context-manager/docs/create-access-policy?hl=ja
アクセス ポリシーの管理
https://cloud.google.com/access-context-manager/docs/manage-access-policy?hl=ja
サービス境界の作成
https://cloud.google.com/vpc-service-controls/docs/create-service-perimeters?hl=ja
VPC Service Controls > トラブルシューティング
https://cloud.google.com/vpc-service-controls/docs/troubleshooting?hl=ja
Google Cloud Next ’19 in Tokyo D1-7-S01 実例から学ぶ、VPC Service Control Deep Dive
https://cloud.withgoogle.com/next/19/tokyo/sessions?session=D1-7-S01