Cloud Asset Inventory と BigQuery を使用して組織の脆弱性レポートを表示する

このドキュメントでは、VM Manager、Cloud Asset Inventory、BigQuery を使用して、組織内の Compute Engine インスタンスの脆弱性レポートを表示する方法について説明します。

Cloud Asset Inventory から BigQuery にデータをエクスポートすると、高度なクエリを実行して、組織全体の保留中のパッチと脆弱性情報を特定できます。

始める前に

  • VM Manager を設定する
  • Cloud Asset Inventory API を有効にします。
  • エクスポートされたデータを保存する BigQuery データセットを作成します。
  • 脆弱性レポートを表示するために必要な権限があることを確認します。
  • まだ設定していない場合は、認証を設定します。認証では、 Google Cloud サービスと API にアクセスするための ID が確認されます。ローカル開発環境からコードまたはサンプルを実行するには、次のいずれかのオプションを選択して Compute Engine に対する認証を行います。

    このページのサンプルをどのように使うかに応じて、タブを選択してください。

    コンソール

    Google Cloud コンソールを使用して Google Cloud サービスと API にアクセスする場合、認証を設定する必要はありません。

    gcloud

    1. Google Cloud CLI をインストールします。インストール後、次のコマンドを実行して Google Cloud CLI を初期化します。

      gcloud init

      外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  • デフォルトのリージョンとゾーンを設定します。

必要なロール

リソースデータを BigQuery にエクスポートするために必要な権限を取得するには、プロジェクト、フォルダ、または組織に対する次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

これらの事前定義ロールには、リソースデータを BigQuery にエクスポートするために必要な権限が含まれています。必要とされる正確な権限については、「必要な権限」セクションを開いてご確認ください。

必要な権限

リソースデータを BigQuery にエクスポートするには、次の権限が必要です。

  • cloudasset.assets.exportOSInventories
  • cloudasset.assets.exportResource
  • bigquery.datasets.get
  • bigquery.tables.create
  • bigquery.tables.update
  • bigquery.tables.get
  • bigquery.jobs.create

カスタムロールや他の事前定義ロールを使用して、これらの権限を取得することもできます。

VM Manager データを BigQuery にエクスポートする

OS インベントリとリソースデータを BigQuery にエクスポートするには、次の操作を行います。

  1. 組織 ID を確認します。

    gcloud projects get-ancestors PROJECT_ID
    

    PROJECT_ID は、プロジェクトのプロジェクト ID に置き換えます。

  2. VM Manager によって収集された OS インベントリ データを VM インスタンスからエクスポートします。

    gcloud asset export \
        --content-type=os-inventory \
        --organization=ORGANIZATION_ID \
        --per-asset-type \
        --bigquery-table="projects/BQ_PROJECT_ID/datasets/DATASET_ID/tables/os"
    

    次のように置き換えます。

    • ORGANIZATION_ID: 実際の組織 ID
    • BQ_PROJECT_ID: BigQuery データセットが配置されているプロジェクト ID。
    • DATASET_ID: BigQuery データセットの名前。
  3. リソース メタデータを BigQuery テーブルにエクスポートします。

    gcloud asset export \
        --content-type=resource \
        --organization=ORGANIZATION_ID \
        --per-asset-type \
        --bigquery-table="projects/BQ_PROJECT_ID/datasets/DATASET_ID/tables/res"
    

    次のように置き換えます。

    • ORGANIZATION_ID: 組織 ID
    • BQ_PROJECT_ID: BigQuery データセットが配置されているプロジェクト ID
    • DATASET_ID: BigQuery データセットの ID

OS インベントリ スナップショットをエクスポートする方法については、アセット スナップショットをエクスポートするをご覧ください。

組織の脆弱性レポートを生成する

インベントリ データをエクスポートしたら、BigQuery で SQL クエリを実行して脆弱性レポートを生成できます。このレポートには、次の情報が表示されます。

  • 組織全体の保留中のパッチの完全なリスト。
  • Compute Engine インスタンスごとの保留中のパッチの概要。
  • プロジェクトごとの保留中のパッチの概要。

