Administra los resultados con la API de Security Command Center

En esta guía, se explica cómo crear y actualizar resultados con la API de Security Command Center.

Antes de comenzar

Antes de crear y actualizar los resultados, debes completar lo siguiente:

Para completar esta guía, debes tener la función de Identity and Access Management (IAM) Editor de hallazgos del centro de seguridad (securitycenter.findingsEditor) en el nivel de la organización. Para obtener más información sobre los roles de Security Command Center, consulta Control de acceso.

Si deseas crear resultados con marcas de seguridad, también debes tener una función de IAM que incluya permisos para el tipo de marca que deseas usar:

  • Escritor de marcas de seguridad de activos (securitycenter.assetSecurityMarksWriter)
  • Escritor de marcas de seguridad de resultados (securitycenter.findingSecurityMarksWriter)

Para obtener más información sobre las marcas, consulta Usa marcas de seguridad de Security Command Center.

Crea un resultado

Crea un resultado activo para una fuente.

gcloud

gcloud scc findings create FINDING_NAME \
    --organization=PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --state=STATE \
    --category=CATEGORY \
    --event-time=EVENT_TIME \
    --resource-name=RESOURCE_NAME

Reemplaza lo siguiente:

  • FINDING_NAME: Es el nombre del hallazgo.
  • PARENT_ID: El ID numérico de la organización superior.
  • LOCATION: Si la residencia de datos está habilitada, la ubicación de Security Command Center en la que se creará un hallazgo. Si la residencia de datos no está habilitada, usa el valor global.
  • SOURCE_ID: Es el ID numérico de la fuente del resultado.
  • STATE: Es el estado del hallazgo. Usa ACTIVE si el hallazgo requiere atención o INACTIVE si se solucionó.
  • CATEGORY: Es el grupo de taxonomía al que pertenece el hallazgo, por ejemplo, AUDIT_LOGGING_DISABLED.
  • EVENT_TIME: La hora en la que ocurrió el evento, con el formato de una marca de tiempo RFC 822 o de otro formato de marca de tiempo que gcloud CLI de gcloud.
  • RESOURCE_NAME: Es el nombre completo del recurso al que se aplica el hallazgo.

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"github.com/golang/protobuf/ptypes"
)

// createFinding demonstrates how to create a new security finding in CSCC.
// sourceName is the full resource name of the source the finding should
// be associated with.
func createFinding(w io.Writer, sourceName string) error {
	// sourceName := "organizations/111122222444/sources/1234/locations/global"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.
	// Use now as the eventTime for the security finding.
	eventTime, err := ptypes.TimestampProto(time.Now())
	if err != nil {
		return fmt.Errorf("TimestampProto: %w", err)
	}

	req := &securitycenterpb.CreateFindingRequest{
		Parent:    sourceName,
		FindingId: "samplefindingid",
		Finding: &securitycenterpb.Finding{
			State: securitycenterpb.Finding_ACTIVE,
			// Resource the finding is associated with. This is an
			// example any resource identifier can be used.
			ResourceName: "//cloudresourcemanager.googleapis.com/organizations/11232/sources/-/locations/global",
			// A free-form category.
			Category: "MEDIUM_RISK_ONE",
			// The time associated with discovering the issue.
			EventTime: eventTime,
		},
	}
	finding, err := client.CreateFinding(ctx, req)
	if err != nil {
		return fmt.Errorf("CreateFinding: %w", err)
	}
	fmt.Fprintf(w, "New finding created: %s\n", finding.Name)
	fmt.Fprintf(w, "Event time (Epoch Seconds): %d\n", eventTime.Seconds)
	return nil
}

Java


import com.google.cloud.securitycenter.v2.CreateFindingRequest;
import com.google.cloud.securitycenter.v2.Finding;
import com.google.cloud.securitycenter.v2.Finding.FindingClass;
import com.google.cloud.securitycenter.v2.Finding.Mute;
import com.google.cloud.securitycenter.v2.Finding.Severity;
import com.google.cloud.securitycenter.v2.Finding.State;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.SourceName;
import com.google.protobuf.Timestamp;
import java.io.IOException;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

