Google Cloud 共有VPCによるインターネットアクセス制御

## 内容
組織ポリシーにより、PublicIPの付与を禁止したプロジェクトがある。
ホストプロジェクトからサービスプロジェクトへ共有VPCをアタッチし、ホストプロジェクトのCloud NAT経由でインターネットへのアクセスを実施する。
最後に、ホストプロジェクトのFirewallによってサービスプロジェクトのインスタンスが正しく制御できることを確認

## 構成図
ホストプロジェクト：shared host PJ
-> External IPの利用可能

サービスプロジェクト1:Service PJ1
サービスプロジェクト2:Service PJ2
-> 組織ポリシーにてサービスプロジェクトではExternal IPの利用を禁止

共有VPCサブネット：internet-access 172.16.0.0/12
Cloud NATをinternet-accessのサブネットに接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/30c1c2b4-49fd-9561-359b-a309111ef821.png)

## 組織階層
組織名：xcloudyx.net
組織ポリシー:パブリックIPの利用を禁止している
組織から配下のフォルダおよびプロジェクトにポリシーを継承している
Adminフォルダに関しては管理者用として利用しており、パブリックIPの利用を許可している
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/da0eeeaf-14e5-ba05-deae-998c19856718.png)

## 共有VPC作成に伴う権限の付与
必要な権限は以下の通り
[参考ページ:共有 VPC 管理者の指名](https://cloud.google.com/vpc/docs/provisioning-shared-vpc?hl=ja#nominating_shared_vpc_admins_for_the_organization)

[プロジェクトレベル]
  compute.projects.get -> **Compute 閲覧者**
  resourcemanager.projects.getIamPolicy -> **Project IAM 管理者**

[組織レベル]
  compute.organizations.enableXpnHost -> **Compute Shared VPC 管理者**
[参考ページ：Compute Shared VPC Admin role](https://cloud.google.com/compute/docs/access/iam?hl=ja#compute.xpnAdmin)

Compute Shared VPC Adminの権限を付与するには、組織もしくはフォルダを選択して実施する
![貼り付けた画像_2023_10_11_13_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/c33e566b-443c-2ae2-c1dd-f5d9a1fed929.png)

## ホストプロジェクトの作成
**共有VPCのホストプロジェクト名**を入力、組織および場所を選択し、**作成**を選択
![貼り付けた画像_2023_11_28_13_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/a03a5405-9ed1-2c3a-cf7a-11a979665577.png)

共有VPCの設定時に必要となるため、ComputeEngineAPIを有効化しておく

## サービスプロジェクトの作成
**サービスプロジェクト名**を入力、組織および場所を選択し、**作成**を選択
![貼り付けた画像_2023_11_29_16_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/d4938c61-346f-4bba-2910-3da5c63b9c51.png)

共有VPCの設定時に必要となるため、ComputeEngineAPIを有効化しておく

## ホストプロジェクトにサービスプロジェクトに共有するVPCを作成
**ホストプロジェクトを選択** -> **VPCネットワーク** -> **VPCネットワーク** -> **VPCネットワークを作成**を選択
![貼り付けた画像_2023_11_29_17_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/e5122a13-5e6f-1476-e79b-780096c04835.png)

名前を入力し、サブネット作成モード**カスタム**にチェックを入れる
![貼り付けた画像_2023_11_29_17_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/f6f9482a-8cb0-cc47-1d1f-d78ce0abd754.png)

**サブネットの名前**、**リージョン**および**サブネットのアドレスレンジを入力**し、**完了**を選択
![貼り付けた画像_2023_11_29_17_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/33a295a0-218b-f0de-33d8-c06992524d93.png)


必要なFWルールにチェックを入れ、**作成**を選択
![貼り付けた画像_2023_11_29_17_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/1ede6391-81eb-b703-f154-8e98f96ec628.png)

ここまでで、共有VPCの作成準備は完了

## 共有VPCの作成
共有VPCを作成するプロジェクトで実施する
![貼り付けた画像_2023_11_28_13_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/46eb3067-d2d4-91c7-df87-b8f3dada6e42.png)

**有効にして続行**を選択
![貼り付けた画像_2023_11_29_9_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/c62ee7ad-e6d7-11ed-5d81-0a8587f81d28.png)

ComputeEngineのAPIを有効化しておかないとエラーとなる
また、権限も足りている必要がある -> [権限の付与](#権限の付与)参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/7ebf8245-3a3a-0633-d5b6-89f6dd57b3e3.png)

サービスプロジェクトへ共有したいサブネットを選択し、**続行**をクリック
今回は、us-centra1のサブネット：172.16.0.0/12を共有する
![貼り付けた画像_2023_11_29_10_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/229b80c3-e1f6-7117-0583-d1a1a99e6ff2.png)

サブネットを共有したいプロジェクトを選択し、**保存**をクリック
![貼り付けた画像_2023_11_29_10_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/7a26496a-eb1e-1c87-5dba-bcbc4177a2c3.png)

追加したいサービスプロジェクトもComputeEngineAPIを有効化しておかないとエラーとなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/781162c5-f421-5070-7edf-3ec882dcd0ab.png)

### ホストプロジェクト側
![貼り付けた画像_2023_11_29_10_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/5f4e0999-f567-c1b3-193d-5828753e40c3.png)

![貼り付けた画像_2023_11_29_10_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/dfaf7ae6-ee92-1766-7d2b-229a8733025b.png)

### サービスプロジェクト側
![貼り付けた画像_2023_11_29_10_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/f770d817-d289-a121-1031-c40091b025ed.png)

## インターネットアクセス用ComputeEngineインスタンスの作成
Shared VPCで払い出された172.16.0.0/12のサブネットにインスタンスを作成する

**Service PJ** -> **ComputeEngine** -> **VMインスタンス** -> **インスタンスを作成**を選択
![貼り付けた画像_2023_11_29_11_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/3064614c-7da4-7eb2-e109-14f157973c63.png)

ホストプロジェクトから共有されたサブネットがあるリージョンを選択する
今回は**us-central1**
![貼り付けた画像_2023_11_29_11_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/861d89cd-9eac-e16a-f6a0-4537809b1f24.png)

下にスクロールし、**詳細オプション** -> **ネットワーキング**から
**共有ネットワーク**を選択し、ホストプロジェクトから共有されたサブネットを選択する
![貼り付けた画像_2023_11_29_11_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/d9924ea3-1c42-c2c0-63a9-fad6c4bd9be0.png)

また、外部IPは**なし**とし、**完了**を選択
今回は組織ポリシーで外部IPの付与を許可していない
![貼り付けた画像_2023_11_29_11_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/6c2c708e-e36f-c50b-4fd0-407b7908db94.png)

最後に、**作成**を選択
![貼り付けた画像_2023_11_29_11_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/adf818f6-a384-e75d-326f-3c03406b85d1.png)

### インターネットにアクセスできないことを確認
作成したComputeEngineインスタンスは外部IPをもっていないため、現状はインターネットにアクセスできない

digコマンドでwww.google.co.jpのIPアドレスを確認
```
manabu_admin@instance-10:~$ dig www.google.co.jp

; <<>> DiG 9.16.44-Debian <<>> www.google.co.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6612
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.google.co.jp.              IN      A

;; ANSWER SECTION:
www.google.co.jp.       300     IN      A       142.250.1.94

;; Query time: 15 msec
;; SERVER: 169.254.169.254#53(169.254.169.254)
;; WHEN: Wed Nov 29 02:31:06 UTC 2023
;; MSG SIZE  rcvd: 61
```

curlコマンドでアクセスを実行するが、応答なしとなる。
```
manabu_admin@instance-10:~$ curl 142.250.1.94
curl: (28) Failed to connect to 142.250.1.94 port 80: Connection timed out
```

digコマンドはデフォルトだとインストールされていないため、別途導入が必要
```
manabu_admin@instance-10:~$ sudo apt-cache search dig
manabu_admin@instance-10:~$ sudo apt-get install -y dnsutils
```

## ホストにてサービスPJ向けのCloudNATを作成
ホストプロジェクトにてCloudNATを作成し、サービスプロジェクト側で作成した
ComputeEngineからインターネットへのアクセスができるようにする
![貼り付けた画像_2023_11_29_11_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/b4df013b-c9c3-4f17-a0c5-7492eee45614.png)

**ゲートウェイの名称**：Cloud NATインスタンスの名前
**NATタイプ**:公開（インターネットにアクセスするため、Cloud NATにパブリックIPが必要）
**Cloud Routerの選択**:NATを利用する際にCloud Routerが必要となるため作成する

![貼り付けた画像_2023_11_29_13_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/5965f4c1-6c31-8d6e-17f3-23ce4666a249.png)

**新しいルーターを作成**を選択
![貼り付けた画像_2023_11_29_13_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/40988b87-aa40-8a69-db29-8e51fab4f922.png)

**名前**だけ入力し、**作成**を選択
![貼り付けた画像_2023_11_29_13_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/6b640d04-e1bf-0aa2-2b33-a2c05e74fb42.png)

パブリックIPアドレスにアクセスするサブネットのIP範囲を、Cloud NATにマッピングする
**カスタム**を選択
![貼り付けた画像_2023_11_29_13_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/59f9843e-6461-9271-0fb1-8000006820da.png)

Cloud NAT経由でインターネットにアクセスさせたいサブネットを選ぶ
サブネット名「**internet-access**」を選択
![貼り付けた画像_2023_11_29_13_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/6fe5077d-54e8-b6c3-e264-af5b55e9bc7d.png)

Cloud NATのIPに指定がなければ、自動のにする。
下記の内容を確認しサービスティアを選択

**ネットワークサービスティア　プレミアム**:トラフィックは Google の高品質グローバル バックボーンを通り、ユーザーに最も近い Google エッジ ピアリング ポイントから出ていきます。
**ネットワークサービスティア　スタンダード**:トラフィックは送信先または送信元のクラウド リージョンに最も近いピアリング ポイントから Google ネットワークに出入りします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/0bc17b7d-5ebf-98ef-43c4-a58b7c89aa7b.png)

最後に、**作成**を選択
これで、パブリックIPを持たないインスタンスからインターネットへの通信が必要な場合、
Cloud NATを経由することで、実現が可能となる。

![貼り付けた画像_2023_11_29_13_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/d4979973-9cb6-5640-71e7-7d6f7844d440.png)

## サービスプロジェクトからのインターネットアクセス

digコマンドでwww.google.co.jpのIPアドレスを確認
```
kyndryl_owner@instance-10:~$ dig www.google.co.jp

; <<>> DiG 9.16.44-Debian <<>> www.google.co.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65181
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.google.co.jp.              IN      A

;; ANSWER SECTION:
www.google.co.jp.       300     IN      A       173.194.193.94

;; Query time: 4 msec
;; SERVER: 169.254.169.254#53(169.254.169.254)
;; WHEN: Wed Nov 29 04:54:08 UTC 2023
;; MSG SIZE  rcvd: 61
```

curlコマンドでアクセスを実行し応答を確認した
```
kyndryl_owner@instance-10:~$ curl 173.194.193.94
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
```

## Firewallの動作確認
ホストプロジェクト側のファイアウォールルールを変更することで、トラフィックの制御ができることを確認する
具体的には、サービスプロジェクトのComputeEngineからHTTPトラフィックがCloud NAT経由に通信できないこと

### Firewallの変更 
共有VPCに設定されている、現状のFirewallルールを確認する
デフォルトでは、下り（google cloudからインターネット向け通信）は全て許可となっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/76f2ac28-086b-c9e9-2c11-b5d7f61ea21f.png)

