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.

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

Before you begin

  1. Enable the Container Analysis API for the project. Enabling this API triggers automatic vulnerability scanning for all your images stored in Container Registry.

    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 required IAM permissions permissions.

    • To view occurrences, you must have the following permission:

      • containeranalysis.notes.listOccurrences

      Alternately, you can 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.

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.

    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 an overview of the vulnerability information:

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

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 {
	req := &grafeaspb.ListOccurrencesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
		Filter: fmt.Sprintf(`kind="DISCOVERY" AND resourceUrl=%q`, imageURL),
	}
	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 vulnerability occurrences

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

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

To view all occurrences for an image, use the following filter expression:

API

The desired resource URL 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) {
	req := &grafeaspb.ListOccurrencesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
		Filter: fmt.Sprintf("resourceUrl=%q", imageURL),
	}
	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
}

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 all images for 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(deployment.undeployTime)

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

kind="DEPLOYABLE" AND resourceUrl="[RESOURCE_URL]" AND \
    deployment.deployTime<"[DEPLOY_TIME]" AND \
    deployment.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

To receive notifications, you must configure the appropriate IAM permissions. For information on the required permissions and roles, refer to the Pub/Sub access control information.

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. After you activate the Container Analysis API, the following Cloud Pub/Sub topics are created for you in your project:

  • container-analysis-notes-v1beta1 + container-analysis- occurrences-v1beta1

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.

    Go to 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-v1beta1
    

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

gcloud

Run the following commands in your shell or terminal window:

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

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:

API

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

gcloud beta pubsub subscriptions create \
    --topic container-analysis-occurrences-v1beta1 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.

¿Te sirvió esta página? Envíanos tu opinión:

Enviar comentarios sobre…