public class CreateFindings {

  public static void main(String[] args) throws IOException {
    // TODO: Replace the sample resource name
    // organizationId: Google Cloud Organization id.
    String organizationId = "{google-cloud-organization-id}";

    // Specify the location to list the findings.
    String location = "global";

    // The source id corresponding to the finding.
    String sourceId = "{source-id}";

    // The finding id.
    String findingId = "testfindingv2" + UUID.randomUUID().toString().split("-")[0];

    // Specify the category.
    Optional<String> category = Optional.of("MEDIUM_RISK_ONE");

    createFinding(organizationId, location, findingId, sourceId, category);
  }

  /**
   * Creates a security finding within a specific source in the Security Command Center.
   */
  public static Finding createFinding(String organizationId, String location, String findingId,
      String sourceId, Optional<String> category) throws IOException {
    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      // Optionally SourceName or String can be used.
      // String sourceName = String.format("organizations/%s/sources/%s", organizationId, sourceId);
      SourceName sourceName = SourceName.of(organizationId, sourceId);

      Instant eventTime = Instant.now();
      // The resource this finding applies to. The Cloud Security Command Center UI can link the
      // findings for a resource to the corresponding asset of a resource if there are matches.
      String resourceName = String.format("//cloudresourcemanager.googleapis.com/organizations/%s",
          organizationId);

      // Set up a request to create a finding in a source.
      String parent = String.format("%s/locations/%s", sourceName.toString(), location);
      Finding finding = Finding.newBuilder()
          .setParent(parent)
          .setState(State.ACTIVE)
          .setSeverity(Severity.LOW)
          .setMute(Mute.UNMUTED)
          .setFindingClass(FindingClass.OBSERVATION)
          .setResourceName(resourceName)
          .setEventTime(Timestamp.newBuilder()
              .setSeconds(eventTime.getEpochSecond())
              .setNanos(eventTime.getNano()))
          .setCategory(category.orElse("LOW_RISK_ONE"))
          .build();

      CreateFindingRequest createFindingRequest = CreateFindingRequest.newBuilder()
          .setParent(parent)
          .setFindingId(findingId)
          .setFinding(finding).build();

      // Call the API.
      Finding response = client.createFinding(createFindingRequest);
      return response;
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
const uuid = require('uuid');

// Create a Security Center client
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

const [source] = await client.createSource({
  source: {
    displayName: 'Customized Display Name V2',
    description: 'A new custom source that does X',
  },
  parent: client.organizationPath(organizationId),
});

const sourceId = source.name.split('/')[3];

// Resource name of the new finding's parent. Examples:
//  - `organizations/[organization_id]/sources/[source_id]`
//  - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
const parent = `organizations/${organizationId}/sources/${sourceId}/locations/${location}`;

// The resource this finding applies to. The Cloud Security Command Center UI can link the
// findings for a resource to the corresponding asset of a resource if there are matches.
const resourceName = `//cloudresourcemanager.googleapis.com/organizations/${organizationId}`;

// Unique identifier provided by the client within the parent scope.
// It must be alphanumeric and less than or equal to 32 characters and
// greater than 0 characters in length.
const findingId = uuid.v4().replace(/-/g, '');

// Get the current timestamp.
const eventDate = new Date();

// Finding category.
const category = 'MEDIUM_RISK_ONE';

// Build the finding request object.
const createFindingRequest = {
  parent: parent,
  findingId: findingId,
  finding: {
    resourceName,
    category,
    state: 'ACTIVE',
    // The time associated with discovering the issue.
    eventTime: {
      seconds: Math.floor(eventDate.getTime() / 1000),
      nanos: (eventDate.getTime() % 1000) * 1e6,
    },
  },
};

// Call the API.
const [finding] = await client.createFinding(createFindingRequest);
console.log('New finding created: %j', finding);

Python

def create_finding(
    organization_id, location_id, finding_id, source_name, category
) -> Dict:
    """
    cretaes a new finding
    Args:
        organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
        source_name: is the resource path for a source that has been created
        finding_id: unique identifier provided by the client.
        location_id: GCP location id; example: 'global'
        category: the additional category group with in findings.
    Returns:
         Dict: returns the created findings details.
    """
    import datetime

    from google.cloud import securitycenter_v2
    from google.cloud.securitycenter_v2 import Finding

    # Create a new client.
    client = securitycenter_v2.SecurityCenterClient()

    # Use the current time as the finding "event time".
    event_time = datetime.datetime.now(tz=datetime.timezone.utc)

    # 'source_name' is the resource path for a source that has been
    # created previously (you can use list_sources to find a specific one).
    # Its format is:
    # source_name = "organizations/{organization_id}/sources/{source_id}"
    # e.g.:
    # source_name = "organizations/111122222444/sources/1234"
    # source_name = f"organizations/{organization_id}/sources/{source_name}"
    # category= "MEDIUM_RISK_ONE"
    # The resource this finding applies to.  The CSCC UI can link
    # the findings for a resource to the corresponding Asset of a resource
    # if there are matches.
    resource_name = (
        f"//cloudresourcemanager.googleapis.com/organizations/{organization_id}"
    )

    finding = Finding(
        state=Finding.State.ACTIVE,
        resource_name=resource_name,
        category=category,
        event_time=event_time,
    )
    parent = source_name + "/locations/" + location_id
    # Call The API.
    created_finding = client.create_finding(
        request={"parent": parent, "finding_id": finding_id, "finding": finding}
    )
    print(created_finding)
    return created_finding

Para obtener información sobre durante cuánto tiempo se almacenan los datos de resultados en Security Command Center, lee Retención de resultados.

Actualiza el estado de un resultado

Security Command Center también proporciona una API para actualizar solo el estado de un resultado. Esta API existe para proporcionar un medio de actualización solo el estado de un resultado. Es una API simple que también permite que los principales de permiso solo puedan modificar el estado y no otro aspecto de un resultado. En el siguiente ejemplo, se muestra cómo cambiar el estado de un resultado a inactivo.

gcloud

gcloud scc findings update \
    PARENT/PARENT_ID/sources/SOURCE_ID/locations/LOCATION/findings/FINDING_NAME \
    --state=STATE

Reemplaza lo siguiente:

  • PARENT: Es el nivel de la jerarquía de recursos en el que se encuentra el hallazgo. Usa organizations, folders o projects.
  • PARENT_ID: El ID numérico de la organización, la carpeta o el proyecto superior, o el ID alfanumérico del proyecto superior.
  • SOURCE_ID: Es el ID numérico de la fuente del resultado.
  • LOCATION: Si la residencia de datos está habilitada, la ubicación de Security Command Center en la que se actualizará un hallazgo. Si la residencia de datos no está habilitada, usa el valor global.
  • FINDING_NAME: Es el hallazgo que se actualizará.
  • STATE: Es el estado del hallazgo. Usa ACTIVE si el hallazgo requiere atención o INACTIVE si se solucionó.

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
)

// updateFindingState demonstrates how to update a security finding's state
// in CSCC.  findingName is the full resource name of the finding to update.
func setFindingState(w io.Writer, findingName string) error {
	// findingName := "organizations/111122222444/sources/1234/locations/global"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.SetFindingStateRequest{
		Name:  findingName,
		State: securitycenterpb.Finding_INACTIVE,
		// New state is effective immediately.
	}

