Google Cloud ログ集約管理

## はじめに
Google Cloud を組織で使用する上では、組織全体のログをまとめて1つのプロジェクトのログバケットや GCS へ集約して管理・保管することが可能
ここでは、設定を Terraform で実施したので試験で使用した抜粋コード例とともにまとめる
また、VPC Service Controls を設定していると追加でアクセスレベル・境界のIngress Rule を設定をする必要があるのでその設定も記載する

## 前提条件
Google Cloud で組織を作成済み
VPC Serive Controles で Cloud Logging が保護済み (未実施の場合は、設定の4.が不要)

## 設定
下記順番で実施する

1. ログ集約用のプロジェクト・バケットの作成
1. 組織レベルでのログシンク設定
1. ログ転送権限設定
1. VPC Service Controls 設定
1. ログ確認

ここでは集約したログをログエクスプローラーで検索も可能にしたいため、
集約ログプロジェクトのログバケットへ組織およびその配下のフォルダ・プロジェクトのログを含めて転送する
(保存のみを目的とするならば、GCS へ直接転送することでも可能。長期保管には別途ログバケットから GCS への転送も実施する)

### 1. ログ集約用のプロジェクト・バケットの作成
集約ログ転送先のプロジェクト・ログバケットを作成する
(API有効化やユーザIAMなど基本的なコードはここでは省略している。長期保管の GCS 転送もここでは省略)

```tf:project.tf
# プロジェクト作成
resource "google_project" "main" {
  name            = var.project_id # 作成するプロジェクト ID を指定する
  project_id      = var.project_id # 作成するプロジェクト ID を指定する (全世界で一意になる必要がある)
  billing_account = var.billing_account # 請求先アカウント ID を指定する
  folder_id       = google_folder.folder.name # プロジェクトを管理するフォルダを指定する
}
```

```tf:logging.tf
# log 短期閲覧用バケット
resource "google_logging_project_bucket_config" "logging_log_bucket" {
  project        = google_project.main.name
  location       = var.location # 保存先のロケーションを指定する (日本ならば asia-northeast1 など)
  retention_days = var.logging_retention_days # ログバケットに保管する期間
  bucket_id      = var.org_logging_bucket_id  # 集約ログバケット名
}
```

### ２. 組織レベルでのログシンク設定
組織レベルでログシンク設定を実施する。設定時に`include_children`を`true`にすることで、組織は以下のプロジェクトのログもすべて sink される

```tf
# Organization Aggregate Logging
## https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/logging_organization_sink
resource "google_logging_organization_sink" "all_log" {
  name        = "organization-ag-all-log-sink"
  description = "Organization Under ALL Log Sink"
  org_id      = var.gcp_common.org_id # 組織 ID を指定する

  include_children = true # 組織は以下の全てのログを sink 対象にする

  destination = "logging.googleapis.com/${google_logging_project_bucket_config.logging_log_bucket.id}"
}
```

設定が完了すると Cloud Console では `ロギング` > `ログルーター` で下記のように確認できる
![スクリーンショット 2023-02-20 1.30.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/7256b357-8cfd-1a15-364b-5c0cca086285.png)


