Google Cloud インシデント調査のメモ。
Google Cloudの構成要素
Google Cloudは以下の要素で構成される。
- Organization
- Folder
- Project
- Resource
Organization
Google Cloudを構成する最上位のオブジェクト。通常はドメイン (例: example.com) を指す。Google Workspaceとリンクする場合、Google CloudとGoogle Workspaceは共通のドメインを使用することとなる。
Folder
部署やチームのグループ化に使われる。Folderの配下にさらに別のFolderを作成することも可能。
Folderに適用されたポリシーはFolder内のProjectやResourceにも適用される。
Project
Resourceをグループ化したもの。
Resource
Google Cloudのリソース(サービス)を指す。Google Cloud Compute, Storage Bucketなど。
Google Cloud Identity and Access Management (IAM)
Google CloudのIAMとして、Googleは以下の2種類を提供する。
- Cloud Identity
- Google Workspace
厳密には上記以外のIAMサービスを利用することも可能だが、本記事では触れない。
Google CloudのIAMの構成要素
Google CloudのIAMは以下の要素で構成される。
- Principal (User)
- Role (Permissions)
- Policy (Principal + Role = Binding)
Principal
ユーザー、グループ、ドメインなど、パーミッションの適用先となるオブジェクトのこと。
GoogleはかつてPrincipalのことをMemberと呼称していた。Googleのインフラ内でMemberという単語を見かけた場合は、その名残である。基本的にPrincipalとMemberは同義。
Role
Principalに適用するパーミッションの集合体。以下の3種類がある。
- Basic Roles: Google Cloudが開発されたときから存在しているロール。以下の4種類がある。
- Owner
- Editor
- Viewer
- Browser: OrganizationやProjectの階層構造を参照するだけのロール。リソースそのものにアクセスすることはできない。
- Predefined Roles: Google Cloudによってあらかじめ定義されたロール。Basic Rolesよりもきめ細かく設定されている。
- Custom Roles: ユーザーが独自に作成することができるロール。
Policy
PrincipalとRoleを組み合わせたものをPolicyと呼ぶ。最大の特徴はPolicyはリソースに適用されるという点である。AWSなど他のクラウドサービスではポリシーはユーザー (Principal) に適用されることが殆どだが、Google Cloudではポリシーはリソースに適用される。
そのため、Google Cloudにおいては、ユーザーのポリシーを調べて、そのユーザーがアクセス可能なリソースを洗い出す、というようなことはできない。代わりにリソースに適用されているポリシーを調べて、そのリソースにアクセス可能なユーザーを洗い出す、というアプローチは可能。
付け加えると、リソースに対して全く別のOrganizationのユーザーからのアクセスを許可する、というようなポリシーも適用可能である。
仮にOrganization Aのユーザーが、Organization Bのリソースに対して高度な権限を有していたとしても、Organization Aからはその事実を確認することはできない。ポリシーはリソースに対して適用されるため、Organization Bにてリソースに適用されているポリシーを確認する必要がある。
以下はポリシーの例。先述したようにmembersはprincipalsのこと。
{
"bindings": [
{
"members": [
"user:hoge@example.com",
"group:sysadmin@example.com",
"domain:test.com"
],
"role": "roles/editor"
}
],
}
ポリシーはリソース単位だけでなく、Organization単位、Folder単位、Project単位でも適用できる。
Policy vs IAM
Policyは何ができるか (できないか)を規定する。
IAMは誰がアクセスできるか (できないか)を規定する。
IAM Service Account
通常、Google Cloudにおいて新しいリソースが作成されると、Service Account も作成される。このService Accountは主にリソースが他のリソースへアクセスする場合に使われる。
例えば、Compute EngineがStorage Bucketへの読み書きを行いたい場合、Storage Bucketへのアクセス権を持つService Accountが必要となる。これを実現するためには、Compute EngineのService Accountからのアクセスを許可するポリシーをStorage Bucketに適用する必要がある。
また、静的なクレデンシャルを使用したい場合もService Accountを作成する必要がある。AWSなどではユーザーに対してAPIキーを生成できるが、Google CloudではService Accountを作成しないとそのような真似はできない。
ProjectにてService Accountが作成された場合、デフォルトでスコープは(特定のリソースではなく)Project全体に設定される。
Owner Role vs Editor Role
Owner
- EditorにできることはOwnerにも可能。
- ProjectのIAM Roleを管理する。
- Projectへの請求を設定および管理する。
Editor
- ViewerにできることはEditorにも可能。
- Project内のリソースを変更可能。
- Service AccountのAPIキーを生成可能。
- 別のアカウントやリソースを装って (actAs) 活動できる。
- Ownerを装うこともできる。
上記の通り、OwnerとEditorの権限にはほとんど差が無い。Editorの時点で、かなり強力な権限を有していることになる。
Editor Roleを悪用した権限昇格
- Editor Roleを有するアカウントを侵害した後、Ownerを装ってService AccountのAPIキーを生成する。
- Service AccountにOwner Roleを付与する。
- 2.のService Accountを用いて水平展開を行う。
Google Cloudのログ事情
Log Sink
Google Cloud内で発生したログまたはGoogle Cloudに送られたログは一旦すべてLogging APIに送信される。その後、ログはLog Sinkへと送られる。このLog Sinkがログを保存するべきか破棄するべきかを判断する。Log SinkはProject単位もしくはOrganization単位で存在する。
以下の3種類のSinkが存在する。
- _Required Sink: _Required Bucket (後述) へとログを送る。_Required Sinkは変更できない。
- _Default Sink: _Default Bucket (後述) へとログを送る。 _Default Sinkは変更可能。
- User Defined Sink: ユーザーによって定義されたSink。同じくユーザーによって定義されたBucketへとログを送る。User Defined Sinkを利用すると非Google Cloudプラットフォームへログを送ることも可能。
_Required Bucket vs _Default Bucket
Google Cloudには_Requiredと_Defaultという2種類のログバケットが存在する (ほかにもユーザーによって定義されるUser Definedバケットがあるが本項では割愛)。
_Required Bucket
Google Cloudによって強制的に有効化されるログバケットで、無効化することはできない。故に無課金。400日間分のデータが保持される。
以下のログを含む。
- Admin Activity Logs (Admin Write): リソースの設定やメタデータを変更するようなAPIの実行やユーザーアクティビティを記録する。例えば、仮想マシンの作成やIAMのパーミッションの変更など。名前にAdminとつくものの、Admin以外のユーザーのアクティビティも記録される。
- System Event Logs: (ユーザー由来ではなく)システム由来のリソースへの設定変更を記録する。
- Login Audit Logs: ユーザーの認証関連のイベントを記録する。例えば、コンソールへのサインインやAPIへのアクセス、gcloud CLIを介した認証など。
- Access Transparency Logs: Googleの従業員による顧客データへのアクセスを記録する。以下の情報が記録される。
- 顧客データに対してどのようなアクションが取られたか
- 顧客データにアクセスしたGoogle従業員の情報 (所在地や職位など)
_Default Bucket
後述するPolicy Denied Logsのみデフォルトで有効化されている。Projectあたり50GiBまでは無料。また、30日間分のログは無料で保管される。
以下のログを含む。
- Policy Denied Logs: (セキュリティーポリシーに違反したために)ブロックされたアクセス行為を記録する。デフォルトで有効化されており、無効化することはできない。ただし、除外フィルターを適用してログをスリム化することはできる。
- Data Access Logs: 設定やメタデータ、リソースへのアクセスまたは変更を伴うようなAPIの実行を記録する。ただし、もともと外部ユーザーに向けて(認証なしで)公開されているようなリソースへのアクセスは記録されない (非Googleユーザーのプライバシーを保護するための措置。BigQueryによるアクセスは記録される)。以下はData Access Logsとして記録されるイベントの種類。
- Admin Read (デフォルトで無効化されている)
- Data Read / Write (デフォルトで無効化されている)
gcloud
Google Cloudとやり取りするためのコマンドラインツール。
- Google Cloudのwebインターフェースよりもログの収集・検索のための機能が充実している。
- 利用するにはGoogle Cloudのアカウントが必要 (Service Accountも使用可)。
- インシデント調査目的でgcloudを使用する場合は、Private Logs Viewer権限を持つアカウントを使用するのが望ましい (Logs Viewer権限も存在するが、こちらは監査ログにアクセスできない)。
Log Explorer vs Log Analytics
Log ExplorerとLog AnalyticsはどちらもGoogle Cloudのログを検索するための機能である。
Log Explorerは以下のような独自の構文を使ってログを検索する。
resource.type="gcs_bucket" resource.labels.bucket_name="flight-maps" resource.labels.location="us-east1"
対して、Log AnalyticsはSQL風の構文を使ってログを検索する。
SELECT timestamp, severity, resource.type, log_name, text_payload, proto_payload, json_payload FROM `suit-ai.global.All_Logs_Bucket._AllLogs` WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR) LIMIT 50
Google Cloud Compute Engineのスナップショットをエクスポート
Google Cloud Compute EngineはGoogle Cloudが提供する仮想マシン。本項ではインシデント調査のために仮想マシンのスナップショットをエクスポートする方法をざっくり紹介する。
- 調査対象のディスクのスナップショットを作成する。スナップショットの作成はCLIとWebコンソールどちらでも可能。
- 1. のスナップショットをディスクイメージに変換する。
- 2. で作成したスナップショットのディスクイメージ (
.vmdk,.vhdx, etc) をエクスポートする。Google Cloud内にエクスポートする場合はStorage Bucketがエクスポート先になる。 - Storage Bucketへのエクスポートが完了するとディスクイメージをダウンロードできるようになる。
スナップショットを作成する際、未割り当て (unallocated) の領域はスナップショットされないので、その点は留意。
Ops Agent
Ops AgentはCompute Engine (仮想マシン) のテレメトリーを収集するためのエージェントである。Fluent Bitをもとに設計されている。WindowsとLinuxに対応しており、syslogや.evtxを始めとするホストのログを収集してGoogle CloudのLogging APIへと送る。
デフォルトでは収集されたログは (ログの収集元の) 仮想マシンが所属しているProjectと同じProject内に保管される。
projects/[project_name]/logs/[host_log_name]
e.g.) projects/suit-ai/logs/syslog
インシデント調査の面では、ホストをオフラインにしなくともログを調査できるというメリットがある。また、上述したスナップショットに比べてより広範囲の時系列を調べることができる。(スナップショットの場合、スナップショットの作成時に発生していた事象しか分からない。プロセスやネットワーク通信など揮発性の高いデータはスナップショットの作成時には既にホストから消えている可能性が大)
Google Cloud Storage
Google Cloudには多数のStorageが存在する。以下は代表的なStorageの種類。本項では主にCloud Storageについて論ずる。
- Cloud Storage: 画像や動画、バックアップデータやデータレイクなど、非構造化データの格納に適している。後述するBlock StorageやFile Storageと異なり、Bucketを作成できる。
- Block Storage: 主に仮想マシンのディスクの格納先として使われる。
- File Storage: NFS (Network File System)。主に共有リソースの格納先として使われる (複数のホストやユーザーからのアクセスが可能なため)。
Cloud Storageのクラス
Cloud Storageは以下の4種類にクラス分けされている。
- Standard Storage
- 最小保存期間: 無し
- 頻繁にアクセスが発生するデータの格納に適している
- Nearline Storage
- 最小保存期間: 30日
- 月0~1回程度のアクセスが発生するデータの格納に適している
- Coldline Storage
- 最小保存期間: 90日
- 四半期に1回程度のアクセスが発生するデータの格納に適している
- Archive Storage
- 最小保存期間: 365日
- 年に0~1回程度のアクセスが発生するデータの格納に適している
Cloud Storage Bucket
Cloud Storageを利用すると、Project内にデータの格納先となるBucketを作成できる。Bucket内にはフォルダーやサブフォルダー、ファイルを作成できる。
Bucket名は外部から閲覧することができるため、Bucket名にセンシティブな情報を含めるべきではない。
Cloud Storage Bucketのパーミッション
Cloud Storage BucketにはデフォルトでUniformというアクセス制限が適用される。これはBucketに適用されたパーミッションが、そのままBucket内のフォルダーやファイルにも適用されるというものである。例えば、Bucketが外部に対して非公開だった場合、Bucket内のフォルダーやファイルも非公開となる。
Uniformアクセス制限を有効化していても、Bucket内のフォルダーやファイルに個別にパーミッションを適用できる。方法については割愛。
Cloud Storage Bucketへの攻撃
以下はCloud Storage Bucketへの攻撃の例。
- 辞書攻撃で外部 (インターネット) に公開されているBucketを列挙する。
- 外部に公開されているBucketを見つけたら、Bucket内のオブジェクトがアクセス可能か確認する。GCPBucketBruteはこれを自動で行ってくれる。
- アクセス可能なオブジェクトをダウンロードする。
Cloud Storage Bucketで権限昇格
allUsersもしくはallAuthenticatedUsers プリンシパルにlegacyBucketOwner ロールが付与されていた場合、Storage Admin ロールへ権限昇格できる。
以下はlegacyBucketOwner ロールが有しているパーミッションの例である。
- storage.buckets.get
- storage.buckets.getIamPolicy
- storage.buckets.setIamPolicy
- storage.buckets.update
- storage.objects.create
- storage.objects.delete
- storage.objects.list
legacyBucketOwner ロールはstorage.buckets.setIamPolicyというパーミッションを有しており、Storage Bucketに適用されているIAMポリシーを編集することができる。
もし、allUsersあるいはallAuthenticatedUsers プリンシパルにlegacyBucketOwner ロールが付与されていた場合、Project内のほかのBucketをクエリーできるのみならず、Bucketのパーミッションを都合の良いように編集することもできる。例として、ユーザーがBucketに対してStroage Adminとなるようにポリシーを変更して、Bucketを作成、編集、削除できるようにする。。。など。
以下はStorage Admin ロールが有しているパーミッションの例である。
- storage.buckets.create
- storage.buckets.delete
- storage.buckets.get
- storage.buckets.getIamPolicy
- storage.buckets.setIamPolicy
- storage.buckets.list
- storage.buckets.update
Cloud Storage Bucketのログ事情
Google CloudではStorage Bucketの読み取りイベントに関するログはデフォルトで無効化されている (有効化すると大量のログが発生することが予想されるため)。
Bucket内のオブジェクトに対する読み取りイベント (storage.buckets.get, storage.objects.list, etc) を記録したい場合は、Audit LogにてData Readを有効化する。ただし、先述したように大量のログが発生することが予想されるため、重要なBucketに対してのみ有効化することが推奨される。
Data Readを有効化しても、外部ユーザーからのオブジェクトへのアクセスは記録されない。記録されるのはあくまで認証済みのユーザーからのアクセスのみである。
外部ユーザーからのオブジェクトへのアクセスを記録したい場合は、gsutilかAPIを介してBucket毎にUsage LogsとStorage Logsを有効化する必要がある。Usage LogsとStorage LogsはLogging APIに送られないため、ログをダウンロードするにはBucketから手動でダウンロードするか、Cloud Functionを利用しなければならない。
Usage Logs
allUsers (外部ユーザー) またallAuthenticatedUsersプリンシパルからのアクセスを記録する。ログは1時間毎に生成され、ログ用のBucketに書き込まれるまでに15分ほどの遅延が発生する場合がある。
以下はUsage Logsに記録されるフィールドと値の例。
| フィールド名 | 値の例 |
| time_micros | 1631018601779253 |
| c_ip | 104.244.76.13 |
| c_ip_type | 1 |
| c_ip_region | |
| cs_method | GET |
| cs_uri | /confidential_plans/Suit_CPU_Design.zip |
| sc_status | 200 |
| cs_bytes | 0 |
| sc_bytes | 1000000000 |
| time_taken_micros | 1994099000 |
| cs_host | storage.googleapis.com |
| cs_referer | |
| cs_user_agent | Mozilla/5.0 (Windows NT 1.0;rv:78.0) Gecko/20100101 Firefox/78.0,gzip(gfe) |
| s_request_id | ADPycdu-yCkI7loaTPI_nuiyU90gyJx2G_zYolx-AAQiybNI3h7OPDcYm1-uQ_56x-tJQsXDPh6CqgudKpowgokBEMypYqGX_w |
| cs_operation | GET_Object |
| cs_bucket | confidential_plans |
| cs_object | Suit_CPU_Design.zip |
Storage Logs
過去24時間のストレージの使用量の詳細を記録する。このログは1日に1回の頻度で書き込まれる。
Bucketに対する請求内容からデータ漏洩の有無を確認する
Storage Bucketにてアクセス関連のログが有効化されていなかった場合、代替手段として請求内容からデータ漏洩の有無を確認することができる。
請求内容を見ることで、Bucketからどれだけのデータが、何時頃ダウンロードされたかを把握できる。ただし、ダウンロードされたファイル名や、ダウンロードを実行したIPアドレスなどの情報は含まれない。もう一つの注意点として、請求内容は請求が確定しないと閲覧できない (請求の確定には通常1か月ほどかかる)。
Google Cloud Virtual Network
Google Cloudの仮想ネットワークのインシデント調査において重要なのは以下の3つである。
- Virtual Private Clouds (VPC) Flow Logs
- VPC Firewall
- Packet Mirroring
VPC Flow Logs
Flow Logsの説明の前に、Google CloudのVirtual Private Clouds (VPC) について簡単に解説する。
VPCはComputeインスタンス (仮想マシン) と他のネットワーク間の通信を可能にする仕組みのこと。
VPCでは、サブネットはひとつのリージョンにしか適用できない (リージョナル)。それ以外のVPCリソース (Firewall, NAT, routing, etc) はグローバルなリソースのため、複数のリージョンに対して適用できる。また、VPCはIPv4のユニキャスト通信のみ対応している。IPv6やブロードキャスト、マルチキャスト通信には対応していない。(一応、外部に公開しているロードバランサーでIPv6を使用することはできる。 ロードバランサーに到達した通信はIPv4に変換される。)
さて、VPCのFlow Logsだが、全ての通信をその都度記録するわけではなく、一定のインターバルで通信をサンプリングする。よって、通信内容を100%把握できるわけではないが、マルウェアの定常通信やDDOS攻撃など継続的に通信が発生するようなイベントを調査する際には有用。
サンプリングされるのはTCPとUDPの通信のみで、それ以外のプロトコル (例: ICMP) は記録されない。
VPC Firewall
VPCのFirewallは以下の要素をもとに通信をフィルターする。
- IPアドレス (CIDRで指定可能)
- プロトコル
- ポート番号
- 通信の方向 (ingress or egress)
- ルールの優先度
新規のVPCを作成すると、デフォルトのFirewallルールも作成されるが、外部ネットワーク (インターネット) からのSSH, RDP, ICMP (Ping) 通信はデフォルトで許可されている。また、内部ネットワークの通信もデフォルトでは特に制限されていないため、一旦内部ネットワークに侵入してしまえば、水平展開は容易。
Firewallのログはデフォルトで無効化されているので、有効化する必要がある。ログを有効化する際に、オプションで以下の追加のメタデータを記録できる。
- 仮想マシンのインスタンスの情報 (通信相手も仮想マシンだった場合、相手のインスタンス情報も)
- VPCの情報 (通信相手もVPCに所属していた場合、相手のVPC情報も)
- 通信相手の地理的所在地 (国名など)
Packet Mirroring
Packet Mirroringを使用するとフルパケットキャプチャが可能。パケットのミラーリングは仮想マシン単位、GKEクラスター単位、VPC単位で設定できる。
キャプチャされた通信はまずロードバランサーへと送られ、パケットの送り先はロードバランサーによって判断される。
VPCで通信が評価・記録される順序
仮想マシンから外向きの通信が発生した場合、以下の順序で通信が評価されてログが生成される。
- 仮想マシンから外向きの通信が発生する。
- 通信がサンプリングされて、VPC Flow Logsが生成される。
- Firewallが通信を許可あるいは拒否する。
- Firewallのログが生成される。
よって、VPC Flow Logsで不審な通信が記録されたが、Firewallのログを確認したところ遮断されていた、ということが有りうる。