Getting vulnerabilities and metadata for images

Container Analysis provides vulnerability information and other types of metadata for the container images in Container Registry. The metadata is stored as notes. An occurrence is created for each instance of a note associated with an image. See Pricing for pricing information.

This page describes how to view, filter, and get notifications for notes and occurrences.

Note: When you enable the Container Scanning API, billing begins immediately. Once you enable the API, Container Analysis automatically scans each newly pushed image, but does not automatically scan existing images. To scan an existing image, you must push it again.

Before you begin

  1. Enable the Container Scanning API. This enables vulnerability scanning as well as the Container Analysis API. You can enable the API for an existing project, or create a new project and then enable the API. You can manually disable vulnerability scanning at a later time.

    Enable the Container Scanning API

  2. If you have not already done so, enable the required IAM permissions. If you are the project owner, skip this step.

    • To view occurrences, you must grant the following predefined IAM role, which will automatically provide the necessary permissions:

      • Container Analysis Occurrences Viewer
    • To receive notifications for occurrences, you need to configure the appropriate Pub/Sub permissions. Refer to Notifications for details.

  3. Read Container Analysis Overview.

Viewing vulnerabilities and other occurrences

You can view occurrences for your images in Container Registry using GCP Console, gcloud command-line tool, or the Container Analysis API. If an image has vulnerabilities, you can then obtain the details.

To view the occurrences for an image:

Console

  1. Open the Container Registry page in the GCP Console.

    Open the Container Registry page

  2. Click on an image name.

    Vulnerability totals for the images are displayed in the Vulnerabilities column.

    Screenshot of an image with vulnerabilities

  3. To view the list of vulnerabilities for an image, click the link in the Vulnerabilities column.

    The vulnerability list shows the severity, availability of a fix, and the name of the package that contains the vulnerability.

  4. To learn more about a specific vulnerability from the vulnerability source, click the link in the Documentation column.

GCLOUD COMMAND

To view occurrences for an image:

gcloud beta container images list-tags --show-occurrences \
    [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]

where:

  • [PROJECT_ID] is the ID of the project, which contains the images.
  • [IMAGE_ID] is the ID of the image for which you want to view vulnerabilities.
  • [HOSTNAME] is one of the options described in Registry name.

You can not specify an image tag with this command.

To view information about a tag or a layer:

 gcloud beta container images describe [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]:[TAG]

  or

 gcloud beta container images describe [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH]

where:

  • [PROJECT_ID] is the ID of the project, which contains the images.
  • [IMAGE_ID] is the ID of the image for which you want to view vulnerabilities.
  • [TAG] is the image tag about which you want to get information.
  • [HASH] is the image digest.
  • [HOSTNAME] is one of the options described in Registry name.

To view vulnerabilities for an image tag or a layer:

 gcloud beta container images describe [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]:[TAG]  \
 --show-package-vulnerability

  or

 gcloud beta container images describe [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH] \
 --show-package-vulnerability

To filter the vulnerability occurrences:

 gcloud beta container images list-tags --show-occurrences \
     [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID] --occurrence-filter=[FILTER_EXPRESSION]

where:

  • [PROJECT_ID] is the ID of the project, which contains the images.
  • [IMAGE_ID] is the ID of the image for which you want to view vulnerability occurrences.
  • [FILTER_EXPRESSION] is a sample filter expression in the format explained in the Filtering vulnerability occurrences.
  • [HOSTNAME] is one of the options described in Registry name.

API

Using cURL

To get a list of occurrences in your project:

 curl -X GET -H "Content-Type: application/json" -H \
    "Authorization: Bearer $(gcloud auth print-access-token)" \
    https://containeranalysis.googleapis.com/v1/projects/[PROJECT_ID]/occurrences

To get a summary of vulnerabilities in your project:

 curl -X GET -H "Content-Type: application/json" -H \
    "Authorization: Bearer $(gcloud auth print-access-token)" \
    https://containeranalysis.googleapis.com/v1/projects/[PROJECT_ID]/occurrences:vulnerabilitySummary

To get an occurrence:

 curl -X GET -H "Content-Type: application/json" -H \
    "Authorization: Bearer $(gcloud auth print-access-token)" \
    https://containeranalysis.googleapis.com/v1/projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID]

Java

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Java API reference documentation .

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.lang.InterruptedException;