### 3. ログ転送権限設定
Cloud Logging への転送のため、[ログバケット書き込み者（roles/logging.configWriter）](https://cloud.google.com/iam/docs/understanding-roles?hl=ja#logging.configWriter)を組織ログを書き込むサービスアカウントへ権限付与する
(Cloud Storage へ直接書き込む際は、[Storage オブジェクト作成者（roles/storage.objectCreator）](https://cloud.google.com/iam/docs/understanding-roles?hl=ja)の権限を付与する)

```tf
resource "google_project_iam_member" "logging_bucketwriter" {
  project = google_project.main.id
  role    = "roles/logging.bucketWriter"
  member  = google_logging_organization_sink.all_log.writer_identity
}
```

### 4. VPC Service Controls 設定
[VPC Service Controls の Cloud Logging のドキュメントでの制限](https://cloud.google.com/vpc-service-controls/docs/supported-products?hl=ja#table_logging)を確認して設定する

具体的な実施方法は 2つある

1. VPC SC のサービス境界に上り（内向き/Ingress）ルールを追加する
1. アクセスレベルでサービスアカウントを許可する

#### 4.1. VPC SC のサービス境界に上り（内向き/Ingress）ルールを追加する
アクセスレベルを作成して、 サービス境界設定に Ingress Policy を追加設定することで許可が可能

```tf
resource "google_access_context_manager_access_policy" "access-policy" {
  parent = "organizations/${var.gcp_common.org_id}" # 組織IDを含めたIDを指定する
  title  = "my policy"

  depends_on = [
    google_organization_iam_binding.organization_org_admin,
  ]
}

resource "google_access_context_manager_access_level" "org_log_writer" {
  parent = "accessPolicies/${google_access_context_manager_access_policy.access-policy.name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.access-policy.name}/accessLevels/org_log_writer"
  title  = "org_log_writer"
  basic {
    conditions {
      members = [google_logging_organization_sink.all_log.writer_identity, ]
    }
  }
}

resource "google_access_context_manager_service_perimeters" "service-perimeter" {
...省略...
    status {
      restricted_services = [
        "logging.googleapis.com",
...省略...
      ]
      access_levels = [] # 集約ログとしては ingress_policies 設定があればここには追加設定不要
      ingress_policies { # 集約ログ用の上り(内向き)ルール
        ingress_from {
          identities = [
            google_logging_organization_sink.all_log.writer_identity,
          ]
          sources {
            access_level = google_access_context_manager_access_level.org_log_writer.id
          }
        }
        ingress_to {
          resources = [
            "projects/[集約ログプロジェクト番号]",
          ]
          operations {
            service_name = "logging.googleapis.com"
            method_selectors {
              method = "*"
            }
          }
        }
      }
...省略...
```

`セキュリティ` > `Access Context Manager` で設定した`google_access_context_manager_access_level`内容が確認できる

![スクリーンショット 2023-02-20 1.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/b0ae163a-d7c6-6c9c-8036-fbd95349badd.png)


`セキュリティ` > `VPC Service Controls` で設定した`google_access_context_manager_service_perimeters`に追加した上り(内向き)(Ingress) ルールを確認できる

![スクリーンショット 2023-02-20 1.35.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/50bbd8de-dc40-52bc-fd93-919fa6c93954.png)



#### 4.2. アクセスレベルでサービスアカウントを許可する (4.1. 実施時は省略)

環境によっては、単純に Access Level のみで許可してしまうことでも可能。(詳細に設定する場合は、4.1.でアクセス方向・アクセスプロジェクトも制御する)

```tf:vpc_service_controls.tf
...省略...
resource "google_access_context_manager_access_level" "org_log_writer" {
  parent = "accessPolicies/${google_access_context_manager_access_policy.access-policy.name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.access-policy.name}/accessLevels/org_log_writer"
  title  = "org_log_writer"
  basic {
    conditions {
      members = [google_logging_organization_sink.all_log.writer_identity, ]
    }
  }
}

resource "google_access_context_manager_service_perimeters" "service-perimeter" {
  parent = "accessPolicies/${google_access_context_manager_access_policy.access-policy.name}"
...省略...
      access_levels = [
        google_access_context_manager_access_level.org_log_writer.id, # アクセスレベルへ直接追加
      ]
...省略...
```

### 5. 集約ログ確認
集約したログを見るには、集約ログのバケットがあるプロジェクトのログエクスプローラで、
`範囲を絞り込む`をクリックして`ストレージによるスコープ`をクリックして作成したバケットをクリックすると見れるようになる

![スクリーンショット 2023-02-20 1.52.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/0c4f4f3d-a37c-aedd-e30b-3a8797309cc8.png)

閲覧すると`ログのフィールド`を見ると`PROJECT ID` が複数みれることがわかる

![スクリーンショット 2023-02-20 2.16.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/c41a3aae-a3a1-9397-82f2-e254635f185b.png)

以上で設定完了

## まとめ
組織全体のログを一元集約で管理・保管が可能となった

## 参照先

https://cloud.google.com/logging/docs/central-log-storage?hl=ja

https://cloud.google.com/iam/docs/understanding-roles?hl=ja#logging-roles

https://cloud.google.com/vpc-service-controls/docs/supported-products?hl=ja#table_logging