チュートリアル: イメージの脆弱性の取得

このチュートリアルでは、Container Analysis を使用して、Container Registry に格納されているイメージをスキャンして脆弱性がないか確認し、イメージに含まれる重大度の高い脆弱性を一覧表示する方法について説明します。

目標

このチュートリアルでは、次の手順について説明します。

  1. 既知の脆弱性が含まれる Docker イメージを作成する
  2. イメージをプロジェクトの Container Registry に push する
  3. Container Analysis をポーリングし、イメージの初期スキャンと分析を完了する
  4. Container Analysis によって識別された脆弱性を表示する
  5. イメージに含まれる重大度の高い脆弱性を一覧表示する

費用

このチュートリアルでは、Google Cloud の課金対象となるコンポーネントを使用します。詳細は料金をご覧ください。

注: Container Scanning API を有効にすると、すぐに課金が開始されます。 この API を有効にすると、Container Analysis では新たに push した各イメージが自動的にスキャンされますが、既存のイメージは自動スキャンされません。既存のイメージをスキャンするには、もう一度 push する必要があります。

新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

Container Analysis を使用するには、Container Analysis と Container Registry を有効にして設定する必要があります。

  1. Google アカウントにログインします。

    Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。

  2. Cloud Console のプロジェクト セレクタページで、Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタのページに移動

  3. Google Cloud プロジェクトに対して課金が有効になっていることを確認します。 プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  4. Container Registry and Container Scanning API を有効にします。

    API を有効にする

  5. Cloud SDK をインストールし、初期化します
  6. まだ行っていない場合は、次のいずれかを実行して、必要な IAM 権限を取得します。すでにプロジェクト オーナーの役割が付与されている場合は、この手順をスキップします。
    • オカレンスを表示するには、次の権限が必要です。
      containeranalysis.notes.listOccurrences
    • または、必要な権限が自動的に付与されるように、次の事前定義された IAM の役割を付与することもできます。
      Container Analysis Occurrences Viewer
  7. Docker をインストールします。Ubuntu や Debian などの Linux ベースのオペレーティング システムを使用している場合は、ユーザー名を docker グループに追加して、sudo を使わずに Docker を実行できるようにします。
    sudo usermod -a -G docker ${USER}

    docker グループにユーザー名を追加した後に、システムの再起動が必要となる場合があります。

  8. Docker を開きます。Docker が稼働中であることを確認するには、現在の時刻と日付を返す次の Docker コマンドを実行します。
  9. docker run busybox date

Docker イメージの作成

このチュートリアル用に、次の Docker イメージを作成して、Container Registry に push するイメージを用意します。Container Analysis によって識別される既知の脆弱性が含まれる Python ランタイムを使用します。この Docker イメージには、小さな Python ウェブアプリが含まれます。このアプリは Flask のウェブ フレームワークを使用して、「Hello, World!」というメッセージを表示するウェブページを提供します。

Docker イメージを作成するには:

  1. 3 つの Docker イメージ ファイルを格納するディレクトリを作成します。

  2. このディレクトリに、Dockerfilerequirements.txtapp.py の 3 つのファイルを作成します。各ファイルの内容に含める必要があるものについては、以下の例をご覧ください。

Dockerfile

# The file Dockerfile defines the image's environment
    # Import Python runtime and set up working directory
    # This specified runtime has known vulnerabilities so that vulnerability
    # scanning can be tested.
    FROM python:3.5-slim
    WORKDIR /app
    ADD . /app

    # Install any necessary dependencies
    RUN pip install -r requirements.txt

    # Open port 80 for serving the webpage
    EXPOSE 80

    # Run app.py when the container launches
    CMD ["python", "app.py"]
    

requirements.txt

# The file requirements.txt defines the image's dependencies
    Flask
    

app.py