public class OccurrencesForImage {
  // Retrieves all the Occurrences associated with a specified image
  // Here, all Occurrences are simply printed and counted
  public static int getOccurrencesForImage(String resourceUrl, String projectId)
      throws IOException, InterruptedException {
    // String resourceUrl = "https://gcr.io/project/image@sha256:123";
    // String projectId = "my-project-id";
    final String projectName = ProjectName.format(projectId);
    final String filterStr = String.format("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();
    int i = 0;
    for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
      // Write custom code to process each Occurrence here
      System.out.println(o.getName());
      i = i + 1;
    }
    return i;
  }
}

Go

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Go API reference documentation .


import (
	"context"
	"fmt"
	"io"

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

// getOccurrencesForImage retrieves all the Occurrences associated with a specified image.
// Here, all Occurrences are simply printed and counted.
func getOccurrencesForImage(w io.Writer, resourceURL, projectID string) (int, error) {
	// resourceURL := fmt.Sprintf("https://gcr.io/my-project/my-image")
	ctx := context.Background()
	client, err := containeranalysis.NewClient(ctx)
	if err != nil {
		return -1, fmt.Errorf("NewClient: %v", err)
	}
	defer client.Close()

	req := &grafeaspb.ListOccurrencesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
		Filter: fmt.Sprintf("resourceUrl=%q", resourceURL),
	}
	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
	count := 0
	for {
		occ, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return -1, fmt.Errorf("occurrence iteration error: %v", err)
		}
		// Write custom code to process each Occurrence here.
		fmt.Fprintln(w, occ)
		count = count + 1
	}
	return count, nil
}

Node.js

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Node.js API reference documentation .

