Managing findings using the Security Command Center API
Stay organized with collections
Save and categorize content based on your preferences.
This guide walks you through creating and updating findings using the Security Command Center API.
Before you begin
Before you create and update findings, you need to complete the following:
To complete this guide, you must have the Identity and Access Management (IAM) Security
Center Findings Editor (securitycenter.findingsEditor) role at the
organization level. For more information on
Security Command Center roles, see
Access control.
If you want to create findings with security marks, you must also have an IAM role that includes permissions for the kind of mark that you want to use:
- Asset Security Marks Writer (
securitycenter.assetSecurityMarksWriter) - Finding Security Marks Writer (
securitycenter.findingSecurityMarksWriter)
For more information about marks, see Using Security Command Center security marks.
Creating a finding
Create an active finding for a source.
gcloud
gcloudsccfindingscreateFINDING_NAME\ --organization=PARENT_ID\ --location=LOCATION\ --source=SOURCE_ID\ --state=STATE\ --category=CATEGORY\ --event-time=EVENT_TIME\ --resource-name=RESOURCE_NAME
Replace the following:
FINDING_NAME: the name of the finding.PARENT_ID: the numeric ID of the parent organization.LOCATION: the Security Command Center location in which to create a finding; if data residency is enabled, useeu,sa, orus; otherwise, use the valueglobal.SOURCE_ID: the numeric ID of the source for the finding.STATE: the state of the finding; useACTIVEif the finding needs attention orINACTIVEif the finding has been addressed.CATEGORY: the taxonomy group that the finding belongs to; for example,AUDIT_LOGGING_DISABLED.EVENT_TIME: the time when the event occurred, formatted as an RFC 822 timestamp or another timestamp format that the gcloud CLI supports.RESOURCE_NAME: the full resource name of the resource that the finding applies to.
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.
funccreateFinding(wio.Writer,sourceNamestring)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)
iferr!=nil{
returnfmt.Errorf("securitycenter.NewClient: %w",err)
}
deferclient.Close ()// Closing the client safely cleans up background resources.
// Use now as the eventTime for the security finding.
eventTime,err:=ptypes.TimestampProto(time.Now())
iferr!=nil{
returnfmt.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)
iferr!=nil{
returnfmt.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)
returnnil
}
Java
importcom.google.cloud.securitycenter.v2.CreateFindingRequest ;
importcom.google.cloud.securitycenter.v2.Finding ;
importcom.google.cloud.securitycenter.v2.Finding.FindingClass ;
importcom.google.cloud.securitycenter.v2.Finding.Mute ;
importcom.google.cloud.securitycenter.v2.Finding.Severity ;
importcom.google.cloud.securitycenter.v2.Finding.State;
importcom.google.cloud.securitycenter.v2.SecurityCenterClient ;
importcom.google.cloud.securitycenter.v2.SourceName ;
importcom.google.protobuf.Timestamp ;
importjava.io.IOException;
importjava.time.Instant;
importjava.util.Optional;
importjava.util.UUID;
publicclass CreateFindings{
publicstaticvoidmain(String[]args)throwsIOException{
// TODO: Replace the sample resource name
// organizationId: Google Cloud Organization id.
StringorganizationId="{google-cloud-organization-id}";
// Specify the location to list the findings.
Stringlocation="global";
// The source id corresponding to the finding.
StringsourceId="{source-id}";
// The finding id.
StringfindingId="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.
*/
publicstaticFinding createFinding(StringorganizationId,Stringlocation,StringfindingId,
StringsourceId,Optional<String>category)throwsIOException{
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);
InstanteventTime=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.
StringresourceName=String.format("//cloudresourcemanager.googleapis.com/organizations/%s",
organizationId);
// Set up a request to create a finding in a source.
Stringparent=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);
returnresponse;
}
}
}Node.js
// Imports the Google Cloud client library.
const{SecurityCenterClient}=require('@google-cloud/security-center').v2;
constuuid=require('uuid');
// Create a Security Center client
constclient=newSecurityCenterClient ();
// TODO(developer): Update the following for your own environment.
constorganizationId='1081635000895';
constlocation='global';
const[source]=awaitclient.createSource({
source:{
displayName:'Customized Display Name V2',
description:'A new custom source that does X',
},
parent:client.organizationPath(organizationId),
});
constsourceId=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]`
constparent=`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.
constresourceName=`//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.
constfindingId=uuid.v4().replace(/-/g,'');
// Get the current timestamp.
consteventDate=newDate();
// Finding category.
constcategory='MEDIUM_RISK_ONE';
// Build the finding request object.
constcreateFindingRequest={
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]=awaitclient.createFinding(createFindingRequest);
console.log('New finding created: %j',finding);Python
defcreate_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.
"""
importdatetime
fromgoogle.cloudimport securitycenter_v2
fromgoogle.cloud.securitycenter_v2import 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
For information on how long findings data is stored in Security Command Center, read Findings retention.
Updating a finding's state
Security Command Center also provides an API to only update a finding's state. The following example shows how to change a finding's state to inactive.
gcloud
gcloudsccfindingsupdate\
PARENT/PARENT_ID/sources/SOURCE_ID/locations/LOCATION/findings/FINDING_NAME\
--state=STATE
Replace the following:
PARENT: the level of the resource hierarchy where the finding is located; useorganizations,folders, orprojects.PARENT_ID: the numeric ID of the parent organization, folder, or project, or the alphanumeric ID of the parent project.SOURCE_ID: the numeric ID of the source for the finding.LOCATION: the Security Command Center location in which to update a finding; if data residency is enabled, useeu,sa, orus; otherwise, use the valueglobal.FINDING_NAME: the finding to update.STATE: the state of the finding; useACTIVEif the finding needs attention orINACTIVEif the finding has been addressed.
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.
funcsetFindingState(wio.Writer,findingNamestring)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)
iferr!=nil{
returnfmt.Errorf("securitycenter.NewClient: %w",err)
}
deferclient.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)
iferr!=nil{
returnfmt.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)
returnnil
}
Java
importcom.google.cloud.securitycenter.v2.Finding ;
importcom.google.cloud.securitycenter.v2.Finding.State;
importcom.google.cloud.securitycenter.v2.FindingName ;
importcom.google.cloud.securitycenter.v2.SecurityCenterClient ;
importcom.google.cloud.securitycenter.v2.SetFindingStateRequest ;
importjava.io.IOException;
publicclass SetFindingsByState{
publicstaticvoidmain(String[]args)throwsIOException{
// organizationId: Google Cloud Organization id.
StringorganizationId="{google-cloud-organization-id}";
// Specify the location to list the findings.
Stringlocation="global";
// The source id corresponding to the finding.
StringsourceId="{source-id}";
// The finding id.
StringfindingId="{finding-id}";
setFindingState(organizationId,location,sourceId,findingId);
}
// Demonstrates how to update a finding's state
publicstaticFinding setFindingState(StringorganizationId,Stringlocation,StringsourceId,
StringfindingId)throwsIOException{
// 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);
returnfinding;
}
}
}Node.js
// Imports the Google Cloud client library.
const{SecurityCenterClient}=require('@google-cloud/security-center').v2;
// Creates a new client.
constclient=newSecurityCenterClient ();
// TODO(developer): Update the following for your own environment.
constorganizationId='1081635000895';
constlocation='global';
asyncfunctioncreateSampleFinding(){
constuuid=require('uuid');
const[source]=awaitclient.createSource({
source:{
displayName:'Customized Display Name V2',
description:'A new custom source that does X',
},
parent:client.organizationPath(organizationId),
});
constsourceId=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]`
constparent=`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.
constresourceName=`//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.
constfindingId=uuid.v4().replace(/-/g,'');
// Get the current timestamp.
consteventDate=newDate();
// Finding category.
constcategory='MEDIUM_RISK_ONE';
// Build the finding request object.
constcreateFindingRequest={
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,
},
},
};
awaitclient.createFinding(createFindingRequest);
return{sourceId,findingId};
}
const{sourceId,findingId}=awaitcreateSampleFinding();
// The name is the full resource name of the source the finding should be associated with.
constname=`organizations/${organizationId}/sources/${sourceId}/locations/${location}/findings/${findingId}`;
// Build the request.
consteventTime=newDate();
constfindingRequest={
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,
},
};
asyncfunctionsetFindingState(){
// Call the API.
const[response]=awaitclient.setFindingState(findingRequest);
console.log('Set finding state: %j',response);
}
awaitsetFindingState();What's next
Learn more about accessing Security Command Center using client libraries.