	finding, err := client.SetFindingState(ctx, req)
	if err != nil {
		return fmt.Errorf("SetFindingState: %w", err)
	}

	fmt.Fprintf(w, "Finding updated: %s\n", finding.Name)
	fmt.Fprintf(w, "Finding state: %v\n", finding.State)
	fmt.Fprintf(w, "Event time (Epoch Seconds): %d\n", finding.EventTime.Seconds)

	return nil
}

Java


import com.google.cloud.securitycenter.v2.Finding;
import com.google.cloud.securitycenter.v2.Finding.State;
import com.google.cloud.securitycenter.v2.FindingName;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.SetFindingStateRequest;
import java.io.IOException;

public class SetFindingsByState {

  public static void main(String[] args) throws IOException {
    // organizationId: Google Cloud Organization id.
    String organizationId = "{google-cloud-organization-id}";

    // Specify the location to list the findings.
    String location = "global";

    // The source id corresponding to the finding.
    String sourceId = "{source-id}";

    // The finding id.
    String findingId = "{finding-id}";

    setFindingState(organizationId, location, sourceId, findingId);
  }

  // Demonstrates how to update a finding's state
  public static Finding setFindingState(String organizationId, String location, String sourceId,
      String findingId) throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      // Optionally FindingName or String can be used.
      // String findingName = String.format("organizations/%s/sources/%s/locations/%s/findings/%s",
      // organizationId,sourceId,location,findingId);
      FindingName findingName = FindingName
          .ofOrganizationSourceLocationFindingName(organizationId, sourceId, location, findingId);