/**
 * 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);

// Retrieves all the Occurrences associated with a specified image
const [occurrences] = await client.getGrafeasClient().listOccurrences({
  parent: formattedParent,
  filter: `resourceUrl = "${imageUrl}"`,
});

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

Ruby

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Ruby API reference documentation .

# 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 occurrences to
#                  retrieve"

require "grafeas"

# Initialize the client
client = Grafeas.new

formatted_parent = Grafeas::V1::GrafeasClient.project_path project_id
filter = "resourceUrl = \"#{resource_url}\""
count = 0
client.list_occurrences(formatted_parent, filter: filter).each do |occurrence|
  # Process occurrence here
  puts occurrence
  count += 1
end
puts "Found #{count} occurrences"

Python

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Python API reference documentation .

def get_occurrences_for_image(resource_url, project_id):
    """Retrieves all the occurrences associated with a specified image.
    Here, all occurrences are simply printed and counted."""
    # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
    # project_id = 'my-gcp-project'

    from google.cloud.devtools import containeranalysis_v1

    filter_str = 'resourceUrl="{}"'.format(resource_url)
    client = containeranalysis_v1.ContainerAnalysisClient()
    grafeas_client = client.get_grafeas_client()
    project_name = grafeas_client.project_path(project_id)

    response = grafeas_client.list_occurrences(project_name,
                                               filter_=filter_str)
    count = 0
    for o in response:
        # do something with the retrieved occurrence
        # in this sample, we will simply count each one
        count += 1
    return count

Filtering occurrences

You can use filter strings in the gcloud commands and the Container Analysis API to filter occurrences before viewing them. The following sections describe the supported search filters.

Viewing occurrences of a specific type

The kind field identifies the type of occurrence. Use this field to limit the list of occurrences to a particular type, such as a vulnerability or deployment.

The filter expression to retrieve occurrences of a specific kind for a specific image is:

kind="[NOTE_KIND]" AND resourceUrl="[RESOURCE_URL]"

where:

  • [NOTE_KIND] is the kind of note.
    • For example, use the kind DISCOVERY to list discovery occurrences. These are created for images when they are initially pushed to the Container Registry.
    • To list vulnerability occurrences, use the kind VULNERABILITY.
  • [RESOURCE_URL] is the complete URL of the image https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH]

The filter expression to retrieve occurrences of a specific kind across many images is:

kind="[NOTE_KIND]" AND has_prefix(resourceUrl, "[RESOURCE_URL_PREFIX]")

where:

  • [RESOURCE_URL_PREFIX] is the URL prefix for some images
    • To list for all version of an image: https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@
    • To list for all images in a project: https://[HOSTNAME]/[PROJECT_ID]/

Viewing discovery occurrences

When an image is initially pushed to the Container Registry, it creates a discovery occurrence, which contains information about the initial scan of the container image.

To retrieve the discovery occurrence for an image, use the following filter expression:

kind="DISCOVERY" AND resourceUrl="[RESOURCE_URL]"

The following snippet shows how to use the above filter expression to view discovery occurrences for an image:

GCLOUD COMMAND

To view discovery occurrences for an image:

gcloud beta container images list-tags --show-occurrences \
  --occurrence-filter='kind="DISCOVERY"' --format=json [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]

API

To retrieve the discovery occurrence, the above filter expression should be URL encoded and embedded in a GET request as follows:

GET https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences?filter=kind%3D%22DISCOVERY%22%20AND%20resourceUrl%3D%22ENCODED_RESOURCE_URL%22

See projects.occurrences.get API endpoint for more details.

Java

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Java API reference documentation .

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.lang.InterruptedException;

public class GetDiscoveryInfo {
  // Retrieves and prints the Discovery Occurrence created for a specified image
  // The Discovery Occurrence contains information about the initial scan on the image
  public static void getDiscoveryInfo(String resourceUrl, String projectId)
      throws IOException, InterruptedException {
    // String resourceUrl = "https://gcr.io/project/image@sha256:123";
    // String projectId = "my-project-id";
    String filterStr = "kind=\"DISCOVERY\" AND resourceUrl=\"" + resourceUrl + "\"";
    final String projectName = ProjectName.format(projectId);

    // 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();
    for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
      System.out.println(o);
    }
  }
}

Go

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Go API reference documentation .


import (
	"context"
	"fmt"
	"io"

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

// getDiscoveryInfo retrieves and prints the Discovery Occurrence created for a specified image.
// The Discovery Occurrence contains information about the initial scan on the image.
func getDiscoveryInfo(w io.Writer, resourceURL, projectID string) error {
	// resourceURL := fmt.Sprintf("https://gcr.io/my-project/my-image")
	ctx := context.Background()
	client, err := containeranalysis.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("NewClient: %v", err)
	}
	defer client.Close()

	req := &grafeaspb.ListOccurrencesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
		Filter: fmt.Sprintf(`kind="DISCOVERY" AND resourceUrl=%q`, resourceURL),
	}
	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
	for {
		occ, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("occurrence iteration error: %v", err)
		}
		fmt.Fprintln(w, occ)
	}
	return nil
}

Node.js

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Node.js API reference documentation .

/**
 * 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);
// Retrieves and prints the Discovery Occurrence created for a specified image
// The Discovery Occurrence contains information about the initial scan on the image
const [occurrences] = await client.getGrafeasClient().listOccurrences({
  parent: formattedParent,
  filter: `kind = "DISCOVERY" AND resourceUrl = "${imageUrl}"`,
});

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

Ruby

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Ruby API reference documentation .

# 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 occurrences to retrieve"

require "grafeas"

# Initialize the client
client = Grafeas.new

formatted_parent = Grafeas::V1::GrafeasClient.project_path project_id
filter = "kind = \"DISCOVERY\" AND resourceUrl = \"#{resource_url}\""
client.list_occurrences(formatted_parent, filter: filter).each do |occurrence|
  # Process discovery occurrence here
  puts occurrence
end

Python

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Python API reference documentation .

def get_discovery_info(resource_url, project_id):
    """Retrieves and prints the discovery occurrence created for a specified
    image. The discovery occurrence contains information about the initial
    scan on the image."""
    # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
    # project_id = 'my-gcp-project'

    from google.cloud.devtools import containeranalysis_v1

    filter_str = 'kind="DISCOVERY" AND resourceUrl="{}"'.format(resource_url)
    client = containeranalysis_v1.ContainerAnalysisClient()
    grafeas_client = client.get_grafeas_client()
    project_name = grafeas_client.project_path(project_id)
    response = grafeas_client.list_occurrences(project_name,
                                               filter_=filter_str)
    for occ in response:
        print(occ)

Viewing vulnerability occurrences

To view vulnerability occurrences for a specific image, create a query with a filter expression:

kind="VULNERABILITY" AND resourceUrl="[RESOURCE_URL]"

The following snippet shows how to retrieve a list of vulnerability occurrences for an image.

GCLOUD COMMAND

To view vulnerability occurrences for an image:

gcloud beta container images list-tags --show-occurrences \
  --occurrence-filter='kind="VULNERABILITY"' --format=json [HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]

API

The desired resource URL should be URL encoded, and embedded in a GET request as follows:

GET https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences?filter=kind%3D%VULNERABILITY%22%20AND%20resourceUrl%3D%22ENCODED_RESOURCE_URL%22

See projects.occurrences.get API endpoint for more details.

Java

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Java API reference documentation .

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

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Go API reference documentation .


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

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Node.js API reference documentation .

/**
 * 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

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Ruby API reference documentation .

# 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

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Python API reference documentation .

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))

Viewing images associated with a specific note

You can retrieve a list of resources that are associated with a specific note ID. For example, you can list images with a specific CVE vulnerability.

To list all images within a project that are associated with a particular note, use the following filter expression:

noteProjectId="[PROVIDER_PROJECT_ID]" AND noteId="[NOTE_ID]"

To check a specific image for a specific note, use the following filter expression:

resourceUrl="[RESOURCE_URL]" AND noteProjectId="[PROVIDER_PROJECT_ID]" \
    AND noteId="[NOTE_ID]"

where:

  • [PROVIDER_PROJECT_ID] is the ID of the provider project. For example, goog-vulnz provides the default vulnerability analysis.
  • [NOTE_ID] is the ID of the note. Security related notes are often formatted as CVE-2019-12345.
  • [RESOURCE_URL] is the complete URL of the image https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH]

For example, to check for all images that have an occurrence of CVE-2017-16231 as analyzed by Google, use the following filter expression:

noteProjectId="goog-vulnz" AND noteId="CVE-2017-16231"

Viewing deployments

You can list deployments that are currently running or deployments that were running during a specified period.

To view deployments that are currently running, use the following filter expression:

kind="DEPLOYABLE" AND resourceUrl="[RESOURCE_URL]" AND \
    isNull(undeployTime)

To view deployments that were running during a specific time period, use the following filter expression:

kind="DEPLOYABLE" AND resourceUrl="[RESOURCE_URL]" AND \
    deployTime<"[DEPLOY_TIME]" AND \
    undeployTime>"[UNDEPLOY_TIME]"

where:

  • [RESOURCE_URL] is the complete URL of the image https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH]
  • [DEPLOY_TIME] is the start time of the deployment period. Use a timestamp in RFC 3339 UTC "Zulu" format, accurate to nanoseconds. Example: "2014-10-02T15:01:23.045123456Z"
  • [UNDEPLOY_TIME] is the end of the deployment period. Use a timestamp in RFC 3339 UTC "Zulu" format, accurate to nanoseconds.

Cloud Pub/Sub notifications

This section describes how to set up notifications for updates to notes and occurrences.

Container Registry provides notifications via Cloud Pub/Sub whenever it scans for vulnerabilities and other metadata. When a note or occurrence is created or updated, a message is published to the corresponding topic for each API version. Use the topic respective to API your current API version.

After you activate the Container Analysis API, the following Cloud Pub/Sub topics are created for you in your project:

  • container-analysis-notes-v1 + container-analysis-occurrences-v1

If the topics were accidentally deleted or are missing, you can add them yourself.

Console

  1. Go to the Cloud Pub/Sub topics page in the GCP Console.

    Open the Cloud Pub/Sub topics page

  2. Click Create Topic.

  3. Enter a topic for notes with the URI:

    projects/[PROJECT-ID]/topics/container-analysis-notes-v1
    

    where [PROJECT-ID] is your GCP project ID.

  4. Click Create.

  5. Create another topic for occurrences with the URI:

     projects/[PROJECT-ID]/topics/container-analysis-occurrences-v1
    

gcloud

Run the following commands in your shell or terminal window:

gcloud pubsub topics create projects/[PROJECT-ID]/topics/container-analysis-notes-v1
gcloud pubsub topics create projects/[PROJECT-ID]/topics/container-analysis-occurrences-v1

To learn more about the gcloud pubsub topics command, see the topics documentation.

Anytime a note or an occurrence is created or updated, a message is published to the respective topic.

Cloud Pub/Sub payloads are in JSON and their schema is as follows:

Notes:

{
    "name": "projects/[PROJECT_ID]/notes/[NOTE_ID]",
    "kind": "[NOTE_KIND]",
    "notificationTime": "[NOTIFICATION_TIME]",
}

Occurrences:

{
    "name": "projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID]",
    "kind": "[NOTE_KIND]",
    "notificationTime": "[NOTIFICATION_TIME]",
}

where:

  • [NOTE_KIND] is one of the values in NoteKind
  • [NOTIFICATION_TIME] is a timestamp in RFC 3339 UTC "Zulu" format, accurate to nanoseconds.

To listen to these events, create a Pub/Sub subscription associated with the topic:

GCLOUD COMMAND

To receive Cloud Pub/Sub events, you must first create a subscription associated with the container-analysis-occurrences-v1 topic:

gcloud pubsub subscriptions create \
    --topic container-analysis-occurrences-v1 occurrences

Going forward, you can pull messages concerning your occurrences using your new subscription:

gcloud pubsub subscriptions pull \
    --auto-ack occurrences

Java

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Java API reference documentation .

import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.PushConfig;
import com.google.pubsub.v1.Subscription;
import io.grpc.StatusRuntimeException;
import java.io.IOException;
import java.lang.InterruptedException;
import java.util.concurrent.TimeUnit;

public class Subscriptions {
  // Handle incoming Occurrences using a Cloud Pub/Sub subscription
  public static int pubSub(String subId, long timeoutSeconds, String projectId)
      throws InterruptedException {
    // String subId = "my-occurrence-subscription";
    // long timeoutSeconds = 20;
    // String projectId = "my-project-id";
    Subscriber subscriber = null;
    MessageReceiverExample receiver = new MessageReceiverExample();

    try {
      // Subscribe to the requested Pub/Sub channel
      ProjectSubscriptionName subName = ProjectSubscriptionName.of(projectId, subId);
      subscriber = Subscriber.newBuilder(subName, receiver).build();
      subscriber.startAsync().awaitRunning();
      // Sleep to listen for messages
      TimeUnit.SECONDS.sleep(timeoutSeconds);
    } finally {
      // Stop listening to the channel
      if (subscriber != null) {
        subscriber.stopAsync();
      }
    }
    // Print and return the number of Pub/Sub messages received
    System.out.println(receiver.messageCount);
    return receiver.messageCount;
  }

  // Custom class to handle incoming Pub/Sub messages
  // In this case, the class will simply log and count each message as it comes in
  static class MessageReceiverExample implements MessageReceiver {
    public int messageCount = 0;

    @Override
    public synchronized void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
      // Every time a Pub/Sub message comes in, print it and count it
      System.out.println("Message " + messageCount + ": " + message.getData().toStringUtf8());
      messageCount += 1;
      // Acknowledge the message
      consumer.ack();
    }
  }

  // Creates and returns a Pub/Sub subscription object listening to the Occurrence topic
  public static Subscription createOccurrenceSubscription(String subId, String projectId)
      throws IOException, StatusRuntimeException, InterruptedException {
    // This topic id will automatically receive messages when Occurrences are added or modified
    String topicId = "container-analysis-occurrences-v1";
    ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
    ProjectSubscriptionName subName = ProjectSubscriptionName.of(projectId, subId);

    SubscriptionAdminClient client = SubscriptionAdminClient.create();
    PushConfig config = PushConfig.getDefaultInstance();
    Subscription sub = client.createSubscription(subName, topicName, config, 0);
    return sub;
  }
}

Go

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Go API reference documentation .


import (
	"context"
	"fmt"
	"io"
	"sync"
	"time"

	pubsub "cloud.google.com/go/pubsub"
)

// occurrencePubsub handles incoming Occurrences using a Cloud Pub/Sub subscription.
func occurrencePubsub(w io.Writer, subscriptionID string, timeout time.Duration, projectID string) (int, error) {
	// subscriptionID := fmt.Sprintf("my-occurrences-subscription")
	// timeout := time.Duration(20) * time.Second
	ctx := context.Background()

	var mu sync.Mutex
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return -1, fmt.Errorf("pubsub.NewClient: %v", err)
	}
	// Subscribe to the requested Pub/Sub channel.
	sub := client.Subscription(subscriptionID)
	count := 0

	// Listen to messages for 'timeout' seconds.
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()
	err = sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		mu.Lock()
		count = count + 1
		fmt.Fprintf(w, "Message %d: %q\n", count, string(msg.Data))
		msg.Ack()
		mu.Unlock()
	})
	if err != nil {
		return -1, fmt.Errorf("sub.Receive: %v", err)
	}
	// Print and return the number of Pub/Sub messages received.
	fmt.Fprintln(w, count)
	return count, nil
}

// createOccurrenceSubscription creates a new Pub/Sub subscription object listening to the Occurrence topic.
func createOccurrenceSubscription(subscriptionID, projectID string) error {
	// subscriptionID := fmt.Sprintf("my-occurrences-subscription")
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %v", err)
	}
	defer client.Close()

	// This topic id will automatically receive messages when Occurrences are added or modified
	topicID := "container-analysis-occurrences-v1"
	topic := client.Topic(topicID)
	config := pubsub.SubscriptionConfig{Topic: topic}
	_, err = client.CreateSubscription(ctx, subscriptionID, config)
	return fmt.Errorf("client.CreateSubscription: %v", err)
}

Node.js

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Node.js API reference documentation .

/**
 * TODO(developer): Uncomment these variables before running the sample
 */
