Cloud Asset Inventory を使用してGoogle Cloud上のアセットを分析する

こんにちは、最近はGoogle Cloudの記事を書いている上野です。(AWSももちろんやってます) 今回はCloud Asset Inventoryを見ていきます。

Cloud Asset Inventoryとは?

Google Cloud上の、アセットを管理できるサービスです。アセットとは、大きく以下の2種類を指します。

リソース

Compute Engine 仮想マシン(VM)やCloud Storage バケットなどのGoogle Cloud上で作成されたリソースのメタデータ

ポリシー

IAMポリシー、Organizationsポリシーなど、誰が何にアクセスできるかという情報(ポリシーのメタデータ)

Google Cloud上に5 週間分の履歴情報が保管されています。

AWSで言うとAWS Configに近いサービスになります。

Cloud Asset Inventoryの開始方法

開始方法は簡単で、Cloud Asset API の有効化すればOKです。

使用したいプロジェクトを選択し、Cloud Asset API の有効化ページから有効化できます。

f:id:fu3ak1:20210824153615p:plain

Cloud Asset Inventoryで色々見てみる

Cloud Asset Inventory用の権限としては、roles/cloudasset.owner、roles/cloudasset.viewerの2種類あり、フルで使用するにはroles/cloudasset.owner権限を付与する必要があります。

何ができるかは、実際に触ってみたほうがわかりやすいのでいくつかサンプルを実行していきます。

画面上で見る

現状プレビュー状態ですが、アセット インベントリ画面が存在します。

f:id:fu3ak1:20210824154917p:plain

シンプルにリソースの一覧を見る場合はこの画面でも充分そうです。

ただし、公式ドキュメントを見ると、多くの操作はgcloudコマンドかAPIとなっているため、機能をフル活用するという意味ではコマンドもしくはプログラム経由で使用したほうが良いでしょう。

各機能をコマンド例と共に見ていきます。

※プロジェクトID、組織ID、ユーザーメールアドレス等の情報は実際の情報から変更していますので、参考にする場合は環境に合わせて修正してください。

アセットの一覧表示

FWの一覧を取得するコマンドです。

# 実行コマンド(FW一覧)
gcloud beta asset list \
  --project=[プロジェクトID] \
  --asset-types=compute.googleapis.com/Firewall \
  --content-type=resource
# 結果例(デフォルトのFW)
ancestors:
- projects/[プロジェクトID]
- organizations/[組織ID]
assetType: compute.googleapis.com/Firewall
name: //compute.googleapis.com/projects/[プロジェクトID]/global/firewalls/default-allow-ssh
resource:
  data:
    allowed:
    - IPProtocol: tcp
      ports:
      - '22'
    creationTimestamp: '2021-01-01T00:00:00.000-08:00'
    description: Allow SSH from anywhere
    direction: INGRESS
    disabled: false
    id: 'xxxxxxxx'
    logConfig:
      enable: false
    name: default-allow-ssh
    network: https://www.googleapis.com/compute/v1/projects/[プロジェクトID]/global/networks/default
    priority: 65534
    selfLink: https://www.googleapis.com/compute/v1/projects/[プロジェクトID]/global/firewalls/default-allow-ssh
    sourceRanges:
    - 0.0.0.0/0
  discoveryDocumentUri: https://www.googleapis.com/discovery/v1/apis/compute/v1/rest
  discoveryName: Firewall
  location: global
  parent: //cloudresourcemanager.googleapis.com/projects/[プロジェクトNo]
  version: v1
updateTime: '2021-01-01T00:00:00.000-08:00Z'

以下のように組織IDを指定して組織は以下のアセットも表示できます。

gcloud beta asset list \
  --organization=[組織ID] \
  --asset-types=compute.googleapis.com/Firewall \
  --content-type=resource

GCSバケットであれば--asset-typesstorage.googleapis.com/Bucket、GCEインスタンスであればcompute.googleapis.com/Instanceを指定すれば取得できます。