レポートを生成する手順は次のとおりです。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    BigQuery に移動

  2. クエリエディタに次の SQL スクリプトを貼り付けます。

    WITH UPDATES_GRANULAR_DATA AS (
      SELECT
        project,
        instance,
        os,
        available_update,
        vuln.cve AS vuln_cve,
        vuln.severity AS linux_vuln_severity,
        windows_categories
      FROM (
        SELECT
          SPLIT(inv.name, '/')[OFFSET(4)] AS project,
          SPLIT(inv.name, '/')[OFFSET(8)] AS instance,
          inv.os_inventory.os_Info.long_Name AS os,
          inv_item.key AS available_update,
          (
            SELECT
              ARRAY_AGG(c.name) windows_cat_names
            FROM UNNEST(inv_item.value.available_Package.wua_Package.categories) c
          ) AS windows_categories
        FROM
          DATASET_ID.os_compute_googleapis_com_Instance AS inv
        CROSS JOIN UNNEST(inv.os_inventory.items) AS inv_item
        WHERE
          inv.name NOT LIKE '%/locations/%'
          AND inv_item.value.type = 2 --"AVAILABLE_PACKAGE"
    
        UNION ALL
    
        SELECT
          project,
          instance,
          os,
          NULL AS available_update,
          NULL AS windows_categories
        FROM (
          SELECT
            SPLIT(name, '/')[OFFSET(4)] AS project,
            SPLIT(name, '/')[OFFSET(8)] AS instance,
            os_Inventory.os_Info.long_Name AS os,
            (
              SELECT COUNT(*)
              FROM UNNEST(os_Inventory.items)
              WHERE value.type = 2 --"AVAILABLE_PACKAGE"
            ) AS count_available_updates
          FROM DATASET_ID.os_compute_googleapis_com_Instance
          WHERE name NOT LIKE '%/locations/%'
        )
        WHERE count_available_updates = 0
      )
      LEFT JOIN (
        SELECT
          inv_item,
          v.details.severity AS severity,
          v.details.cve AS cve
        FROM DATASET_ID.res_osconfig_googleapis_com_VulnerabilityReport
        CROSS JOIN UNNEST(resource.data.vulnerabilities) AS v
        CROSS JOIN UNNEST(v.availableInventoryItemIds) AS inv_item
        WHERE
          ARRAY_LENGTH(resource.data.vulnerabilities)>0 AND
          ARRAY_LENGTH(v.availableInventoryItemIds)>0
      ) AS vuln
      ON vuln.inv_item = available_update
    ),
    
    REPORT_WITH_WINDOWS_CATEGORIES_VERBOSE AS (
      SELECT
        project,
        instance,
        os,
        COUNTIF(available_update IS NOT NULL) as updates_pending,
        IF(
          COUNTIF(available_update IS NOT NULL)>0 AND ARRAY_LENGTH(ARRAY_CONCAT_AGG(windows_categories)) IS NULL,
            IF(
              ARRAY_LENGTH(ARRAY_AGG(DISTINCT(linux_vuln_severity) IGNORE NULLS)) > 0,
              IF(
                CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY_AGG(DISTINCT(linux_vuln_severity) IGNORE NULLS),""), "CRITICAL"),
                "CRITICAL",
                IF(
                  CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY_AGG(DISTINCT(linux_vuln_severity) IGNORE NULLS),""), "HIGH"),
                  "HIGH",
                  IF(
                    CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY_AGG(DISTINCT(linux_vuln_severity) IGNORE NULLS),""), "MEDIUM"),
                    "MEDIUM",
                    IF(
                      CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY_AGG(DISTINCT(linux_vuln_severity) IGNORE NULLS),""), "LOW"),
                      "LOW",
                      "SEVERITY_UNSPECIFIED"
                    )
                  )
                )
              ),
              "UNKNOWN"
            ),
            NULL
        ) as linux_vuln_severity,
        ARRAY_CONCAT_AGG(windows_categories) as windows_categories_agg
      FROM UPDATES_GRANULAR_DATA
      GROUP BY project, instance, os
      ORDER BY project, instance, os
    ),
    
    REPORT_BY_VM AS (
      SELECT
        project,
        instance,
        os,
        updates_pending,
        linux_vuln_severity,
        IF(
          ARRAY_LENGTH(windows_categories_agg) > 0,
          IF(
            CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY(SELECT DISTINCT(a) as n FROM UNNEST(windows_categories_agg) a ORDER BY n ASC),","), "Security Updates"),
            "SECURITY UPDATES",
            IF(
              CONTAINS_SUBSTR(ARRAY_TO_STRING(ARRAY(SELECT DISTINCT(a) as n FROM UNNEST(windows_categories_agg) a ORDER BY n ASC),","), "Update Rollups"),
              "UPDATE ROLLUPS",
              "OTHER UPDATES"
            )
          ),
          NULL
        ) as windows_category
      FROM REPORT_WITH_WINDOWS_CATEGORIES_VERBOSE
    ),
    
    REPORT_BY_PROJECT AS (
      SELECT
        project,
        COUNT(*) as total_vms,
        COUNTIF(updates_pending=0) as vms_up_to_date,
        COUNTIF(updates_pending>0) as vms_with_updates_pending,
        COUNTIF(linux_vuln_severity = "CRITICAL") as linux_vms_critical,
        COUNTIF(linux_vuln_severity = "HIGH") as linux_vms_high,
        COUNTIF(linux_vuln_severity = "MEDIUM") as linux_vms_medium,
        COUNTIF(linux_vuln_severity = "LOW") as linux_vms_low,
        COUNTIF(linux_vuln_severity = "SEVERITY_UNSPECIFIED") as linux_vms_severity_unspecified,
        COUNTIF(linux_vuln_severity = "UNKNOWN") as linux_vms_unknown,
        COUNTIF(windows_category = "SECURITY UPDATES") as win_vms_security_updates,
        COUNTIF(windows_category = "UPDATE ROLLUPS") as win_vms_update_rollups,
        COUNTIF(windows_category = "OTHER UPDATES") as win_vms_other_updates
      FROM REPORT_BY_VM
      GROUP BY project
    )
    
    -- To view the report, uncomment one of the following SELECT statements:
    
    -- 1. List of every pending update package across all VMs with associated vulnerability severity:
    -- SELECT * FROM UPDATES_GRANULAR_DATA
    
    -- 2. List of VMs and pending updates count:
    -- SELECT * FROM REPORT_BY_VM
    
    -- 3. Summary of projects, showing count of VMs up-to-date and with pending updates:
    SELECT * FROM REPORT_BY_PROJECT
    

    DATASET_ID は、BigQuery データセットの ID に置き換えます。

  3. [実行] をクリックします。

データのクエリの詳細については、クエリの実行をご覧ください。

レポートを生成したら、データポータルを使用してカスタム ダッシュボードを作成できます。詳細については、データポータルでデータを分析するをご覧ください。

次のステップ