// const projectId = 'your-project-id', // Your GCP Project ID
// const subscriptionId = 'my-sub-id', // A user-specified subscription to the 'container-analysis-occurrences-v1' topic
// const timeoutSeconds = 30 // The number of seconds to listen for the new Pub/Sub Messages

// Import the pubsub library and create a client, topic and subscription
const {PubSub} = require('@google-cloud/pubsub');
const pubsub = new PubSub({projectId});
const subscription = pubsub.subscription(subscriptionId);

// Handle incoming Occurrences using a Cloud Pub/Sub subscription
let count = 0;
const messageHandler = message => {
  count++;
  message.ack();
};

// Listen for new messages until timeout is hit
subscription.on(`message`, messageHandler);

setTimeout(() => {
  subscription.removeListener(`message`, messageHandler);
  console.log(`Polled ${count} occurrences`);
}, timeoutSeconds * 1000);

Ruby

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Ruby API reference documentation .

# subscription_id = "A user-specified identifier for the new subscription"
# timeout_seconds = "The number of seconds to listen for new Pub/Sub
#                    messages"
# project_id      = "Your Google Cloud project ID"

require "google/cloud/pubsub"

pubsub = Google::Cloud::Pubsub.new project: project_id
topic = pubsub.topic "container-analysis-occurrences-v1"
subscription = topic.subscribe subscription_id

