Getting Image Vulnerabilities

Container Analysis provides vulnerability information for the container images in Container Registry.

This page describes how to view, filter, and get notifications on vulnerabilities for the images in Container Registry.

Before you begin

  1. Enable the Container Analysis API for the project. You can enable the API for an existing project, or create a new project and then enable the API.

    Enable the Container Analysis API

  2. Enable vulnerability scanning under the Container Registry page settings.

    Enable vulnerability scanning

  3. Read Container Analysis Overview.

Viewing vulnerability occurrences for container images

You can view vulnerability occurrences for your images in Container Registry using GCP Console, gcloud command-line tool, or the Container Analysis API.

IAM Permissions

To perform this task, you must have the following IAM permissions:

  • containeranalysis.notes.listOccurrences

Alternately, you can grant the following predefined IAM role, which will automatically provide the necessary permissions:

  • Container Analysis Occurrences Viewer

To view the vulnerability occurrences for images:

Console

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

    Open the Container Registry page

  2. Click on an image name.

    The vulnerabilities for the images are displayed in the Vulnerabilities column.

    Screenshot of an image with vulnerabilities

  3. Click on a vulnerability to see more details.

GCLOUD COMMAND

To view an overview of the vulnerability information:

gcloud alpha 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.

To view information about a tag or a layer:

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

  or

 gcloud alpha 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 filter the vulnerability occurrences:

 gcloud alpha 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 an occurrence:

 curl -X GET -H "Content-Type: application/json" -H \
    "Authorization: Bearer $(gcloud auth print-access-token)" \
    https://containeranalysis.googleapis.com/v1beta1/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 .

/**
 * Retrieves and prints a specified Occurrence from the server
 * @param client The Grafeas client used to perform the API requests.
 * @param occurrenceName the name of the Occurrence to delete
 *                       format: "projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID]"
 * @return the requested Occurrence object
 */
public static Occurrence getOccurrence(GrafeasV1Beta1Client client, String occurrenceName) {
  Occurrence occ = client.getOccurrence(occurrenceName);
  System.out.println(occ);
  return occ;
}

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 .

// getOccurrence retrieves and prints a specified Occurrence from the server.
// occurrenceName should be in the following format: "projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID]"
func getOccurrence(ctx context.Context, client *containeranalysis.GrafeasV1Beta1Client, occurrenceName string) (*grafeaspb.Occurrence, error) {
	req := &grafeaspb.GetOccurrenceRequest{Name: occurrenceName}
	occ, err := client.GetOccurrence(ctx, req)
	fmt.Println(occ)
	return occ, err
}

Filtering vulnerability occurrences

You can use filter strings in the gcloud commands and the Container Analysis API to filter vulnerability occurrences before viewing them. You can query for occurrences based on the values of the following fields:

  • occurrenceId
  • noteId
  • noteProjectId
  • resourceUrl
  • kind
  • createTime
  • updateTime

For example, to list all vulnerability occurrences for a resource URL in your gcr.io host, use the following filter string:

kind="PACKAGE_VULNERABILITY" \
    AND has_prefix(resource_url, "https://gcr.io/path/to/resource")

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.

IAM Permissions

To perform this task, you must have the following IAM permissions:

  • containeranalysis.notes.listOccurrences

Alternately, you can grant one of the following predefined IAM role, which will automatically provide the necessary permissions:

  • Container Analysis Occurrences Viewer

To view discovery occurrences:

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:

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/v1beta1/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 .

/**
 * Retrieves and prints the Discovery Occurrence created for a specified image
 * The Discovery Occurrence contains information about the initial scan on the image
 * @param client The Grafeas client used to perform the API requests.
 * @param imageUrl the Container Registry URL associated with the image
 *                 example: "https://gcr.io/project/image@sha256:foo"
 * @param projectId the GCP project the image belongs to
 */
public static void getDiscoveryInfo(GrafeasV1Beta1Client client, String imageUrl,
    String projectId) {
  String filterStr = "kind=\"DISCOVERY\" AND resourceUrl=\"" + imageUrl + "\"";
  final String projectName = ProjectName.format(projectId);

  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 .

// 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(ctx context.Context, client *containeranalysis.GrafeasV1Beta1Client, imageURL, projectID string) error {
	filterStr := `kind="DISCOVERY" AND resourceUrl="` + imageURL + `"`
	projectName := "projects/" + projectID

	req := &grafeaspb.ListOccurrencesRequest{
		Parent: projectName,
		Filter: filterStr,
	}
	it := client.ListOccurrences(ctx, req)
	for {
		occ, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Println(occ)
	}
	return nil
}

Viewing all occurrences for an image

IAM Permissions

To perform this task, you must have the following IAM permissions:

  • containeranalysis.notes.listOccurrences

Alternately, you can grant one of the following predefined IAM role, which will automatically provide the necessary permissions:

  • Container Analysis Occurrences Viewer