従って、下りに対してTCP80を拒否するルールを作成する
これにより、curlコマンドでアクセスできないことを確認する
**ファイアウォールルールを作成**を選択
![貼り付けた画像_2023_11_29_17_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/d784c15e-a620-6637-77a8-b049407d8d5c.png)


**ポリシー名**を入力し、**続行**を選択
![貼り付けた画像_2023_11_29_17_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/1ea33852-dca0-bbbc-bcfc-dbe980a3b759.png)

**ルールを追加**を選択
![貼り付けた画像_2023_11_29_17_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/7e794da9-77c7-6210-5af3-c0efb9b61f11.png)

**名前**：ポリシー名を入力
**ネットワーク**:共有VPC名を選択
**トラフィックの方向**:Google Cloudからインターネット向けのため、下りを選択
**一致した時のアクション**:拒否とする
**送信先IPv4範囲**:インターネット向けを全て拒否するため、0.0.0.0/0とする
![貼り付けた画像_2023_11_29_17_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/7c02df80-756f-f27f-38b7-5988ad6e0831.png)

**指定したプロトコルとポート**:TCP80を拒否するため、TCPにチェックをいれ、ポートに80を入力
最後に。**作成**を選択
![貼り付けた画像_2023_11_29_18_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/a955d547-2ed5-c4cb-c2b0-2c6dd37d45a5.png)