      SetFindingStateRequest request = SetFindingStateRequest.newBuilder()
          .setName(findingName.toString())
          .setState(State.INACTIVE)
          .build();

      // Call the API.
      Finding finding = client.setFindingState(request);

      System.out.println("Updated Finding: " + finding);
      return finding;
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;

// Creates a new client.
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

async function createSampleFinding() {
  const uuid = require('uuid');

  const [source] = await client.createSource({
    source: {
      displayName: 'Customized Display Name V2',
      description: 'A new custom source that does X',
    },
    parent: client.organizationPath(organizationId),
  });

  const sourceId = source.name.split('/')[3];

  // Resource name of the new finding's parent. Examples:
  //  - `organizations/[organization_id]/sources/[source_id]`
  //  - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
  const parent = `organizations/${organizationId}/sources/${sourceId}/locations/${location}`;

  // The resource this finding applied to. The Cloud Security Command Center UI can link the
  // findings for a resource to the corresponding asset of a resource if there are matches.
  const resourceName = `//cloudresourcemanager.googleapis.com/organizations/${organizationId}`;

  // Unique identifier provided by the client within the parent scope.
  // It must be alphanumeric and less than or equal to 32 characters and
  // greater than 0 characters in length.
  const findingId = uuid.v4().replace(/-/g, '');

  // Get the current timestamp.
  const eventDate = new Date();

  // Finding category.
  const category = 'MEDIUM_RISK_ONE';

  // Build the finding request object.
  const createFindingRequest = {
    parent: parent,
    findingId: findingId,
    finding: {
      resourceName,
      category,
      state: 'ACTIVE',
      // The time associated with discovering the issue.
      eventTime: {
        seconds: Math.floor(eventDate.getTime() / 1000),
        nanos: (eventDate.getTime() % 1000) * 1e6,
      },
    },
  };

  await client.createFinding(createFindingRequest);
  return {sourceId, findingId};
}

const {sourceId, findingId} = await createSampleFinding();

// The name is the full resource name of the source the finding should be associated with.
const name = `organizations/${organizationId}/sources/${sourceId}/locations/${location}/findings/${findingId}`;

// Build the request.
const eventTime = new Date();

const findingRequest = {
  name,
  state: 'INACTIVE',
  // use now as the time when the new state takes effect.
  startTime: {
    seconds: Math.floor(eventTime.getTime() / 1000),
    nanos: (eventTime.getTime() % 1000) * 1e6,
  },
};

async function setFindingState() {
  // Call the API.
  const [response] = await client.setFindingState(findingRequest);
  console.log('Set finding state: %j', response);
}

await setFindingState();

¿Qué sigue?

Obtén más información para acceder a Security Command Center con bibliotecas cliente.