本指南将介绍如何使用 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 位置;如果启用了数据驻留,请使用eu
、sa
或us
;否则,请使用值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
:发现结果所在的资源层次结构的级别;使用organizations
、folders
或projects
。PARENT_ID
:父级组织、文件夹或项目的数字 ID,或父级项目的字母数字 ID。SOURCE_ID
:发现结果的来源的数字 ID。LOCATION
:在其中更新发现结果的 Security Command Center 位置;如果启用了数据驻留,请使用eu
、sa
或us
;否则,请使用值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。