ファイアウォールポリシーに追加したルールが確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703043/d7adb633-1993-21c0-8c66-af5f68e5282a.png)

### 動作確認
サービスプロジェクトのComputeEngineからHTTPアクセスをためしてみる

「www.kyndryl.com」に対して、HTTP80の通信を実施すると、タイムアウトする
```
kyndryl_owner@instance-1:~$ curl --max-time 5 http://www.kyndryl.com
curl: (28) Failed to connect to www.kyndryl.com port 80: Connection timed out
```

拒否していないHTTPS443通信の場合、正常に応答が返ってくることからFirewallが正しく動作している
```
kyndryl_owner@instance-1:~$ curl --max-time 5 https://www.kyndryl.com
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://www.kyndryl.com/us/en">here</a>.</p>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v84a3a4012de94ce1a686ba8c167c359c1696973893317" integrity="sha512-euoFGowhlaLqXsPWQ48qSkBSCFs3DPRyiwVu3FjR96cMPx+Fr+gpWRhIafcHwqwCqWS42RZhIudOvEI+Ckf6MA==" data-cf-beacon='{"rayId":"82d9ae0fabb622ca","b":1,"version":"2023.10.0","token":"82de1bcba60e4fe390aecc52326b7583"}' crossorigin="anonymous"></script>
</body></html>
```