Configurer des notifications Pub/Sub

Ce document explique comment configurer les notifications pour les mises à jour des notes et des occurrences.

Artifact Analysis fournit des notifications via Pub/Sub pour les failles détectées lors d'une analyse automatisée et pour d'autres métadonnées. Lorsqu'une note ou une occurrence est créée ou mise à jour, un message est publié dans le sujet correspondant pour chaque version de l'API. Utilisez le sujet correspondant à la version de l'API que vous utilisez.

Avant de commencer

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Enable the Container Analysis API.

    Enable the API

  4. Install the Google Cloud CLI.
  5. To initialize the gcloud CLI, run the following command:

    gcloud init
  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  7. Enable the Container Analysis API.

    Enable the API

  8. Install the Google Cloud CLI.
  9. To initialize the gcloud CLI, run the following command:

    gcloud init
  10. Découvrez comment configurer le contrôle des accès pour les métadonnées de votre projet. Ignorez cette étape si vous n'utilisez que les métadonnées des occurrences de failles créées par l'analyse des conteneurs Artifact Analysis.

Créer des sujets Pub/Sub

Une fois l'API Artifact Analysis activée, elle crée automatiquement des sujets Pub/Sub avec les ID de sujet suivants:

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

Si les sujets ont été supprimés par accident ou sont manquants, vous pouvez les ajouter vous-même. Par exemple, les sujets peuvent être manquants si votre organisation Google Cloud est soumise à une contrainte de règle d'administration qui nécessite le chiffrement avec des clés de chiffrement gérées par le client (CMEK). Lorsque l'API Pub/Sub figure dans la liste de refus de cette contrainte, les services ne peuvent pas créer automatiquement de sujets avec des clés appartenant à Google et gérées par Google.

Pour créer des sujets avec des clés détenues et gérées par Google:

Console

  1. Accédez à la page des sujets Pub/Sub dans la console Google Cloud.

    Ouvrir la page "Sujets Pub/Sub"

  2. Cliquez sur Créer un sujet.

  3. Saisissez un ID de sujet:

    container-analysis-notes-v1
    

    afin que le nom corresponde à l'URI:

    projects/PROJECT_ID/topics/container-analysis-notes-v1
    

    PROJECT_ID correspond à votre ID de projet Google Cloud.

  4. Cliquez sur Créer.

  5. Saisissez un ID de sujet:

    container-analysis-occurrences-v1
    

    afin que le nom corresponde à l'URI:

    projects/PROJECT_ID/topics/container-analysis-occurrences-v1
    

gcloud

Exécutez les commandes suivantes dans la fenêtre de votre interface système ou de votre 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

Pour en savoir plus sur la commande gcloud pubsub topics, consultez la documentation sur topics.

Pour créer des sujets avec le chiffrement CMEK, consultez les instructions Pub/Sub pour chiffrer des sujets.

Chaque fois qu'une note ou une occurrence est créée ou mise à jour, un message est publié dans le sujet correspondant. Vous devez toutefois également créer un abonnement Pub/Sub pour écouter les événements et recevoir des messages du service Pub/Sub.

Créer un abonnement Pub/Sub

Pour écouter des événements, créez un abonnement Pub/Sub associé au sujet:

Console

  1. Accédez à la page "Abonnements Pub/Sub" dans la console Google Cloud.

    Ouvrir la page "Abonnements Pub/Sub"

  2. Cliquez sur Créer un abonnement.

  3. Saisissez un nom pour l'abonnement. Exemple : notes.

  4. Saisissez l'URI du sujet pour les notes :

    projects/PROJECT_ID/topics/container-analysis-notes-v1
    

    PROJECT_ID correspond à votre ID de projet Google Cloud.

  5. Cliquez sur Créer.

  6. Créez un autre abonnement pour les occurrences avec l'URI :

    projects/PROJECT_ID/topics/container-analysis-occurrences-v1
    

gcloud

Pour recevoir des événements Pub/Sub, vous devez d'abord créer un abonnement associé au sujet container-analysis-occurrences-v1 :

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

Vous pouvez ensuite récupérer des messages concernant vos occurrences à l'aide de votre nouvel abonnement :

gcloud pubsub subscriptions pull \
    --auto-ack occurrences

Java

Pour savoir comment installer et utiliser la bibliothèque cliente pour l'Artifact Analysis, consultez la page Bibliothèques clientes d'analyse d'artefacts. Pour en savoir plus, consultez la documentation de référence de l'API Artifact Analysis Java.

Pour vous authentifier auprès d'Artifact Analysis, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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.PubsubMessage;
import com.google.pubsub.v1.PushConfig;
import com.google.pubsub.v1.Subscription;
import com.google.pubsub.v1.SubscriptionName;
import com.google.pubsub.v1.TopicName;
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";
    TopicName topicName = TopicName.of(projectId, topicId);
    SubscriptionName subName = SubscriptionName.of(projectId, subId);

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

Go

Pour savoir comment installer et utiliser la bibliothèque cliente pour l'Artifact Analysis, consultez la page Bibliothèques clientes d'analyse d'artefacts. Pour en savoir plus, consultez la documentation de référence de l'API Artifact Analysis Go.

Pour vous authentifier auprès d'Artifact Analysis, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.


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: %w", 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: %w", 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: %w", 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: %w", err)
}

Node.js

Pour savoir comment installer et utiliser la bibliothèque cliente pour l'Artifact Analysis, consultez la page Bibliothèques clientes d'analyse d'artefacts. Pour en savoir plus, consultez la documentation de référence de l'API Artifact Analysis Node.js.

Pour vous authentifier auprès d'Artifact Analysis, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour l'Artifact Analysis, consultez la page Bibliothèques clientes d'analyse d'artefacts. Pour en savoir plus, consultez la documentation de référence de l'API Artifact Analysis Ruby.

Pour vous authentifier auprès d'Artifact Analysis, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

# 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

Pour savoir comment installer et utiliser la bibliothèque cliente pour l'Artifact Analysis, consultez la page Bibliothèques clientes d'analyse d'artefacts. Pour en savoir plus, consultez la documentation de référence de l'API Artifact Analysis Python.

Pour vous authentifier auprès d'Artifact Analysis, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

import time

from google.api_core.exceptions import AlreadyExists
from google.cloud.pubsub import SubscriberClient
from google.cloud.pubsub_v1.subscriber.message import Message


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

    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) -> None:
        # initialize counter to 0 on initialization
        self.msg_count = 0

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


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

    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

Les applications d'abonnés ne reçoivent que les messages publiés dans le sujet après la création de l'abonnement.

Les charges utiles Pub/Sub sont au format JSON et leur schéma se présente comme suit :

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",
}

où :

  • NOTE_KIND est l'une des valeurs de NoteKind.
  • NOTIFICATION_TIME est un code temporel au format RFC 3339 UTC "Zulu", précis à la nanoseconde près.

Afficher les détails

Pour en savoir plus sur une note ou une occurrence, vous pouvez accéder aux métadonnées stockées dans l'Artifact Analysis. Par exemple, vous pouvez demander tous les détails d'un événement spécifique. Pour en savoir plus, consultez la section Examiner les failles.

Étape suivante

  • Pour savoir comment utiliser Artifact Analysis pour stocker et gérer vos métadonnées personnalisées, consultez la section Créer des notes et des occurrences personnalisées.

  • Vous pouvez utiliser des attestations avec l'analyse des failles pour empêcher les images présentant des problèmes de sécurité connus de s'exécuter dans votre environnement de déploiement. Pour obtenir des instructions à ce sujet, consultez la section Créer des attestations avec Kritis Signer.