Notificaciones de Pub/Sub

En este documento, se describe cómo configurar las notificaciones sobre actualizaciones de notas y casos.

Container Registry proporciona notificaciones a través de Pub/Sub cada vez que realiza análisis en busca de vulnerabilidades y otros metadatos. Cuando se crea o actualiza una nota o un caso, se publica un mensaje en el tema correspondiente para cada versión de la API. Usa el tema correspondiente a tu versión actual de la API.

Antes de comenzar

  1. Habilita la API de Container Analysis

  2. Lee la descripción general de Container Analysis.

Crea temas de Pub/Sub

Después de activar la API de Container Analysis, se crean los siguientes temas de Pub/Sub para tu proyecto:

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

Si los temas se borraron por accidente o no se encuentran disponibles, puedes agregarlos tú mismo.

Console

  1. Ve a la página de temas de Pub/Sub en Cloud Console.

    Abrir la página de temas de Pub/Sub

  2. Haz clic en Crear tema.

  3. Ingresa un tema para las notas con el URI:

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

    En el ejemplo anterior, [PROJECT-ID] es el ID de tu proyecto de Google Cloud.

  4. Haz clic en Crear.

  5. Crea otro tema para los casos con el URI:

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

gcloud

Ejecuta el siguiente comando en el shell o la ventana de la terminal:

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

Para obtener más información sobre el comando gcloud pubsub topics, consulta la documentación de topics.

Cada vez que se crea o actualiza una nota o un caso, se publica un mensaje en el tema correspondiente.

Las cargas útiles de Pub/Sub están en formato JSON y su esquema es el siguiente:

Notas:

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

Casos:

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

donde:

  • [NOTE_KIND] es uno de los valores en NoteKind
  • [NOTIFICATION_TIME] es una marca de tiempo en formato RFC 3339 UTC “Zulu”, con precisión de nanosegundos.

Crea suscripciones a Pub/Sub

Para escuchar eventos, crea una suscripción a Pub/Sub asociada con el tema:

Console

  1. Ve a la página de suscripciones a Pub/Sub en Cloud Console.

    Abrir la página de suscripciones a Pub/Sub

  2. Haz clic en Crear suscripción.

  3. Escribe un nombre para la suscripción. Por ejemplo, notas.

  4. Ingresa el URI del tema para las notas:

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

    En el ejemplo anterior, [PROJECT-ID] es el ID de tu proyecto de Google Cloud.

  5. Haz clic en Crear.

  6. Crea otra suscripción para los casos con el URI:

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

gcloud

Para recibir eventos de Pub/Sub, primero debes crear una suscripción asociada con el tema container-analysis-occurrences-v1:

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

A partir de ahora, puedes extraer mensajes relacionados con tus casos mediante tu nueva suscripción:

gcloud pubsub subscriptions pull \
    --auto-ack occurrences

Java

Para obtener información sobre cómo instalar y usar la biblioteca cliente de Container Registry, consulta las Bibliotecas cliente de Container Registry. Si deseas obtener más información, consulta la documentación de referencia de la API de Java para Container Registry.

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

Para obtener información sobre cómo instalar y usar la biblioteca cliente de Container Registry, consulta las Bibliotecas cliente de Container Registry. Si deseas obtener más información, consulta la documentación de referencia de la API de Container Registry para Go.


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

Para obtener información sobre cómo instalar y usar la biblioteca cliente de Container Registry, consulta las Bibliotecas cliente de Container Registry. Si deseas obtener más información, consulta la documentación de referencia de la API de Node.js para Container Registry.

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

Para obtener información sobre cómo instalar y usar la biblioteca cliente de Container Registry, consulta las Bibliotecas cliente de Container Registry. Si deseas obtener más información, consulta la documentación de referencia de la API de Ruby para Container Registry.

# 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

Para obtener información sobre cómo instalar y usar la biblioteca cliente de Container Registry, consulta las Bibliotecas cliente de Container Registry. Si deseas obtener más información, consulta la documentación de referencia de la API de Python para Container Registry.

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 = f"projects/{project_id}/topics/{topic_id}"
    subscription_name = client.subscription_path(project_id, subscription_id)
    success = True
    try:
        client.create_subscription({"name": subscription_name, "topic": topic_name})
    except AlreadyExists:
        # if subscription already exists, do nothing
        pass
    else:
        success = False
    return success

Las aplicaciones de suscriptor solo reciben los mensajes que se publican en el tema después de que se crea la suscripción.

Qué sigue

  • Si deseas obtener instrucciones para usar Container Analysis a fin de almacenar y administrar los metadatos de tus clientes, consulta Proporcionar metadatos para las imágenes.

  • Puedes integrar la autorización binaria en el análisis de vulnerabilidades para evitar que se ejecuten imágenes con problemas de seguridad conocidos en tu entorno de implementación. Si deseas obtener instrucciones para hacerlo, consulta la Integración del análisis de vulnerabilidades.