Pub/Sub 알림 구성

이 문서에서는 메모어커런스 업데이트 알림을 설정하는 방법을 설명합니다.

Artifact Analysis는 자동 스캔으로 발견된 취약점과 기타 메타데이터에 대해 Pub/Sub를 통해 알림을 제공합니다. 메모 또는 어커런스가 생성되거나 업데이트되면 각 API 버전에 해당하는 주제에 메시지가 게시됩니다. 사용 중인 API 버전의 주제를 사용하세요.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Enable the Container Analysis API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  4. Google Cloud CLI를 설치합니다.

  5. 외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 gcloud CLI에 로그인해야 합니다.

  6. gcloud CLI를 초기화하려면, 다음 명령어를 실행합니다.

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

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  8. Enable the Container Analysis API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  9. Google Cloud CLI를 설치합니다.

  10. 외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 gcloud CLI에 로그인해야 합니다.

  11. gcloud CLI를 초기화하려면, 다음 명령어를 실행합니다.

    gcloud init
  12. 프로젝트의 메타데이터에 대한 액세스 제어를 설정하는 방법을 알아봅니다. Artifact Analysis 컨테이너 스캔으로 생성된 어커런스의 메타데이터만 사용하는 경우 이 단계를 건너뛰세요.

Pub/Sub 주제 만들기

Artifact Analysis API를 활성화하면 Artifact Analysis는 다음 주제 ID로 Pub/Sub 주제를 자동으로 만듭니다.

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

주제가 실수로 삭제되거나 누락된 경우 직접 추가할 수 있습니다. 예를 들어 Google Cloud조직에 고객 관리 암호화 키 (CMEK)로 암호화해야 하는 조직 정책 제약조건이 있는 경우 주제가 누락될 수 있습니다. Pub/Sub API가 이 제약조건의 거부 목록에 있으면 서비스가Google-owned and Google-managed encryption keys로 주제를 자동으로 만들 수 없습니다.

Google-owned and Google-managed encryption keys로 주제를 만들려면 다음 단계를 따르세요.

콘솔

  1. Google Cloud 콘솔에서 Pub/Sub 주제 페이지로 이동합니다.

    Pub/Sub 주제 페이지 열기

  2. 주제 만들기를 클릭합니다.

  3. 주제 ID를 입력합니다.

    container-analysis-notes-v1
    

    이름이 URI와 일치하도록 합니다.

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

    여기서 PROJECT_ID는 Google Cloud 프로젝트 ID입니다.

  4. 만들기를 클릭합니다.

  5. 주제 ID를 입력합니다.

    container-analysis-occurrences-v1
    

    이름이 URI와 일치하도록 합니다.

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

gcloud

셸 또는 터미널 창에서 다음 명령어를 실행합니다.

gcloud pubsub topics create projects/PROJECT_ID/topics/container-analysis-notes-v1
gcloud pubsub topics create projects/PROJECT_ID/topics/container-analysis-occurrences-v1

gcloud pubsub topics 명령어에 대한 자세한 내용은 topics 문서를 참조하세요.

CMEK 암호화로 주제를 만들려면 Pub/Sub 주제 암호화 안내를 참고하세요.

메모나 어커런스가 작성되거나 업데이트될 때마다 해당 주제에 메시지가 게시됩니다. 하지만 이벤트를 수신하고 Pub/Sub 서비스에서 메시지를 받으려면 Pub/Sub 구독도 만들어야 합니다.

Pub/Sub 구독 만들기

이벤트를 수신하려면 주제와 연결된 Pub/Sub 구독을 만듭니다.

콘솔

  1. Google Cloud 콘솔에서 Pub/Sub 구독 페이지로 이동합니다.

    Pub/Sub 구독 페이지 열기

  2. 구독 만들기를 클릭합니다.

  3. 구독 이름을 입력합니다. 예를 들어 메모가 있습니다.

  4. 메모의 주제 URI를 입력합니다.

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

    여기서 PROJECT_ID는 Google Cloud 프로젝트 ID입니다.

  5. 만들기를 클릭합니다.

  6. URI와 함께 또 다른 어커런스 구독을 만듭니다.

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

gcloud

Pub/Sub 이벤트를 수신하려면 먼저 container-analysis-occurrences-v1 주제와 관련된 구독을 만들어야 합니다.

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

이후에는 새 구독을 이용해 어커런스에 대한 메시지를 가져올 수 있습니다.

gcloud pubsub subscriptions pull \
    --auto-ack occurrences

Java

Artifact Analysis용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Artifact Analysis 클라이언트 라이브러리를 참고하세요. 자세한 내용은 Artifact Analysis Java API 참고 문서를 참고하세요.

Artifact Analysis에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.

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

Artifact Analysis용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Artifact Analysis 클라이언트 라이브러리를 참고하세요. 자세한 내용은 Artifact Analysis Go API 참고 문서를 참고하세요.

Artifact Analysis에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.


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

Artifact Analysis용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Artifact Analysis 클라이언트 라이브러리를 참고하세요. 자세한 내용은 Artifact Analysis Node.js API 참고 문서를 참고하세요.

Artifact Analysis에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.

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

Artifact Analysis용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Artifact Analysis 클라이언트 라이브러리를 참고하세요. 자세한 내용은 Artifact Analysis Ruby API 참고 문서를 참고하세요.

Artifact Analysis에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.

# 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_id: project_id
subscription_admin = pubsub.subscription_admin
subscription = subscription_admin.create_subscription \
  name: pubsub.subscription_path(subscription_id),
  topic: pubsub.topic_path("container-analysis-occurrences-v1")

subscriber = pubsub.subscriber subscription.name
count = 0
listener = subscriber.listen do |received_message|
  count += 1
  # Process incoming occurrence here
  puts "Message #{count}: #{received_message.data}"
  received_message.acknowledge!
end

listener.start
# Wait for incoming occurrences
sleep timeout_seconds
listener.stop.wait!

subscription_admin.delete_subscription subscription: subscription.name

# Print and return the total number of Pub/Sub messages received
puts "Total Messages Received: #{count}"
count

Python

Artifact Analysis용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Artifact Analysis 클라이언트 라이브러리를 참고하세요. 자세한 내용은 Artifact Analysis Python API 참고 문서를 참고하세요.

Artifact Analysis에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.

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

구독자 애플리케이션은 구독이 생성된 후에만 주제에 게시된 메시지를 수신합니다.

Pub/Sub 페이로드는 JSON 형식이며 스키마는 다음과 같습니다.

메모:

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

어커런스:

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

각 항목의 의미는 다음과 같습니다.

  • NOTE_KINDNoteKind의 값 중 하나입니다.
  • NOTIFICATION_TIME는 RFC 3339 UTC 'Zulu' 형식의 타임스탬프로, 정밀도는 나노초 수준입니다.

세부정보 보기

메모 또는 발생에 대해 자세히 알아보려면 아티팩트 분석에 저장된 메타데이터에 액세스하면 됩니다. 예를 들어 특정 발생의 모든 세부정보를 요청할 수 있습니다. 취약점 조사의 안내를 참고하세요.

다음 단계