IAMポリシーの検索

ユーザーやリソース単位でどんな権限付いているの?という検索ができます。

特定のユーザーに付与された権限

# 特定ユーザーについている権限一覧
# --scppeはprojects/[PROJECT_ID]でもOK
gcloud asset search-all-iam-policies \
  --scope=organizations/[組織ID] \
  --query=policy:ueno@example.com 
#結果サンプル

## 組織権限(Admin)
assetType: cloudresourcemanager.googleapis.com/Organization
organization: organizations/[組織ID]
policy:
  bindings:
  - members:
    - user:ueno@example.com
    role: roles/accesscontextmanager.policyAdmin
  - members:
    - user:ueno@example.com
    role: roles/owner
  - members:
    - user:ueno@example.com
    role: roles/resourcemanager.organizationAdmin
resource: //cloudresourcemanager.googleapis.com/organizations/[組織ID]
---
## プロジェクト権限(Owner)
assetType: cloudresourcemanager.googleapis.com/Project
organization: organizations/[組織ID]
policy:
  bindings:
  - members:
    - user:ueno@example.com
    role: roles/owner
project: projects/[プロジェクトNo]
resource: //cloudresourcemanager.googleapis.com/projects/[プロジェクトID]

特定リソースに付与された権限

# 特定リソース(audit_log_sink_projectというデータセット)についている権限一覧
gcloud asset search-all-iam-policies \
  --scope projects/[プロジェクトID] \
  --query=resource:datasets/audit_log_sink_project
#結果サンプル
assetType: bigquery.googleapis.com/Dataset
organization: organizations/[組織ID]
policy:
  bindings:
  - members:
    - projectEditor:[プロジェクトID]
    - serviceAccount:pxxxxxxxxxx-xxxxx@gcp-sa-logging.iam.gserviceaccount.com
    role: roles/bigquery.dataEditor
  - members:
    - projectOwner:[プロジェクトID]
    - user:ueno@example.com
    role: roles/bigquery.dataOwner
  - members:
    - projectViewer:[プロジェクトID]
    role: roles/bigquery.dataViewer
project: projects/[プロジェクトNo]
resource: //bigquery.googleapis.com/projects/[プロジェクトID]/datasets/audit_log_sink_project

外部公開されているリソース

# 外部公開されているリソース一覧
gcloud asset search-all-iam-policies \
  --scope projects/[プロジェクトID] \
  --query "policy:(allAuthenticatedUsers OR allUsers)"
#結果サンプル(GCSバケット)
assetType: storage.googleapis.com/Bucket
policy:
  bindings:
  - members:
    - allAuthenticatedUsers
    - allUsers
    role: roles/storage.objectViewer
project: projects/[プロジェクトNo]
resource: //storage.googleapis.com/testbucket

アセット履歴の表示

特定のリソースに対して、いつどのように変更があったかを表示できます。

次の例では、過去1日間でファイアウォールにどのような変更があったか表示しています。

# 特定のFW「default-allow-ssh」について、過去1日分の変更履歴表示
YESTERDAY=$(TZ=GMT date +"%Y-%m-%dT%H:%M:%SZ" -d "yesterday")
NOW=$(TZ=GMT date +"%Y-%m-%dT%H:%M:%SZ")
gcloud asset get-history --project=[プロジェクトID] \
  --asset-names='//compute.googleapis.com/projects/[プロジェクトID]/global/firewalls/default-allow-ssh' \
  --start-time=$YESTERDAY \
  --end-time=$NOW --content-type='resource'

結果は長いため一部抜粋しますが、8/24にsourceRangesが0.0.0.0/0から10.0.0.0/16に変わっていることがわかります。