To view all occurrences for an image:

To view all the occurrences found for a specific container image, create a query with a filter expression:

kind="PACKAGE_VULNERABILITY" \
    AND has_prefix(resource_url, "https://[HOSTNAME]/path/to/resource")

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

API

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

GET https://containeranalysis.googleapis.com/v1beta1/projects/PROJECT_ID/occurrences?filter=resourceUrl%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 .

/**
 * Retrieves all the Occurrences associated with a specified image
 * Here, all Occurrences are simply printed and counted
 * @param client The Grafeas client used to perform the API requests.
 * @param imageUrl the Container Registry URL associated with the image
 *                 example: "https://gcr.io/project/image@sha256:foo"
 * @param projectId the GCP project to search for Occurrences in
 * @return number of Occurrences found
 */
public static int getOccurrencesForImage(GrafeasV1Beta1Client client, String imageUrl, 
    String projectId) {
  final String filterStr = "resourceUrl=\"" + imageUrl + "\"";
  final String projectName = ProjectName.format(projectId);
  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 .

// getOccurrencesForImage retrieves all the Occurrences associated with a specified image.
// Here, all Occurrences are simply printed and counted.
func getOccurrencesForImage(ctx context.Context, client *containeranalysis.GrafeasV1Beta1Client, imageURL, projectID string) (int, error) {
	filterStr := `resourceUrl="` + imageURL + `"`
	project := "projects/" + projectID

	req := &grafeaspb.ListOccurrencesRequest{
		Parent: project,
		Filter: filterStr,
	}
	it := client.ListOccurrences(ctx, req)
	count := 0
	for {
		occ, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return -1, err
		}
		// Write custom code to process each Occurrence here.
		fmt.Println(occ)
		count = count + 1
	}
	return count, nil
}

Cloud Pub/Sub notifications

IAM Permissions: You'll need the appropriate IAM permissions to perform this task. For information on the required permissions and roles, see PUB/SUB IAM Permissions.

Container Registry provides notifications via Cloud Pub/Sub whenever it scans for vulnerabilities. After you activate the Container Analysis API, the following Cloud Pub/Sub topics are created for you in your project:

  • resource-notes-occurrences-v1alpha1

Anytime 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:

{
    "occurrenceName": "projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID]"
}

To listen to these events, create a Pub/Sub subscription associated with the topic, and create a MessageReceiver subclass that can handle the notifications as they come in. In the following sample, the MessageReceiver logs and counts the messages as they come in.

API

To receive Cloud Pub/Sub events, you must first create a subscription associated with the resource-notes-occurrences-v1beta1 topic:

gcloud beta pubsub subscriptions create \
    --topic resource-notes-occurrences-v1alpha1 occurrences

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

gcloud beta 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 .

/**
 * Handle incoming Occurrences using a Cloud Pub/Sub subscription
 * @param subId the user-specified identifier for the Pub/Sub subscription
 * @param timeout the amount of time to listen for Pub/Sub messages (in seconds)
 * @param projectId the GCP project the Pub/Sub subscription belongs to
 * @return number of Occurrence Pub/Sub messages received before exiting
 * @throws InterruptedException on errors with the subscription client
 */
public static int pubSub(String subId, int timeout, String projectId) 
    throws InterruptedException {
  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();
    // Listen to messages for 'timeout' seconds
    for (int i = 0; i < timeout; i++) {
      sleep(1000);
    }
  } 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
 * @param subId the identifier you want to associate with the subscription
 * @param projectId the GCP project to create the subscription under
 * @throws IOException thrown on errors with the subscription client
 * @throws StatusRuntimeException if subscription already exists
 *
 */
public static Subscription createOccurrenceSubscription(String subId, String projectId) 
    throws IOException, StatusRuntimeException {
  // This topic id will automatically receive messages when Occurrences are added or modified
  String topicId = "container-analysis-occurrences-v1beta1";
  SubscriptionAdminClient client = SubscriptionAdminClient.create();
  PushConfig config = PushConfig.getDefaultInstance();
  ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
  ProjectSubscriptionName subName = ProjectSubscriptionName.of(projectId, subId);
  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 .

// occurrencePubsub handles incoming Occurrences using a Cloud Pub/Sub subscription.
func occurrencePubsub(ctx context.Context, subscriptionID string, timeout int, projectID string) (int, error) {
	var mu sync.Mutex
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return -1, err
	}
	// Subscribe to the requested Pub/Sub channel.
	sub := client.Subscription(subscriptionID)
	count := 0

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

// createOccurrenceSubscription creates and returns a Pub/Sub subscription object listening to the Occurrence topic.
func createOccurrenceSubscription(ctx context.Context, subscriptionID, projectID string) error {
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return err
	}

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

Only messages that are published to the topic after the subscription is created are available to subscriber applications.

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.

Was this page helpful? Let us know how we did:

Send feedback about...

Container Registry