Como visualizar vulnerabilidades e metadados para imagens

O Container Analysis fornece informações sobre vulnerabilidade das imagens de contêiner no Container Registry. Os metadados são armazenados como notas. Uma ocorrência é criada para cada instância de nota associada a uma imagem.

Nesta página, descrevemos como visualizar, filtrar e receber notificações sobre notas e ocorrências.

Antes de começar

  1. Ative a API Container Analysis no projeto. A ativação dessa API aciona a verificação automática de vulnerabilidades de todas as imagens armazenadas no Container Registry.

    É possível ativar a API em um projeto ou criar um novo e ativá-la em seguida.

    Ativar a API Container Analysis

  2. Ative as permissões necessárias do IAM.

    • Para ver ocorrências, é necessário ter a seguinte permissão:

      • containeranalysis.notes.listOccurrences

      Como alternativa, é possível atribuir o seguinte papel predefinido do IAM, que concede automaticamente as permissões necessárias:

      • Leitor de ocorrências do Container Analysis
    • Para receber notificações sobre ocorrências, é necessário configurar as permissões apropriadas do Pub/Sub. Consulte Notificações para saber mais.

  3. Leia a Visão geral do Container Analysis.

Como visualizar vulnerabilidades e outras ocorrências

É possível visualizar as ocorrências das suas imagens no Container Registry usando o Console do GCP, a ferramenta de linha de comando gcloud ou a API Container Analysis.

Para ver as ocorrências de vulnerabilidade das imagens:

Console

  1. Abra a página Container Registry no console do GCP.

    Abrir a página do Container Registry

  2. Clique no nome de uma imagem.

    O total de vulnerabilidades das imagens será exibido na coluna Vulnerabilidades.

    Captura de tela de uma imagem com vulnerabilidades

  3. Para ver a lista de vulnerabilidades de uma imagem, clique no link na coluna Vulnerabilidades.

    A lista de vulnerabilidades mostra a gravidade, se há alguma correção disponível e o nome do pacote que contém a vulnerabilidade.

  4. Para saber mais sobre uma vulnerabilidade específica da origem de vulnerabilidade, clique no link na coluna Documentação.

COMANDO GCLOUD

Para uma visão geral das informações de vulnerabilidade:

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

em que:

  • [PROJECT_ID] é o código do projeto que contém as imagens;
  • [IMAGE_ID] é o código da imagem com as vulnerabilidades que você quer ver;
  • [HOSTNAME] é uma das opções descritas em Nome do registro.

É possível especificar uma tag de imagem com esse comando.

Para ver informações sobre uma tag ou uma camada:

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

  or

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

em que:

  • [PROJECT_ID] é o código do projeto que contém as imagens;
  • [IMAGE_ID] é o código da imagem com as vulnerabilidades que você quer ver;
  • [TAG] é a tag da imagem que tem as informações que você quer receber;
  • [HASH] é o resumo da imagem;
  • [HOSTNAME] é uma das opções descritas em Nome do registro.

Para filtrar as ocorrências de vulnerabilidades:

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

em que:

  • [PROJECT_ID] é o código do projeto que contém as imagens;
  • [IMAGE_ID] é o código da imagem com as ocorrências de vulnerabilidades que você quer ver;
  • [FILTER_EXPRESSION] é uma expressão de filtro de amostra no formato explicado nas Ocorrências de vulnerabilidades de filtragem;
  • [HOSTNAME] é uma das opções descritas em Nome do registro.

API

Como usar cURL

Para ver uma ocorrência:

 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

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Java.

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

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Go.

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

Como filtrar ocorrências

É possível usar strings de filtro nos comandos do gcloud e usar a API Container Analysis para filtrar ocorrências antes de visualizá-las. Veja a descrição dos filtros de pesquisa compatíveis nas seções a seguir.

Como visualizar ocorrências de um tipo específico

O campo tipo identifica o tipo de ocorrência. Use esse campo para limitar a lista de ocorrências a um tipo específico, como uma vulnerabilidade ou implantação.

A expressão de filtro usada para recuperar ocorrências de um tipo específico para uma imagem específica é:

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

em que:

  • [NOTE_KIND] é o tipo de nota;
    • Por exemplo, use o tipo DISCOVERY para listar ocorrências de descoberta. Elas são criadas para imagens no momento em que são enviadas por push para o Container Registry.
    • Para listar as ocorrências de vulnerabilidade, use o tipo VULNERABILITY.
  • [RESOURCE_URL] é o URL completo da imagem https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH].

A expressão de filtro usada para recuperar ocorrências de um tipo específico em várias imagens é:

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

em que:

  • [RESOURCE_URL_PREFIX] é o prefixo de URL para algumas imagens.
    • Para listar todas as versões de uma imagem: https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@
    • Para listar todas as imagens em um projeto: https://[HOSTNAME]/[PROJECT_ID]/

Como visualizar as ocorrências de descoberta

Quando uma imagem é inicialmente enviada para o Container Registry, ele cria uma ocorrência de descoberta que contém informações sobre a verificação inicial da imagem do contêiner.

Para recuperar a ocorrência de descoberta de uma imagem, use a seguinte expressão de filtro:

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

O snippet a seguir mostra como usar a expressão de filtro acima para exibir ocorrências de descoberta para uma imagem:

