NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    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 の有効化ページから有効化できます。

    Cloud Asset Inventoryで色々見てみる

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

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

    画面上で見る

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

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

    ただし、公式ドキュメントを見ると、多くの操作は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の場合、テーブルのスキーマは以下のようになっています。

    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)もあるので、慣れない方はこちらがやりやすい場合もあると思います。

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

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

    フィードと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を使い分けると良いと思います。

    執筆者上野史瑛

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