# 結果サンプル(一部抜粋)
asset:
  assetType: compute.googleapis.com/Firewall
  name: //compute.googleapis.com/projects/[プロジェクトID]/global/firewalls/default-allow-ssh
  resource:
    data:
      allowed:
      - IPProtocol: tcp
        ports:
        - '22'
      creationTimestamp: '2021-06-24T17:58:06.325-07:00'
      description: Allow SSH from anywhere
      direction: INGRESS
      name: default-allow-ssh
      priority: 65534
      sourceRanges:
      - 10.0.0.0/16 ##ここが変わっている
    discoveryName: Firewall
  updateTime: '2021-08-24T10:06:06.495844Z'
window:
  endTime: '2262-04-11T23:47:16.854775807Z'
  startTime: '2021-08-24T10:06:06.495844Z'  #変更日時
---
asset:
  assetType: compute.googleapis.com/Firewall
  name: //compute.googleapis.com/projects/[プロジェクトID]/global/firewalls/default-allow-ssh
  resource:
    data:
      allowed:
      - IPProtocol: tcp
        ports:
        - '22'
      creationTimestamp: '2021-06-24T17:58:06.325-07:00'
      description: Allow SSH from anywhere
      direction: INGRESS
      name: default-allow-ssh
      priority: 65534
      sourceRanges:
      - 0.0.0.0/0 #変更前の情報
    discoveryName: Firewall
  updateTime: '2021-06-25T00:58:06.622282Z'
window:
  endTime: '2021-08-24T10:06:06.495844Z' #変更日時
  startTime: '2021-06-25T00:58:06.622282Z'

BigQueryへエクスポート

BigQueryへCAIの情報をエクスポートできます。

エクスポート後、指定条件で検索を行い検知、といった発見的ガードレールの実装も可能です。

  gcloud asset export \
     --content-type resource \
     --project [プロジェクトID] \
     --bigquery-table projects/[プロジェクトID]/datasets/[データセットID]/tables/[テーブル名] \
     --output-bigquery-force

--content-typeでアセットのコンテンツタイプを指定しています。iam-policyを指定するとIAMポリシーをすべてエクスポートできます。

--output-bigquery-forceは既存テーブルへ上書きを行うオプションです。

コンテンツタイプがresourceの場合、テーブルのスキーマは以下のようになっています。

f:id:fu3ak1:20210825115044p:plain

resource.dataにリソースごとの詳細情報がJSONで格納されており、バケットでは以下のようになっています。

{
    "acl": [],
    "billing": {},
    "cors": [],
    "defaultObjectAcl": [],
    "encryption": {},
    "etag": "CAE=",
    "iamConfiguration": {
        "bucketPolicyOnly": {
            "enabled": true,
            "lockedTime": "2021-08-20T02:58:06.027Z"
        },
        "uniformBucketLevelAccess": {
            "enabled": true,
            "lockedTime": "2021-08-20T02:58:06.027Z"
        }
    },
    "id": "[バケット名]",
    "kind": "storage#bucket",
    "labels": {},
    "lifecycle": {
        "rule": []
    },
    "location": "ASIA-NORTHEAST1",
    "locationType": "region",
    "logging": {},
    "metageneration": 1,
    "name": "[バケット名]",
    "owner": {},
    "projectNumber": [プロジェクトNo],
    "retentionPolicy": {},
    "satisfiesPZS": false,
    "selfLink": "https://www.googleapis.com/storage/v1/b/[バケット名]",
    "storageClass": "STANDARD",
    "timeCreated": "2021-05-22T02:58:06.027Z",
    "updated": "2021-05-22T02:58:06.027Z",
    "versioning": {},
    "website": {},
    "zoneAffinity": []
}

エクスポートはGCSバケットへも可能です。

IAMポリシーの分析

「IAMポリシーの検索」と少し似ているのですが、分析ではサービスアカウントやデータセットなどのリソースに対して、誰が、どの権限を持ってアクセスできるのか、といった観点で確認ができます。