# The Docker image contains the following code in app.py
    from flask import Flask
    import os
    import socket

    app = Flask(__name__)

    @app.route("/")
    def hello():
        html = "<h3>Hello, World!</h3>"
        return html

    if __name__ == "__main__":
      app.run(host='0.0.0.0', port=80)
    

Docker イメージをビルドするには、イメージのファイルが含まれているディレクトリから、次の Docker コマンドを実行します。

docker build -t vulnerabilities-tutorial-image .
    

これで、ローカルマシンに Docker イメージが作成されました。

イメージを Container Registry に追加する

gcloud コマンドライン ツールを認証ヘルパーとして使用するように docker を構成する

イメージを push または pull するには、gcloud コマンドライン ツールを使用して Container Registry へのリクエストを認証するように Docker を構成する必要があります。これを行うには、次のコマンドを実行します(実行する必要があるのは一度だけです)。

gcloud auth configure-docker
    

イメージにレジストリ名をタグ付けする

Docker イメージを Container Registry に push する前に、そのイメージにレジストリ名をタグ付けする必要があります。Docker イメージにレジストリ名をタグ付けすると、イメージを特定の場所に push するように docker push コマンドが構成されます。このクイックスタートでは、ホストの場所は gcr.io です。

Docker イメージにタグを付けるには、次のコマンドを実行します。

docker tag vulnerabilities-tutorial-image gcr.io/[PROJECT-ID]/vulnerabilities-tutorial-image:tag1
    

ここで

  • [PROJECT-ID] は、Google Cloud Console プロジェクト ID です。対象の ID をコマンドに追加します。
  • gcr.io はホスト名です。
  • vulnerabilities-tutorial-image は Docker イメージの名前です。
  • tag1 は Docker イメージに追加するタグです。タグを指定しない場合は、Docker でデフォルトのタグ latest が適用されます。

イメージを Container Registry に push する準備ができました。

イメージを Container Registry に push する

認証ヘルパーとして gcloud を使用するように docker を構成し、ローカル イメージにレジストリ名をタグ付けしたら、そのイメージを Container Registry に push できます。

Docker イメージを push するには、次のコマンドを実行します。

docker push gcr.io/[PROJECT-ID]/vulnerabilities-tutorial-image:tag1
    

[PROJECT-ID] は、Google Cloud Console プロジェクト ID です。プロジェクト ID にコロン(:)が含まれている場合は、ドメインをスコープとするプロジェクトをご覧ください。

