使用 Security Command Center API 管理发现结果

本指南将介绍如何使用 Security Command Center API 创建和更新发现结果。

准备工作

在创建和更新发现结果之前,您需要完成以下操作:

为完成本指南,必须拥有组织级别的 Identity and Access Management (IAM) Security Center Findings Editor (securitycenter.findingsEditor) 角色。如需详细了解 Security Command Center 角色,请参阅访问权限控制

如果要使用安全标志创建发现结果,还必须拥有包含要使用的标记种类的权限的 IAM 角色:

  • Asset Security Marks Writer (securitycenter.assetSecurityMarksWriter)
  • Finding Security Marks Writer (securitycenter.findingSecurityMarksWriter)

如需详细了解标记,请参阅 使用 Security Command Center 安全标记

创建发现结果

为来源创建活跃的发现结果。

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

替换以下内容:

  • FINDING_NAME:发现结果的名称。
  • PARENT_ID:父级组织的数字 ID。
  • LOCATION:在其中创建发现结果的 Security Command Center 位置;如果启用了数据驻留,请使用 eusaus;否则,请使用值 global
  • SOURCE_ID:发现结果的来源的数字 ID。
  • STATE:发现结果的状态;如果发现结果需要注意,请使用 ACTIVE;如果发现结果已解决,请使用 INACTIVE
  • CATEGORY:发现结果所属的分类群组;例如 AUDIT_LOGGING_DISABLED
  • EVENT_TIME:事件发生的时间,格式为 RFC 822 时间戳或其他 gcloud CLI 支持的时间戳格式
  • RESOURCE_NAME:发现结果适用的资源的完整资源名称。

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  

如需了解 Security Command Center 中发现结果数据的存储时长,请参阅发现结果保留

更新发现结果的状态

Security Command Center 还提供了一个 API,可让您仅更新发现结果的状态。以下示例展示了如何将发现结果的状态更改为非活跃。

gcloud

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

替换以下内容:

  • PARENT:发现结果所在的资源层次结构的级别;使用 organizationsfoldersprojects
  • PARENT_ID:父级组织、文件夹或项目的数字 ID,或父级项目的字母数字 ID。
  • SOURCE_ID:发现结果的来源的数字 ID。
  • LOCATION:在其中更新发现结果的 Security Command Center 位置;如果启用了数据驻留,请使用 eusaus;否则,请使用值 global
  • FINDING_NAME:要更新的发现结果。
  • STATE:发现结果的状态;如果发现结果需要注意,请使用 ACTIVE;如果发现结果已解决,请使用 INACTIVE

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();

后续步骤

详细了解如何使用客户端库访问 Security Command Center