count = 0
subscriber = subscription.listen do |received_message|
  count += 1
  # Process incoming occurrence here
  puts "Message #{count}: #{received_message.data}"
  received_message.acknowledge!
end
subscriber.start
# Wait for incomming occurrences
sleep timeout_seconds
subscriber.stop.wait!
subscription.delete
# Print and return the total number of Pub/Sub messages received
puts "Total Messages Received: #{count}"
count

Python

To learn how to install and use the client library for Container Registry, see the Container Registry Client Libraries . For more information, see the Container Registry Python API reference documentation .

def pubsub(subscription_id, timeout_seconds, project_id):
    """Respond to incoming occurrences using a Cloud Pub/Sub subscription."""
    # subscription_id := 'my-occurrences-subscription'
    # timeout_seconds = 20
    # project_id = 'my-gcp-project'

    import time
    from google.cloud.pubsub import SubscriberClient

    client = SubscriberClient()
    subscription_name = client.subscription_path(project_id, subscription_id)
    receiver = MessageReceiver()
    client.subscribe(subscription_name, receiver.pubsub_callback)

    # listen for 'timeout' seconds
    for _ in range(timeout_seconds):
        time.sleep(1)
    # print and return the number of pubsub messages received
    print(receiver.msg_count)
    return receiver.msg_count