新しいホストの場所にイメージを push すると、プロジェクトに固有の基になるストレージ バケットが作成されます。Container Registry でホストされているイメージは Cloud Console から、またはウェブブラウザでイメージのレジストリ名(http://gcr.io/[PROJECT-ID]/vulnerabilities-tutorial-image)にアクセスして確認できます。

イメージのダイジェストを確認する

次のステップでは、イメージの SHA256 ダイジェストが必要になります。これは、レジストリに push したときに生成されたイメージのハッシュです。

タグを使用すると、さまざまな時点で異なるバージョンをマークできますが、ダイジェストは常にイメージ バージョンに固有です。

curl -H "Authorization: Bearer $(gcloud auth print-access-token)" https://gcr.io/v2/[PROJECT-ID]/vulnerabilities-tutorial-image/tags/list
    

返されるレスポンスは、アップロードしたイメージのさまざまなバージョンに関する情報と関連するタグを含む JSON オブジェクトです。

{
      "child": [],
      "manifest": {
        "sha256:1e70b945e7266268e35b3db3ddc5c13e88fe4e42ee6ffbfa8962ec0b1562b51a": {
          "imageSizeBytes": "2803075",
          "layerId": "",
          "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
          "tag": [],
          "timeCreatedMs": "1583923219860",
          "timeUploadedMs": "1583923231051"
        },
        "sha256:95d270793da3f9eb77ae6c0ebe84beaaa84a66c331c3fb2205f8645646568a98": {
          "imageSizeBytes": "61212796",
          "layerId": "",
          "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
          "tag": [
            "tag1"
          ],
          "timeCreatedMs": "1583923518920",
          "timeUploadedMs": "1583923552668"
        }
      },
      "name": "[PROJECT-ID]/vulnerabilities-tutorial-image",
      "tags": [
        "tag1"
      ]
    }
    

たとえば JQ ツールを使用して解析できます。

curl -H "Authorization: Bearer $(gcloud auth print-access-token)" https://gcr.io/v2/[PROJECT-ID]/vulnerabilities-tutorial-image/tags/list | jq  '.manifest | to_entries[] | select(.value.tag | contains(["tag1"])) | .key'
    

初期スキャンのポーリングと分析結果

Container Analysis は、イメージの初期スキャンと分析を自動的に実行します。また、初期スキャンで収集された情報を含む検出オカレンスを作成します。さらに、Container Analysis は、スキャンの現在のステータスが含まれるように検出オカレンスを更新します。

次のサンプルコードは、初期スキャンの現在のステータスをポーリングします。これによって、脆弱性情報が表示できるようになるタイミングを判断できます。

Java

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Java API のリファレンス ドキュメントをご覧ください。

import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.DiscoveryOccurrence;
    import io.grafeas.v1.DiscoveryOccurrence.AnalysisStatus;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import java.io.IOException;
    import java.lang.InterruptedException;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;

    public class PollDiscoveryOccurrenceFinished {
      // Repeatedly query the Container Analysis API for the latest discovery occurrence until it is
      // either in a terminal state, or the timeout value has been exceeded
      public static Occurrence pollDiscoveryOccurrenceFinished(String resourceUrl, String projectId,
          long timeoutSeconds) throws IOException, TimeoutException, InterruptedException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        // long timeoutSeconds = 30;
        final String projectName = ProjectName.format(projectId);
        long deadline = System.currentTimeMillis() + timeoutSeconds * 1000;

        // Initialize client that will be used to send requests. After completing all of your requests,
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();

        // find the discovery occurrence using a filter string
        Occurrence discoveryOccurrence = null;
        // vulbnerability discovery occurrences are always associated with the
        // PACKAGE_VULNERABILITY note in the "goog-analysis" GCP project
        String filter =  String.format("resourceUrl=\"%s\" AND noteProjectId=\"%s\" AND noteId=\"%s\"",
            resourceUrl, "goog-analysis",  "PACKAGE_VULNERABILITY");
        while (discoveryOccurrence == null) {
          for (Occurrence o : client.listOccurrences(projectName, filter).iterateAll()) {
            if (o.getDiscovery() != null) {
              // there should be only one valid discovery occurrence returned by the given filter
              discoveryOccurrence = o;
            }
          }
          TimeUnit.SECONDS.sleep(1);
          // check for timeout
          if (System.currentTimeMillis() > deadline) {
            throw new TimeoutException("discovery occurrence not found");
          }
        }

        // wait for discovery occurrence to enter a terminal state
        AnalysisStatus status = AnalysisStatus.PENDING;
        while (status != AnalysisStatus.FINISHED_SUCCESS
            && status != AnalysisStatus.FINISHED_FAILED
            && status != AnalysisStatus.FINISHED_UNSUPPORTED) {
          // update the occurrence state
          discoveryOccurrence = client.getOccurrence(discoveryOccurrence.getName());
          status = discoveryOccurrence.getDiscovery().getAnalysisStatus();
          TimeUnit.SECONDS.sleep(1);
          // check for timeout
          if (System.currentTimeMillis() > deadline) {
            throw new TimeoutException("discovery occurrence not in terminal state");
          }
        }
        return discoveryOccurrence;
      }
    }

