Google Cloud クラウドプロバイダからのアクセスの承認とログ機能

## はじめに
Google Cloud では[アクセスの透明性とアクセスの承認](https://cloud.google.com/security/products/access-transparency?hl=ja)に記載がある通り、
管理者の**アクセスログ**と**承認コントロール**により、**クラウド プロバイダによるアクセス**を**可視化**して**制御**できる。

ここでは、`アクセスの透明性ログ` の有効化方法と `Access Approval` を使用した Google 担当者からのアクセス承認機能の有効化方法を記載する

IaC ツールとしては `Terraform` を使用する 
(ただし後述の通り、現状は一部 GUI 設定のみ対応可能)

## アクセスの透明性ログの有効化
下記設定を有効化すると、Google の担当者が行った操作ログを記録できるようになる

### 有効化方法
アクセスの透明性ログの有効化は [issuetracker で要望が出ているが対応されてなく](https://issuetracker.google.com/issues/227875479)、そのため　[Terraform provider 側の issue も Open のまま](https://github.com/hashicorp/terraform-provider-google/issues/9077)なので、GUI での操作方法しか現状 (2024.03.03 時点) 対応できない


### GUI での有効化
[手順](https://cloud.google.com/assured-workloads/access-transparency/docs/enable?hl=ja#configuring)を参考に実施する

アクセスの透明性管理者（`roles/axt.admin`）の権限があるユーザで実行する必要がある

プロジェクトの `IAM の管理` > `設定` に移動して `設定` 内の `アクセスの透明性`箇所で有効化する

有効後は下画像のようになる

![スクリーンショット 2024-03-03 15.30.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/e42fe81d-6db4-e92b-14f0-447f0342b2e7.png)

以上で設定完了

## Access Approval を使用したアクセス承認
Access Approval の設定をすることで、Google の担当者がカスタマーケアやエンジニアリングのためデータにアクセスする必要がある場合は、常に明示的な承認が必要に設定ができる ([Access Approval の概要](https://cloud.google.com/assured-workloads/access-approval/docs/overview?hl=ja))

### Access Approval を使用・設定する前提条件

- 前述の[リソース階層以上の同じレベルでアクセスの透明性を有効](https://cloud.google.com/assured-workloads/access-approval/docs/overview?hl=ja#requirements) であること
- 設定するアカウント (Terraform のサービスアカウントなど) は `roles/accessapproval.configEditor` の権限を持っていること
- terraform がアクセスするデフォルトのプロジェクト先で `accessapproval.googleapis.com` API が有効化されていること

### 試験環境

- 実施環境 (2024.03.03 時点最新 Version)
    - terraform version: 1.7.4
    - google cloud provider version: 5.18.0

### Terraform Code 例

ここでは 2 つのフォルダ (インフラ、サービス) に分かれている環境に Access Approval を設定するコード例を記載する

- Terraform 構成
    - backend (terraform state ファイル置き場の GCS) はフォルダ一階層上の `backend.hcl`に定義してある
        - init 時に `terraform init -backend-config=../backend.hcl` で取り込む構成
    - 設定対象にする Google Folder は別のフォルダで Terraform 管理しているので、data.terraform_remote_state を使用してパラメータを参照する
- パラメータ (例：`terraform.tfvars`)
    - メール受信者 (`infrastructure_email_list`, `service_email_list`) のメールアドレスをリストで記載する
    - メール受信後に承認する Google アカウントはメール受信とは別の Google Group などを指定できるようにパラメータを分けている (`infrastructure_approvers_list`,`service_approvers_list`)
        -  例で記載している名称は [エンタープライズ組織でのセキュリティ管理者](https://cloud.google.com/docs/enterprise/best-practices-for-enterprise-organizations?hl=ja#groups-and-service-accounts) から借用
    - 既存 folder id 取得
        - 前提として、既存 folder は別の Terraform ディレクトリで作成されて、gcs の terraform state をバックエンドとしている
            - `organization_terraform_state_bucket_name` : バケット名
            - `organization_terraform_state_workspace`: workspace 名
            - `organization_terraform_state_prefix` : プレフィックス名
        - 前提として、既存の ID は output で `google_folder.[your_resource_name].id` で state ファイルで参照できるようになっている
            - `google_folder.[your_resource_name].folder_id` としなかったので `folders/[id]` で出力されるので一部 `trim` で加工している
        - 例として記載している `data`, `resource名` は下記の通り
            - data.terraform_remote_state.state.outputs.organization_infrastructure_folder_id
            - data.terraform_remote_state.state.outputs.organization_service_folder_id

この例では環境が dev, prd などをフォルダ別にして切り替えても、コード流用しやすいように folder id 取得を別の terraform state から取るようにしているが、
フォルダ ID を単純に直接指定しても問題はない

```sh:フォルダ構成
$ tree -a
|-- access_approval
|   |-- .terraform-version
|   |-- approval.tf
|   |-- data.tf
|   |-- iam.tf
|   |-- main.tf
|   |-- terraform.tfvars
|   `-- variables.tf
`-- backend.hcl
```

```.terraform-version
1.7.4
```

```tf:terraform.tfvars(例)
# 通知先メールアドレスリスト
infrastructure_email_list = ["[YOUR_EMAIL_ACCOUT]@[YOUR_EMAIL_DOMAIN]]", ]
service_email_list        = ["[YOUR_EMAIL_ACCOUT]@[YOUR_EMAIL_DOMAIN]]", ]

# 承認権限をつける Google Account リスト (iam_binding 表記)
infrastructure_approvers_list = ["group:gcp-security-admins@[YOUR_DOMAIN_NAME]", "group:gcp-network-admins@[YOUR_DOMAIN_NAME]", ]
service_approvers_list        = ["group:gcp-security-admins@[YOUR_DOMAIN_NAME]", ]

# ID 引用先のバケット情報
organization_terraform_state_bucket_name = "YOUR_ORG_TERRAFORM_STATE_BUCKET_NAME"
organization_terraform_state_workspace   = "dev" # workspace を使用してなければ (=`default`)ならば指定しない
organization_terraform_state_prefix      = "terraform/state"
```

```tf:variables.tf
variable "infrastructure_email_list" {
  type = list(string)
}

variable "service_email_list" {
  type = list(string)
}

variable "infrastructure_approvers_list" {
  type = list(string)
}

variable "service_approvers_list" {
  type = list(string)
}

variable "organization_terraform_state_workspace" {
  default = "default"
}

variable "organization_terraform_state_bucket_name" {}

variable "organization_terraform_state_prefix" {}

```

```tf:data.tf
# ステートファイルの参照
data "terraform_remote_state" "state" {
  backend   = "gcs"
  workspace = var.organization_terraform_state_workspace # workspace を使用している場合は指定する. workspace を使用してない場合は指定不要
  config = {
    bucket = var.organization_terraform_state_bucket_name # 参照する GCS を指定する
    prefix = var.organization_terraform_state_prefix      # 参照する Terraform が指定している prefix を記載する
  }
}
```

```tf:approval.tf
# インフラ管理フォルダ
resource "google_folder_access_approval_settings" "infrastructure_folder" {
  folder_id           = trim(data.terraform_remote_state.state.outputs.organization_infrastructure_folder_id, "folders/")
  notification_emails = var.infrastructure_email_list

  enrolled_services {
    cloud_product = "all"
  }
}

# サービス管理フォルダ
resource "google_folder_access_approval_settings" "service_folder" {
  folder_id           = trim(data.terraform_remote_state.state.outputs.organization_service_folder_id, "folders/")
  notification_emails = var.service_email_list

  enrolled_services {
    cloud_product = "all"
  }
}
```

```tf:iam.tf
resource "google_folder_iam_binding" "infrastructure_accessapproval_approver" {
  folder = data.terraform_remote_state.state.outputs.organization_infrastructure_folder_id
  role   = "roles/accessapproval.approver" # https://cloud.google.com/assured-workloads/access-approval/docs/access-control?hl=ja#approve-request

  members = var.infrastructure_approvers_list
}

resource "google_folder_iam_binding" "service_accessapproval_approver" {
  folder = data.terraform_remote_state.state.outputs.organization_service_folder_id
  role   = "roles/accessapproval.approver" # https://cloud.google.com/assured-workloads/access-approval/docs/access-control?hl=ja#approve-request

  members = var.service_approvers_list
}
```

```tf:main.tf(例)
terraform {
  required_version = "1.7.4"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "=5.18.0" # 2024.03.03 Latest https://registry.terraform.io/providers/hashicorp/google/5.18.0/docs
    }
  }
  backend "gcs" {
    # bucket = "XXXXX" # Terraform State Bucket Name # terraform init -backend-config=../backend.hcl
    prefix = "terraform/state/organization/access_approval"       # env manage terraform state file
  }
}


provider "google" {
  # export GOOGLE_APPLICATION_CREDENTIALS=YOUR_CREDENTIALS_PATS
}
```

```backend.hcl
bucket = "YOUR_GCS_BUCKET_NAME"
```

### Terraform 実行コマンド / Cloud Console 前後表示例
設定適用

```sh
cd access_approval
terraform init -backend-config=../backend.hcl
terraform plan
terraform apply
```

適用前

![スクリーンショット 2024-03-03 16.37.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/f8255c26-9a6c-84e8-38b5-b1952bc0e656.png)

適用後

![スクリーンショット 2024-03-03 17.04.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/bbb30967-210f-4aca-71da-1664eee48c5a.png)

以上で設定完了

## おわりに
検証で使用したのは個人のラボ環境のため、実際にはサポート契約を結んでないのでアクセス承認が来ることがない
よって、実際の承認試験は行なっていないので参照時はそれをご注意ください (参考：[承認方法ドキュメント](https://cloud.google.com/assured-workloads/access-approval/docs/approve-requests?hl=ja#approving-requests))

## 参照

https://cloud.google.com/security/products/access-transparency?hl=ja

https://cloud.google.com/assured-workloads/access-transparency/docs/enable?hl=ja

https://cloud.google.com/assured-workloads/access-approval/docs/overview?hl=ja

https://cloud.google.com/assured-workloads/access-approval/docs/using-terraform?hl=ja

https://cloud.google.com/docs/enterprise/best-practices-for-enterprise-organizations?hl=ja#groups-and-service-accounts

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/folder_access_approval_settings

https://github.com/hashicorp/terraform-provider-google/issues/9077