API

Para recuperar a ocorrência da descoberta, a expressão de filtro acima precisa ser codificada por URL e incorporada a uma solicitação GET da seguinte maneira:

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

Consulte o endpoint da API projects.occurrences.get para mais detalhes.

Java

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Java.

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

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Go.

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

Como visualizar ocorrências de vulnerabilidade

Para visualizar todas as ocorrências de vulnerabilidade de uma imagem específica, crie uma consulta com uma expressão de filtro:

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

Para visualizar todas as ocorrências de uma imagem, use a seguinte expressão de filtro:

API

O URL do recurso pretendido precisa ser codificado por URL e incorporado em uma solicitação GET da seguinte maneira:

GET https://containeranalysis.googleapis.com/v1beta1/projects/PROJECT_ID/occurrences?filter=resourceUrl%3D%22ENCODED_RESOURCE_URL%22

Consulte o endpoint da API projects.occurrences.get para mais detalhes.

Java

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Java.

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

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Go.

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

Como visualizar imagens associadas a uma nota específica

É possível recuperar uma lista de recursos associados a um código de nota específico. Por exemplo, é possível listar imagens com uma vulnerabilidade CVE específica.

Para listar todas as imagens de um projeto que estão associadas a uma nota específica, use a seguinte expressão de filtro:

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

Para verificar uma imagem específica de uma determinada nota, use a seguinte expressão de filtro:

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

em que:

  • [PROVIDER_PROJECT_ID] é o código do projeto provedor. Por exemplo, goog-vulnz fornece a análise de vulnerabilidade padrão;
  • [NOTE_ID] é o código da nota. As notas relacionadas à segurança costumam ter o formato CVE-2019-12345;
  • [RESOURCE_URL] é o URL completo da imagem https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH].

Por exemplo, para verificar todas as imagens que têm uma ocorrência de CVE-2017-16231, conforme analisado pelo Google, use a seguinte expressão de filtro:

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

Como visualizar implantações

É possível listar as implantações que estão sendo executadas atualmente ou as implantações que estavam em execução durante um período específico.

Para visualizar implantações que estão em execução atualmente, use a seguinte expressão de filtro:

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

Para visualizar implantações que estavam em execução durante um período de tempo específico, use a seguinte expressão de filtro:

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

em que:

  • [RESOURCE_URL] é o URL completo da imagem https://[HOSTNAME]/[PROJECT_ID]/[IMAGE_ID]@sha256:[HASH];
  • [DEPLOY_TIME] é o horário de início do período de implantação. Use um carimbo de data/hora no formato UTC "Zulu" RFC 3339, medido com precisão de nanossegundos. Exemplo: "2014-10-02T15:01:23.045123456Z";
  • [UNDEPLOY_TIME] é o término do período de implementação. Use um carimbo de data/hora no formato UTC "Zulu" RFC 3339, medido com precisão de nanossegundos.

Notificações do Cloud Pub/Sub

Para receber notificações, configure as permissões apropriadas do IAM. Para conseguir informações sobre as permissões e papéis necessários, consulte Controle de acesso do PUB/SUB.

Nesta seção, você verá como configurar notificações de atualizações em notas e ocorrências.

O Container Registry fornece notificações via Cloud Pub/Sub sempre que pesquisa vulnerabilidades e outros metadados. Depois de ativar a API Container Analysis, os seguintes tópicos do Cloud Pub/Sub serão criados para você no projeto:

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

Sempre que uma nota ou uma ocorrência for criada ou atualizada, uma mensagem será publicada no respectivo tópico.

Os payloads do Cloud Pub/Sub estão em JSON e o esquema é o seguinte:

Notas:

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

Ocorrências:

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

em que:

  • [NOTE_KIND] é um dos valores em NoteKind;
  • [NOTIFICATION_TIME] é um carimbo de data/hora no formato UTC "Zulu" RFC 3339, precisamente medido em nanossegundos.

Para ouvir esses eventos, crie uma assinatura do Pub/Sub associada ao tópico:

API

Para receber eventos do Cloud Pub/Sub, primeiro crie uma assinatura associada ao tópico container-analysis-occurrences-v1beta1:

gcloud beta pubsub subscriptions create \
    --topic container-analysis-occurrences-v1beta1 occurrences

Agora você pode enviar mensagens sobre suas ocorrências usando a nova assinatura:

gcloud beta pubsub subscriptions pull \
    --auto-ack occurrences

Java

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Java.

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

Para saber como instalar e usar a biblioteca de cliente do Container Registry, consulte Bibliotecas de cliente do Container Registry. Para mais informações, consulte a documentação de referência da API Container Registry Go.

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

Somente as mensagens publicadas no tópico após a criação da assinatura estão disponíveis para os aplicativos inscritos.

Próximas etapas

  • Para instruções sobre como usar o Container Analysis para armazenar e gerenciar os metadados dos clientes, consulte Como fornecer metadados para imagens.

  • Você pode integrar a autorização binária com a verificação de vulnerabilidades para impedir que imagens com problemas de segurança conhecidos sejam executadas no seu ambiente de implementação. Para instruções sobre como fazer isso, consulte Integração da verificação de vulnerabilidades.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…