Go

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Go API のリファレンス ドキュメントをご覧ください。


    import (
    	"context"
    	"fmt"
    	"time"

    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )

    // pollDiscoveryOccurrenceFinished returns the discovery occurrence for a resource once it reaches a finished state.
    func pollDiscoveryOccurrenceFinished(resourceURL, projectID string, timeout time.Duration) (*grafeaspb.Occurrence, error) {
    	// resourceURL := fmt.Sprintf("https://gcr.io/my-project/my-image")
    	// timeout := time.Duration(5) * time.Second
    	ctx, cancel := context.WithTimeout(context.Background(), timeout)
    	defer cancel()

    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return nil, fmt.Errorf("NewClient: %v", err)
    	}
    	defer client.Close()

    	// ticker is used to poll once per second.
    	ticker := time.NewTicker(1 * time.Second)
    	defer ticker.Stop()

    	// Find the discovery occurrence using a filter string.
    	var discoveryOccurrence *grafeaspb.Occurrence
    	for discoveryOccurrence == nil {
    		select {
    		case <-ctx.Done():
    			return nil, fmt.Errorf("timeout while retrieving discovery occurrence")
    		case <-ticker.C:
    			req := &grafeaspb.ListOccurrencesRequest{
    				Parent: fmt.Sprintf("projects/%s", projectID),
    				// Vulnerability discovery occurrences are always associated with the
    				// PACKAGE_VULNERABILITY note in the "goog-analysis" GCP project.
    				Filter: fmt.Sprintf(`resourceUrl=%q AND noteProjectId="goog-analysis" AND noteId="PACKAGE_VULNERABILITY"`, resourceURL),
    			}
    			it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    			// Only one occurrence should ever be returned by ListOccurrences
    			// and the given filter.
    			result, err := it.Next()
    			if err == iterator.Done {
    				break
    			}
    			if err != nil {
    				return nil, fmt.Errorf("it.Next: %v", err)
    			}
    			if result.GetDiscovery() != nil {
    				discoveryOccurrence = result
    			}
    		}
    	}

    	// Wait for the discovery occurrence to enter a terminal state.
    	for {
    		select {
    		case <-ctx.Done():
    			return nil, fmt.Errorf("timeout waiting for terminal state")
    		case <-ticker.C:
    			// Update the occurrence.
    			req := &grafeaspb.GetOccurrenceRequest{Name: discoveryOccurrence.GetName()}
    			updated, err := client.GetGrafeasClient().GetOccurrence(ctx, req)
    			if err != nil {
    				return nil, fmt.Errorf("GetOccurrence: %v", err)
    			}
    			switch updated.GetDiscovery().GetAnalysisStatus() {
    			case grafeaspb.DiscoveryOccurrence_FINISHED_SUCCESS,
    				grafeaspb.DiscoveryOccurrence_FINISHED_FAILED,
    				grafeaspb.DiscoveryOccurrence_FINISHED_UNSUPPORTED:
    				return discoveryOccurrence, nil
    			}
    		}
    	}
    }
    

Node.js

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Node.js API のリファレンス ドキュメントをご覧ください。

