Google Cloud 組織ポリシー

## はじめに
Google Cloud には[組織ポリシー](https://cloud.google.com/resource-manager/docs/organization-policy/overview?hl=ja)がある
適用できるポリシーは多くあり、何を適用したらいいのか個人的にわかりにくかったので、
組織利用でよく利用するであろう、ネットワーク利用制限や利用リージョン制限などの観点でまとめてみた
(調べたら[デザインパターン](https://events.withgoogle.com/solution-design-pattern-enterprise-fundamentals/org-policy/)なるものがあった)
また、実際の設定方法としても Terraform で試したのでそのコードも記載する

## 組織ポリシー

組織のポリシー サービスを使用すると、組織の Cloud リソースをプログラムで一元管理できる ([ドキュメント](https://cloud.google.com/resource-manager/docs/organization-policy/overview?hl=ja))

組織ポリシーを利用する条件としては組織を作成しておく必要がある
(過去に組織作成自体は別記事に記載。[組織作成](https://qiita.com/suzuyui/items/947867f52897417ee31b)、[組織作成・Terraform](https://qiita.com/suzuyui/items/879dfa5d837a19c39a54))

組織全体や特定のフォルダ配下のプロジェクトへ制約を、組織の管理者側が制約をかけられる

利用できる組織ポリシーの一覧は少しわかりにくいところにあって、下記となる
「Resource Manager」 > 「ドキュメント」 > 「リソース」 > 「組織のポリシーの制約」 > 「[使用可能な制約](https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints?hl=ja#available_constraints)」 

設定はリストとブールの2つがある ([制約方法](https://cloud.google.com/resource-manager/docs/organization-policy/overview?hl=ja#constraints))

### 利用例

例として、下記を設定ポリシーとすると、下記表のようなポリシー・値を利用できる 

- Public IP
    - 設定可能な VM を制限
    - Loadbalancer, CloudSQL では設定不可
- リソースロケーション
    - 日本国内限定
- 外部ネットワーク接続
    - 特定フォルダ配下プロジェクトは不可
    - VPN 先 IP を制限
- アカウント
    - 利用できるドメインを制限
    - [デフォルトのサービスアカウント](https://cloud.google.com/iam/docs/service-accounts?hl=ja#default) に対する IAM ロールの自動付与の無効化
        - <code dir="ltr"><var>project-number</var>-compute@developer.gserviceaccount.com</code> 
        - デフォルトの動作は**編集者ロール（roles/editor）** が付与される
        - 最小権限の原則に従い、自動的なロール付与を無効にすることが強い推奨がされている
        - 注記： デフォルトのサービスアカウントを Compute Engine などに使用する場合
            - ログ書き込み権限を与えないとログが当然書けないので注意すること
            - [Ops Agent で必要になる権限](https://cloud.google.com/logging/docs/agent/ops-agent/authorization?hl=ja#create-service-account) : `roles/logging.logWriter`, `roles/monitoring.metricWriter`
- PSC
    - 転送制限
- Cloud Storage
    - 全体公開設定不可
- Google APIs
    - 利用可能 API を制限
        - この機能は試してみているが、制約がありそうで特定の機能の Deny しか今の所うまく行ってない (私のやり方が悪い可能性もあり)
        - [ドキュメント](https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints?hl=ja) の `constraints/serviceuser.services` を参照
- TLS Version (2024.03.20追加) / [ドキュメント](https://cloud.google.com/assured-workloads/docs/restrict-tls-versions?hl=ja#gcloud)
    - コンプライアンス要件を満たすため、古い TLS バージョンを使用しているクライアントからの handshake リクエストを拒否する
    - ここでは TLS 1.2 以上 (v1.0,1.1を拒否)に制限する

(非常に参考になる記事： [Google Cloud のイケてる(ような気がする)サービス・機能のご紹介](https://medium.com/google-cloud-jp/google-cloud-features-worth-mentioning-d82b4ee6758a) ※特に、組織ポリシーの箇所を参照。下記は基本こちらの記事を参照して、一覧見て必要そうなのをさらに追加したもの)


| Policy | 対象 | 概要 | 形式 | 本構成でのパラメータ(例) |
|:--|:--|:--|:--|:--|
| compute.vmExternalIpAccess | Compute Engine | VM インスタンス用に許可される外部 IP を定義する | List | インスタンスのID |
| compute.restrictSharedVpcHostProjects | Compute Engine | 共有 VPC ホスト プロジェクトの制限 | List | ホストプロジェクトID|
| compute.restrictDedicatedInterconnectUsage | Interconnect  | Dedicated Interconnect の使用の制限 | List | deny, under:[サービスフォルダID] |
| compute.restrictPartnerInterconnectUsage | Interconnect | Partner Interconnect の使用の制限 | List | deny, under:[サービスフォルダID] |
| compute.restrictVpnPeerIPs | VPN | VPN ピア IP の制限 | List | VPN対向先PublicIP |
| compute.restrictVpcPeering | VPC Peering | VPC ピアリング使用量の制限 | List | deny, under:[サービスフォルダID] |
| compute.restrictLoadBalancerCreationForTypes | Loadbalancer | ロードバランサの種類に基づいてロードバランサの作成を制限する | List | is:INTERNAL_TCP_UDP <br> is:INTERNAL_HTTP_HTTPS |
| compute.disableInternetNetworkEndpointGroup | インターネット NEG | インターネット ネットワーク エンドポイント グループの無効化 | Bool | true |
| compute.restrictProtocolForwardingCreationForTypes | Compute Engine | IP アドレスの種類に基づいてプロトコル転送を制限する | List | is:INTERNAL |
| compute.restrictCloudNATUsage | CloudNAT | Cloud NAT の使用制限 | List | deny, under:[サービスフォルダID] |
| gcp.resourceLocations | Resource | リソース ロケーションの制限 | List | in:asia-northeast1-locations <br>in:asia-northeast2-locations<br>is:ASIA1 |
| compute.skipDefaultNetworkCreation | VPC | デフォルト ネットワークの作成をスキップ | Bool | true |
| iam.allowedPolicyMemberDomains | IAM  | ドメインで制限された共有 | List | [Google Admins](https://admin.google.com/ac/accountsettings?hl=ja) の 顧客 ID |
| sql.restrictPublicIp | CloudSQL | Cloud SQL インスタンスに対するパブリック IP のアクセスを制限する | Bool | true |
| storage.publicAccessPrevention | Cloud Storage | 公開アクセスの防止を適用する (2021.09.25時点 プレビュー) | Bool | true |
| compute.disablePrivateServiceConnectCreationForConsumers | Private Service Connect | コンシューマ向け Private Service Connect の無効化 | List | is:GOOGLE_APIS <br> is:SERVICE_PRODUCERS |
| essentialcontacts.allowedContactDomains | 重要な連絡先 | [重要な連絡先] に追加できるメールアドレスのドメインのセットを定義 | List | 自分のドメイン |
| constraints/serviceuser.services | Google APIs | 許可される Google Cloud API とサービスを制限する | List | 特定の API しか Deny できなそう ([ドキュメント](https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints?hl=ja) の `constraints/serviceuser.services` を参照) |
| constraints/iam.automaticIamGrantsForDefaultServiceAccounts | Service Account | デフォルトのサービス アカウントに対する IAM ロールの自動付与の無効化 | Bool | true |
| constraints/gcp.restrictTLSVersion | [対象サービス](https://cloud.google.com/assured-workloads/docs/restrict-tls-versions?hl=ja#supported-services) | 特定 TLS バージョンを拒否する([ドキュメント](https://cloud.google.com/assured-workloads/docs/restrict-tls-versions)) | List | TLS_VERSION_1, TLS_VERSION_1_1 |

## Terraform での実践コード

Terraform で実際に試したコードは下記の通り
※`var`やほかリソースからの変数などはなんとなくで察してください

- 利用モジュール
    - [google_organization_policy](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_organization_policy)
        - 組織全体へのポリシー適用
    - [google_folder_organization_policy](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_folder_organization_policy)
        - 特定フォルダ配下へのポリシー適用

```tf
## 組織ポリシー
### デフォルトネットワーク作成の無効化
resource "google_organization_policy" "skipDefaultNetworkCreation" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.skipDefaultNetworkCreation"

  boolean_policy {
    enforced = true
  }
}

### VM インスタンス用に許可される外部 IP を定義する
resource "google_organization_policy" "vmExternalIpAccess" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.vmExternalIpAccess"

  list_policy {
    allow {
      values = [google_compute_instance.service1_gce1.id]
    }
  }
}

### 共有 VPC ホスト プロジェクトの制限
#### Service Folder (organization_service_folder) 配下は共有 VPC を制限 (host_project が共有 VPC ホストプロジェクト)
resource "google_folder_organization_policy" "service1_restrictSharedVpcHostProjects" {
  folder     = google_folder.organization_service_folder.id
  constraint = "compute.restrictSharedVpcHostProjects"

  list_policy {
    allow {
      values = [google_project.host_project.id]
    }
  }
}

### Dedicated Interconnect の使用の制限
resource "google_organization_policy" "restrictDedicatedInterconnectUsage" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictDedicatedInterconnectUsage"

  list_policy {
    deny {
      values = ["under:${google_folder.organization_service_folder.id}"]
    }
  }
}

### Partner Interconnect の使用の制限
resource "google_organization_policy" "restrictPartnerInterconnectUsage" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictPartnerInterconnectUsage"

  list_policy {
    deny {
      values = ["under:${google_folder.organization_service_folder.id}"]
    }
  }
}

### VPN ピア IP の制限
resource "google_organization_policy" "restrictVpnPeerIPs" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictVpnPeerIPs"

  list_policy {
    allow {
      values = [var.vpn.peer_global_ip_address]
    }
  }
}

### VPC ピアリング使用量の制限
resource "google_organization_policy" "restrictVpcPeering" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictVpcPeering"

  list_policy {
    deny {
      values = ["under:${google_folder.organization_service_folder.id}"]
    }
  }
}

### ロードバランサの種類に基づいてロードバランサの作成を制限する
resource "google_organization_policy" "restrictLoadBalancerCreationForTypes" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictLoadBalancerCreationForTypes"

  list_policy {
    allow {
      values = ["is:INTERNAL_TCP_UDP", "is:INTERNAL_HTTP_HTTPS"]
    }
  }
}

### インターネット ネットワーク エンドポイント グループの無効化
resource "google_organization_policy" "disableInternetNetworkEndpointGroup" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.disableInternetNetworkEndpointGroup"

  boolean_policy {
    enforced = true
  }
}

### IP アドレスの種類に基づいてプロトコル転送を制限する
resource "google_organization_policy" "restrictProtocolForwardingCreationForTypes" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictProtocolForwardingCreationForTypes"

  list_policy {
    allow {
      values = ["is:INTERNAL"]
    }
  }
}

### Cloud NAT の使用制限
resource "google_organization_policy" "restrictCloudNATUsage" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.restrictCloudNATUsage"

  list_policy {
    deny {
      values = ["under:${google_folder.organization_service_folder.id}"]
    }
  }
}

### リソースロケーションの制限
resource "google_organization_policy" "gcp_resourceLocations" {
  org_id     = var.gcp_common.org_id
  constraint = "gcp.resourceLocations"

  list_policy {
    allow {
      values = [
        "in:asia-northeast1-locations",
        "in:asia-northeast2-locations",
        "is:ASIA1",
        "in:us-west1-locations",
      ]
    }
  }
}

### ドメインで制限された共有
resource "google_organization_policy" "iam_allowedPolicyMemberDomains" {
  org_id     = var.gcp_common.org_id
  constraint = "iam.allowedPolicyMemberDomains"

  list_policy {
    allow {
      values = [var.google_admin_customer_id]
    }
  }
}

### Cloud SQL の Public IP 制限
resource "google_organization_policy" "sql_restrictPublicIp" {
  org_id     = var.gcp_common.org_id
  constraint = "sql.restrictPublicIp"

  boolean_policy {
    enforced = true
  }
}

### 公開アクセスの防止を適用する
resource "google_organization_policy" "storage_publicAccessPrevention" {
  org_id     = var.gcp_common.org_id
  constraint = "storage.publicAccessPrevention"

  boolean_policy {
    enforced = true
  }
}

### コンシューマ向け Private Service Connect の組織全体での Google APIS 以外の無効化
resource "google_organization_policy" "disablePrivateServiceConnectCreationForConsumers" {
  org_id     = var.gcp_common.org_id
  constraint = "compute.disablePrivateServiceConnectCreationForConsumers"

  list_policy {
    deny {
      values = ["is:SERVICE_PRODUCERS"]
    }
  }
}

### コンシューマ向け Private Service Connect のサービスプロジェクトでの無効化
resource "google_folder_organization_policy" "service1_disablePrivateServiceConnectCreationForConsumers" {
  folder     = google_folder.organization_service_folder.id
  constraint = "compute.disablePrivateServiceConnectCreationForConsumers"

  list_policy {
    deny {
      values = ["is:GOOGLE_APIS", "is:SERVICE_PRODUCERS"]
    }
  }
}

### [重要な連絡先] に追加できるメールアドレスのドメインのセットを定義
resource "google_organization_policy" "essentialcontacts_allowedContactDomains" {
  org_id     = var.gcp_common.org_id
  constraint = "essentialcontacts.allowedContactDomains"

  list_policy {
    allow {
      values = ["@${var.gcp_common.org_id}"]
    }
  }
}

### 許可される Google Cloud API とサービスを制限する [現状 deny と特定 API しかうまくいかない？]
#### https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints?hl=ja
resource "google_folder_organization_policy" "service_serviceuser_services" {
  folder     = google_folder.organization_service_folder.id
  constraint = "serviceuser.services"

  list_policy {
    suggested_value = "compute.googleapis.com"

    deny {
      values = [
        "doubleclicksearch.googleapis.com",
        "replicapool.googleapis.com",
        "replicapoolupdater.googleapis.com",
        "resourceviews.googleapis.com",
      ]
    }
  }
}

### デフォルトのサービス アカウントに対する IAM ロールの自動付与の無効化
resource "google_organization_policy" "automaticIamGrantsForDefaultServiceAccounts" {
  org_id     = var.gcp_common.org_id
  constraint = "iam.automaticIamGrantsForDefaultServiceAccounts"

  boolean_policy {
    enforced = true
  }
}

### TLS Version の制限 (v1.0, v1.1 を拒否)
#### https://cloud.google.com/assured-workloads/docs/restrict-tls-versions?hl=ja
resource "google_organization_policy" "restrict_tls_version" {
  org_id     = var.gcp_common.org_id
  constraint = "gcp.restrictTLSVersion"

  list_policy {
    deny {
      values = [
        "TLS_VERSION_1",
        "TLS_VERSION_1_1",
      ]
    }
  }
}

```

## おわりに
組織ポリシーを調べてパラメータを確認して設定を試してみた

ポリシー種別の追加を定期的にウォッチして必要なものを検証・利用していきたい

## 参照

https://cloud.google.com/resource-manager/docs/organization-policy/overview?hl=ja

https://events.withgoogle.com/solution-design-pattern-enterprise-fundamentals/org-policy/

https://medium.com/google-cloud-jp/google-cloud-features-worth-mentioning-d82b4ee6758a


https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints?hl=ja

https://cloud.google.com/assured-workloads/docs/restrict-tls-versions?hl=ja