class MessageReceiver:
    """Custom class to handle incoming Pub/Sub messages."""
    def __init__(self):
        # initialize counter to 0 on initialization
        self.msg_count = 0

    def pubsub_callback(self, message):
        # every time a pubsub message comes in, print it and count it
        self.msg_count += 1
        print('Message {}: {}'.format(self.msg_count, message.data))
        message.ack()


def create_occurrence_subscription(subscription_id, project_id):
    """Creates a new Pub/Sub subscription object listening to the
    Container Analysis Occurrences topic."""
    # subscription_id := 'my-occurrences-subscription'
    # project_id = 'my-gcp-project'

    from google.api_core.exceptions import AlreadyExists
    from google.cloud.pubsub import SubscriberClient

    topic_id = 'container-analysis-occurrences-v1'
    client = SubscriberClient()
    topic_name = client.topic_path(project_id, topic_id)
    subscription_name = client.subscription_path(project_id, subscription_id)
    success = True
    try:
        client.create_subscription(subscription_name, topic_name)
    except AlreadyExists:
        # if subscription already exists, do nothing
        pass
    else:
        success = False
    return success

Subscriber applications only receive messages that are published to the topic after the subscription is created.

Disabling vulnerability scanning

To disable vulnerability scanning, do the following:

  1. Open the Container Registry Settings page in the GCP Console.

    Open the Settings page

  2. Click Disable Vulnerability Scanning.

What's next

  • For instructions on how to use Container Analysis to store and manage your customers' metadata, see Providing Metadata for Images.

  • You can integrate Binary Authorization with vulnerability scanning to prevent images with known security issues from running in your deployment environment. For instructions on doing this see, Vulnerability Scanning Integration.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...