たとえば以下のコマンドでは、データセットaudit_log_sink_projectに対してbigquery.datasets.getまたはbigquery.tables.get権限を持つプリンシパル(IAMユーザーやサービスアカウント)を検索できます。

gcloud asset analyze-iam-policy --project=[プロジェクトID] \
    --full-resource-name="//bigquery.googleapis.com/projects/[プロジェクトID]/datasets/audit_log_sink_project" \
    --permissions="bigquery.datasets.get,bigquery.tables.get"
#結果サンプル、複数の一致するACLが表示される
ACLs:
- accesses:
  - permission: bigquery.datasets.get
  identities:
  - name: user:ueno@example.com
  resources:
  - fullResourceName: //bigquery.googleapis.com/projects/[プロジェクトID] /datasets/audit_log_sink_project
policy:
  attachedResource: //cloudresourcemanager.googleapis.com/projects/[プロジェクトID] 
  binding:
    members:
    - user:ueno@example.com
    role: roles/owner

「IAMポリシーの検索」と同じように、特定ユーザーに付与されている権限を調べることもできます。

gcloud asset analyze-iam-policy --organization=[組織ID] \
    --identity="user:ueno@example.com"
#結果サンプル

## 組織権限(Admin)
---
ACLs:
- accesses:
  - role: roles/resourcemanager.organizationAdmin
  identities:
  - name: user:ueno@example.com
  resources:
  - fullResourceName: //cloudresourcemanager.googleapis.com/organizations/[組織ID]
policy:
  attachedResource: //cloudresourcemanager.googleapis.com/organizations/[組織ID]
  binding:
    members:
    - user:ueno@example.com
    role: roles/resourcemanager.organizationAdmin
---
## プロジェクト権限(Owner)
ACLs:
- accesses:
  - role: roles/owner
  identities:
  - name: user:ueno@example.com
  resources:
  - fullResourceName: //cloudresourcemanager.googleapis.com/projects/[プロジェクトID] 
policy:
  attachedResource: //cloudresourcemanager.googleapis.com/projects/[プロジェクトID] 
  binding:
    members:
    - user:ueno@example.com
    role: roles/owner

ほかにも色々な分析方法が公式ドキュメントで紹介されています。

また、 IAMポリシーの分析コンソール画面(GUI)もあるので、慣れない方はこちらがやりやすい場合もあると思います。

ただし現時点ではプレビュー状態で、組織の指定が必要です。(プロジェクト指定で利用不可)

f:id:fu3ak1:20210825175105p:plain

アセットの変更のモニタリング

フィードとPub/Subを使用して、リソースの変更が発生したら通知するという運用も可能です。

実際の通知まで設定内容を紹介すると長くなってしまうので、本記事ではフィードの作成例を1つだけ紹介しておきます。

以下のコマンドでは、BigQuery テーブル内のコンテンツが変更されたときにtopic_nameという Pub/Sub トピックから通知を作成します。

 gcloud asset feeds create quick_start_feed \
  --project=[プロジェクトID]  \
  --content-type=resource --asset-types="bigquery.googleapis.com/Table" \
  --pubsub-topic="projects/[プロジェクトID] /topics/topic_name"

その他通知方法の詳細内容は公式ドキュメントを参照してください。

まとめ

Cloud Asset Inventoryでできることをgcloudコマンドベースでざっと整理してみました。APIをONにするだけで色々検索できるのはありがたいですね。

セキュリティガードレールなど、特定の設定を検知したい場合はBigQueryに一度入れて条件でひっかけるやり方が良いかなと思います。Security Command Centerでリアルタイム検知できる内容もあるので、そちらでできることも確認して、Cloud Asset InventoryとSecurity Command Centerを使い分けると良いと思います。

f:id:fu3ak1:20210325095452j:plain

執筆者上野史瑛

Japan APN Ambassador 2020
AWSを中心としたクラウドの導入、最適化を専門に行っています。