/**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // const imageUrl = 'https://gcr.io/my-project/my-image:123', // Image to attach metadata to
    // const retries = 5 // The number of retries to listen for the new Pub/Sub messages

    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();

    const formattedParent = client.getGrafeasClient().projectPath(projectId);

    let filter = `resourceUrl="${imageUrl}" AND noteProjectId="goog-analysis" AND noteId="PACKAGE_VULNERABILITY"`;

    // Repeatedly query the Container Analysis API for the latest discovery occurrence until it is
    // either in a terminal state, or the timeout value has been exceeded
    const pRetry = require('p-retry');
    const discoveryOccurrence = await pRetry(
      async () => {
        const [occurrences] = await client.getGrafeasClient().listOccurrences({
          parent: formattedParent,
          filter: filter,
        });
        if (occurrences.length < 0) {
          throw new Error('No occurrences found for ' + imageUrl);
        }
        return occurrences[0];
      },
      {
        retries: retries,
      }
    );

    // Wait for discovery occurrence to enter a terminal state or the timeout value has been exceeded
    const finishedOccurrence = await pRetry(
      async () => {
        let status = 'PENDING';
        const [updated] = await client.getGrafeasClient().getOccurrence({
          name: discoveryOccurrence.name,
        });
        status = updated.discovery.analysisStatus;
        if (
          status !== 'FINISHED_SUCCESS' &&
          status !== 'FINISHED_FAILED' &&
          status !== 'FINISHED_UNSUPPORTED'
        ) {
          throw new Error('Timeout while retrieving discovery occurrence');
        }
        return updated;
      },
      {
        retries: retries,
      }
    );
    console.log(
      `Found discovery occurrence ${finishedOccurrence.name}.  Status: ${finishedOccurrence.discovery.analysisStatus}`
    );

Ruby

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Ruby API のリファレンス ドキュメントをご覧ください。

# resource_url    = "The URL of the resource associated with the occurrence.
    #                    e.g. https://gcr.io/project/image@sha256:123"
    # timeout_seconds = "The number of seconds to wait for the discovery
    #                    occurrence"
    # project_id      = "Your Google Cloud project ID"

    require "grafeas"

    deadline = Time.now + timeout_seconds

    # Initialize the client
    client = Grafeas.new
    formatted_parent = Grafeas::V1::GrafeasClient.project_path project_id

    # Find the discovery occurrence using a filter string
    discovery_occurrence = nil
    while discovery_occurrence.nil?
      begin
        filter = 'resourceUrl="#{resource_url}" ' \
                 'AND noteProjectId="goog-analysis" ' \
                 'AND noteId="PACKAGE_VULNERABILITY"'
        # Only the discovery occurrence should be returned for the given filter
        discovery_occurrence = client.list_occurrences(formatted_parent, filter: filter).first
      rescue StandardError # If there is an error, keep trying until the deadline
        puts "discovery occurrence not yet found"
      ensure
        # check for timeout
        sleep 1
        if Time.now > deadline
          raise "Timeout while retrieving discovery occurrence."
        end
      end
    end

    # Wait for the discovery occurrence to enter a terminal state
    status = Grafeas::V1::DiscoveryOccurrence::AnalysisStatus::PENDING
    while status != :FINISHED_SUCCESS &&
          status != :FINISHED_FAILED &&
          status != :FINISHED_UNSUPPORTED
      # Update occurrence
      begin
        updated = client.get_occurrence discovery_occurrence.name
        status = updated.discovery.analysis_status
      rescue StandardError # If there is an error, keep trying until the deadline
        puts "discovery occurrence not yet in terminal state"
      ensure
        # check for timeout
        sleep 1
        if Time.now > deadline
          raise "Timeout while retrieving discovery occurrence."
        end
      end
    end
    puts "Found discovery occurrence #{updated.name}."
    puts "Status: #{updated.discovery.analysis_status}"

Python

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Python API のリファレンス ドキュメントをご覧ください。

def poll_discovery_finished(resource_url, timeout_seconds, project_id):
        """Returns the discovery occurrence for a resource once it reaches a
        terminal state."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # timeout_seconds = 20
        # project_id = 'my-gcp-project'

        import time
        from grafeas.grafeas_v1.gapic.enums import DiscoveryOccurrence
        from google.cloud.devtools import containeranalysis_v1

        deadline = time.time() + timeout_seconds

        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = grafeas_client.project_path(project_id)

        discovery_occurrence = None
        while discovery_occurrence is None:
            time.sleep(1)
            filter_str = 'resourceUrl="{}" \
                          AND noteProjectId="goog-analysis" \
                          AND noteId="PACKAGE_VULNERABILITY"'.format(resource_url)
            result = grafeas_client.list_occurrences(project_name, filter_str)
            # only one occurrence should ever be returned by ListOccurrences
            # and the given filter
            for item in result:
                discovery_occurrence = item
            if time.time() > deadline:
                raise RuntimeError('timeout while retrieving discovery occurrence')

        status = DiscoveryOccurrence.AnalysisStatus.PENDING
        while status != DiscoveryOccurrence.AnalysisStatus.FINISHED_UNSUPPORTED \
                and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_FAILED \
                and status != DiscoveryOccurrence.AnalysisStatus.FINISHED_SUCCESS:
            time.sleep(1)
            updated = grafeas_client.get_occurrence(discovery_occurrence.name)
            status = updated.discovery.analysis_status
            if time.time() > deadline:
                raise RuntimeError('timeout while waiting for terminal state')
        return discovery_occurrence

スキャンのステータスが FINISHED_SUCCESS になった時点で、脆弱性のリストを表示する準備が完了しています。

イメージに関連するすべての脆弱性の一覧表示

既知の脆弱性はメモとして保存されます。Container Analysis は、イメージの分析中に検出したメモのインスタンスごとにオカレンスを作成します。Container Analysis は、脆弱性に関する新しい情報を収集すると、オカレンスのリストを自動的に更新します。

GCP Console、gcloud コマンドライン ツール、Container Analysis API を使用して、メモとオカレンスに関する情報を取得できます。また、API ではメモやオカレンスに関する特定の情報を取得するためのいくつかのフィルタ式がサポートされています。

次のコードサンプルは、イメージで検出された脆弱性を取得します。

Java

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Java API のリファレンス ドキュメントをご覧ください。

import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import java.io.IOException;
    import java.util.LinkedList;
    import java.util.List;

    public class VulnerabilityOccurrencesForImage {
      // Retrieve a list of vulnerability occurrences assoviated with a resource
      public static List<Occurrence> findVulnerabilityOccurrencesForImage(String resourceUrl,
          String projectId) throws IOException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        final String projectName = ProjectName.format(projectId);
        String filterStr = String.format("kind=\"VULNERABILITY\" AND resourceUrl=\"%s\"", resourceUrl);

        // Initialize client that will be used to send requests. After completing all of your requests,
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();
        LinkedList<Occurrence> vulnerabilitylist = new LinkedList<Occurrence>();
        for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
          vulnerabilitylist.add(o);
        }
        return vulnerabilitylist;
      }
    }

Go

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Go API のリファレンス ドキュメントをご覧ください。


    import (
    	"context"
    	"fmt"

    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )

    // findVulnerabilityOccurrencesForImage retrieves all vulnerability Occurrences associated with a resource.
    func findVulnerabilityOccurrencesForImage(resourceURL, projectID string) ([]*grafeaspb.Occurrence, error) {
    	// resourceURL := fmt.Sprintf("https://gcr.io/my-project/my-image")
    	ctx := context.Background()
    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return nil, fmt.Errorf("NewClient: %v", err)
    	}
    	defer client.Close()

    	req := &grafeaspb.ListOccurrencesRequest{
    		Parent: fmt.Sprintf("projects/%s", projectID),
    		Filter: fmt.Sprintf("resourceUrl = %q kind = %q", resourceURL, "VULNERABILITY"),
    	}

    	var occurrenceList []*grafeaspb.Occurrence
    	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    	for {
    		occ, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return nil, fmt.Errorf("occurrence iteration error: %v", err)
    		}
    		occurrenceList = append(occurrenceList, occ)
    	}

    	return occurrenceList, nil
    }
    

Node.js

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Node.js API のリファレンス ドキュメントをご覧ください。

/**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // const imageUrl = 'https://gcr.io/my-project/my-image:123' // Image to attach metadata to

    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();

    const formattedParent = client.getGrafeasClient().projectPath(projectId);

    // Retrieve a list of vulnerability occurrences assoviated with a resource
    const [occurrences] = await client.getGrafeasClient().listOccurrences({
      parent: formattedParent,
      filter: `kind = "VULNERABILITY" AND resourceUrl = "${imageUrl}"`,
    });

    if (occurrences.length) {
      console.log(`All Vulnerabilities for ${imageUrl}`);
      occurrences.forEach(occurrence => {
        console.log(`${occurrence.name}:`);
      });
    } else {
      console.log('No occurrences found.');
    }

Ruby

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Ruby API のリファレンス ドキュメントをご覧ください。

# resource_url = "The URL of the resource associated with the occurrence
    #                e.g. https://gcr.io/project/image@sha256:123"
    # project_id   = "The Google Cloud project ID of the vulnerabilities to find"

    require "grafeas"

    # Initialize the client
    client = Grafeas.new

    formatted_parent = Grafeas::V1::GrafeasClient.project_path project_id
    filter = "resourceUrl = \"#{resource_url}\" AND kind = \"VULNERABILITY\""
    client.list_occurrences formatted_parent, filter: filter

Python

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Python API のリファレンス ドキュメントをご覧ください。

def find_vulnerabilities_for_image(resource_url, project_id):
        """"Retrieves all vulnerability occurrences associated with a resource."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # project_id = 'my-gcp-project'

        from google.cloud.devtools import containeranalysis_v1

        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = grafeas_client.project_path(project_id)

        filter_str = 'kind="VULNERABILITY" AND resourceUrl="{}"'\
            .format(resource_url)
        return list(grafeas_client.list_occurrences(project_name, filter_str))

重大度の高い脆弱性の一覧表示

ぞれぞれの脆弱性には重大度レベルが関連付けられています。Container Analysis では、サポート対象の Linux ディストリビューションによって提供される重大度レベルの情報が使用されます。ディストリビューションに固有の重大度レベルを使用できない場合は、CVSS スコアに基づくレベルが割り当てられます。

脆弱性の修正プランに優先順位を付けるために、脆弱性のリストを重大度の高い脆弱性のみに絞り込むことができます。

次のコードサンプルは、イメージで「高」または「重大」の重大度が割り当てられた脆弱性のリストを取得します。

Java

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Java API のリファレンス ドキュメントをご覧ください。

import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import io.grafeas.v1.Severity;
    import java.io.IOException;
    import java.util.LinkedList;
    import java.util.List;

    public class HighVulnerabilitiesForImage {
      // Retrieve a list of vulnerability occurrences with a severity level of 'HIGH' or greater
      public static List<Occurrence> findHighSeverityVulnerabilitiesForImage(String resourceUrl,
          String projectId) throws IOException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        final String projectName = ProjectName.format(projectId);
        String filterStr = String.format("kind=\"VULNERABILITY\" AND resourceUrl=\"%s\"", resourceUrl);

        // Initialize client that will be used to send requests. After completing all of your requests,
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();
        LinkedList<Occurrence> vulnerabilitylist = new LinkedList<Occurrence>();
        for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
          Severity severity = o.getVulnerability().getSeverity();
          if (severity == Severity.HIGH || severity == Severity.CRITICAL) {
            vulnerabilitylist.add(o);
          }
        }
        return vulnerabilitylist;
      }
    }

Go

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Go API のリファレンス ドキュメントをご覧ください。


    import (
    	"context"
    	"fmt"

    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )

    // findHighSeverityVulnerabilitiesForImage retrieves a list of only high vulnerability occurrences associated with a resource.
    func findHighSeverityVulnerabilitiesForImage(resourceURL, projectID string) ([]*grafeaspb.Occurrence, error) {
    	// resourceURL := fmt.Sprintf("https://gcr.io/my-project/my-image")
    	ctx := context.Background()
    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return nil, fmt.Errorf("NewClient: %v", err)
    	}
    	defer client.Close()

    	req := &grafeaspb.ListOccurrencesRequest{
    		Parent: fmt.Sprintf("projects/%s", projectID),
    		Filter: fmt.Sprintf("resourceUrl = %q kind = %q", resourceURL, "VULNERABILITY"),
    	}

    	var occurrenceList []*grafeaspb.Occurrence
    	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    	for {
    		occ, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return nil, fmt.Errorf("occurrence iteration error: %v", err)
    		}

    		severityLevel := occ.GetVulnerability().GetEffectiveSeverity()
    		if severityLevel == grafeaspb.Severity_HIGH || severityLevel == grafeaspb.Severity_CRITICAL {
    			occurrenceList = append(occurrenceList, occ)
    		}
    	}

    	return occurrenceList, nil
    }
    

Node.js

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Node.js API のリファレンス ドキュメントをご覧ください。

/**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // const imageUrl = 'https://gcr.io/my-project/my-image:123' // Image to attach metadata to

    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();

    const formattedParent = client.getGrafeasClient().projectPath(projectId);

    // Retrieve a list of vulnerability occurrences with a severity level of 'HIGH' or greater
    const [occurrences] = await client.getGrafeasClient().listOccurrences({
      parent: formattedParent,
      filter: `kind = "VULNERABILITY" AND resourceUrl = "${imageUrl}"`,
    });

    if (occurrences.length) {
      console.log(`High Severity Vulnerabilities for ${imageUrl}`);
      occurrences.forEach(occurrence => {
        if (
          occurrence.vulnerability.severity === 'HIGH' ||
          occurrence.vulnerability.severity === 'CRITICAL'
        ) {
          console.log(`${occurrence.name}:`);
        }
      });
    } else {
      console.log('No occurrences found.');
    }

Ruby

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Ruby API のリファレンス ドキュメントをご覧ください。

# resource_url = "The URL of the resource associated with the occurrence,
    #                 e.g. https://gcr.io/project/image@sha256:123"
    # project_id   = "The Google Cloud project ID of the vulnerabilities to find"

    require "grafeas"

    # Initialize the client
    client = Grafeas.new

    formatted_parent = Grafeas::V1::GrafeasClient.project_path project_id
    filter = "resourceUrl = \"#{resource_url}\" AND kind = \"VULNERABILITY\""
    vulnerability_list = client
                         .list_occurrences(formatted_parent, filter: filter)
    # Filter the list to include only "high" and "critical" vulnerabilities
    vulnerability_list.select do |item|
      item.vulnerability.severity == :HIGH || item.vulnerability.severity == :CRITICAL
    end

Python

Container Registry 用のクライアント ライブラリをインストールして使用する方法については、Container Registry のクライアント ライブラリをご覧ください。詳細については、Container Registry Python API のリファレンス ドキュメントをご覧ください。

def find_high_severity_vulnerabilities_for_image(resource_url, project_id):
        """Retrieves a list of only high vulnerability occurrences associated
        with a resource."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # project_id = 'my-gcp-project'

        from grafeas.grafeas_v1.gapic.enums import Severity
        from google.cloud.devtools import containeranalysis_v1

        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = grafeas_client.project_path(project_id)

        filter_str = 'kind="VULNERABILITY" AND resourceUrl="{}"'\
            .format(resource_url)
        vulnerabilities = grafeas_client.list_occurrences(project_name, filter_str)
        filtered_list = []
        for v in vulnerabilities:
            if v.severity == Severity.HIGH or v.severity == Severity.CRITICAL:
                filtered_list.append(v)
        return filtered_list

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

イメージの削除

追加した Docker イメージのみを削除する場合は、次のコマンドを実行して Container Registry から Docker イメージを削除します。

gcloud container images delete gcr.io/[PROJECT-ID]/vulnerabilities-tutorial-image:tag1 --force-delete-tags
    

[PROJECT-ID] は、Google Cloud Console プロジェクト ID です。プロジェクト ID にコロン(:)が含まれている場合は、ドメインをスコープとするプロジェクトをご覧ください。

プロジェクトの削除

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには、次のようにします。

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] ページに移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

次のステップ