本指南将介绍如何使用 Security Command Center API 创建来源以生成发现结果。在您添加来源时,Security Command Center 会创建适当的来源并为它们分配相关权限。
Security Command Center 的 IAM 角色可以在组织、文件夹或项目级层授予。您能否查看、修改、创建或更新发现结果、资产和安全来源,取决于您获授予的访问权限级别。如需详细了解 Security Command Center 角色,请参阅访问权限控制。
准备工作
在设置来源之前,您需要使用 Security Command Center API 进行身份验证。
创建来源
此示例展示了如何创建具有特定显示名称和说明的来源,这些名称和说明在 Security Command Center 内使用。
该服务器会自动为该来源分配一个 ID。
REST
在 API 中,向 organizations.sources.create
方法发出请求:请求正文包含一个 Source
实例。
POST https://securitycenter.googleapis.com/v2/organizations/ORGANIZATION_ID/sources { "name": "SOURCE_NAME", "description": "SOURCE_DESCRIPTION", "displayName": "DISPLAY_NAME" }
替换以下内容:
ORGANIZATION_ID
:您的组织 ID。SOURCE_NAME
:来源的名称。SOURCE_DESCRIPTION
:来源的说明(最多 1024 个字符)。DISPLAY_NAME
:来源的显示名(介于 1 到 64 个字符之间)。
Go
import (
"context"
"fmt"
"io"
securitycenter "cloud.google.com/go/securitycenter/apiv2"
"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
)
// createSource creates a new source for organization orgID. orgID is
// the numeric identifier of the organization
func createSource(w io.Writer, orgID string) error {
// orgID := "12321311"
// 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.CreateSourceRequest{
Source: &securitycenterpb.Source{
DisplayName: "Customized Display Name",
Description: "A new custom source that does X",
},
Parent: fmt.Sprintf("organizations/%s", orgID),
}
source, err := client.CreateSource(ctx, req)
if err != nil {
return fmt.Errorf("CreateSource: %w", err)
}
fmt.Fprintf(w, "New source created: %s\n", source.Name)
fmt.Fprintf(w, "Display Name: %s\n", source.DisplayName)
return nil
}
Java
import com.google.cloud.securitycenter.v2.CreateSourceRequest;
import com.google.cloud.securitycenter.v2.OrganizationName;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.Source;
import java.io.IOException;
public class CreateSource {
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}";
createSource(organizationId);
}
/**
* Creates a new "source" in the Security Command Center.
*/
public static Source createSource(String organizationId) throws IOException {
try (SecurityCenterClient client = SecurityCenterClient.create()) {
// Start setting up a request to create a source in an organization.
OrganizationName organizationName = OrganizationName.of(organizationId);
Source source =
Source.newBuilder()
.setDisplayName("Custom display name")
.setDescription("A source that does X")
.build();
CreateSourceRequest createSourceRequest =
CreateSourceRequest.newBuilder()
.setParent(organizationName.toString())
.setSource(source)
.build();
// The source is not visible in the Security Command Center dashboard
// until it generates findings.
Source response = client.createSource(createSourceRequest);
return response;
}
}
}
Node.js
// Import the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
// Create a new Security Center client
const client = new SecurityCenterClient();
// TODO(developer): Update for your own environment.
const organizationId = '1081635000895';
// Resource name of the new source's parent. Format is:
// "organizations/[organization_id]".
const parent = client.organizationPath(organizationId);
// The source object.
const source = {
displayName: 'Customized Display Name V2',
description: 'A new custom source that does X',
};
// Build the create source request.
const createSourceRequest = {
parent,
source,
};
// The source is not visible in the Security Command Center dashboard
// until it generates findings.
// Call the API
async function createSource() {
const [source] = await client.createSource(createSourceRequest);
console.log('New Source created: %j', source);
}
await createSource();
Python
def create_source(organization_id) -> Dict:
"""
Create a new findings source
Args:
organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
Returns:
Dict: returns the created findings source details.
"""
from google.cloud import securitycenter_v2
client = securitycenter_v2.SecurityCenterClient()
org_name = f"organizations/{organization_id}"
response = client.create_source(
request={
"parent": org_name,
"source": {
"display_name": "Customized Display Name",
"description": "A new custom source that does X",
},
}
)
print(f"Created Source: {response.name}")
return response
来源只有在生成发现结果后才会显示在 Security Command Center 控制台中。您可以按照获取特定来源中的说明来验证其已创建。
更新来源
您可以在创建来源后更新其显示名和说明。您还可以使用字段掩码仅更新一个字段。以下示例使用字段掩码来仅更新显示名,而使说明保持不变。
REST
在 API 中,向 organizations.sources.patch
方法发出请求。请求正文包含一个 Source
实例。
PATCH https://securitycenter.googleapis.com/v2/organizations/ORGANIZATION_ID/sources/SOURCE_ID?updateMask=displayName -d { "description": "SOURCE_DESCRIPTION", "displayName": "DISPLAY_NAME", }
替换以下内容:
ORGANIZATION_ID
:您的组织 ID。SOURCE_ID
:来源 ID;如需了解如何查找来源 ID,请参阅获取来源 ID。SOURCE_DESCRIPTION
:来源的说明(最多 1024 个字符)。DISPLAY_NAME
:来源的显示名(介于 1 到 64 个字符之间)。
Go
import (
"context"
"fmt"
"io"
securitycenter "cloud.google.com/go/securitycenter/apiv2"
"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
"google.golang.org/genproto/protobuf/field_mask"
)
// updateSource changes a sources display name to "New Display Name" for a
// specific source. sourceName is the full resource name of the source to be
// updated.
func updateSource(w io.Writer, sourceName string) error {
// sourceName := "organizations/111122222444/sources/1234"
// 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.UpdateSourceRequest{
Source: &securitycenterpb.Source{
Name: sourceName,
DisplayName: "New Display Name",
},
// Only update the display name field (if not set all mutable
// fields of the source will be updated.
UpdateMask: &field_mask.FieldMask{
Paths: []string{"display_name"},
},
}
source, err := client.UpdateSource(ctx, req)
if err != nil {
return fmt.Errorf("UpdateSource: %w", err)
}
fmt.Fprintf(w, "Source Name: %s, ", source.Name)
fmt.Fprintf(w, "Display name: %s, ", source.DisplayName)
fmt.Fprintf(w, "Description: %s\n", source.Description)
return nil
}
Java
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.Source;
import com.google.cloud.securitycenter.v2.SourceName;
import com.google.cloud.securitycenter.v2.UpdateSourceRequest;
import com.google.protobuf.FieldMask;
import java.io.IOException;
public class UpdateSource {
public static void main(String[] args) throws IOException {
// TODO: Replace the below variables.
// organizationId: Google Cloud Organization id.
String organizationId = "{google-cloud-organization-id}";
// Specify the source-id.
String sourceId = "{source-id}";
updateSource(organizationId, sourceId);
}
// Demonstrates how to update a source.
public static Source updateSource(String organizationId, String sourceId) 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()) {
// Start setting up a request to get a source.
SourceName sourceName = SourceName.ofOrganizationSourceName(organizationId, sourceId);
Source source = Source.newBuilder()
.setDisplayName("Updated Display Name")
.setName(sourceName.toString())
.build();
// Set the update mask to specify which properties should be updated.
// If empty, all mutable fields will be updated.
// For more info on constructing field mask path, see the proto or:
// https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.FieldMask
FieldMask updateMask = FieldMask.newBuilder()
.addPaths("display_name")
.build();
UpdateSourceRequest request = UpdateSourceRequest.newBuilder()
.setSource(source)
.setUpdateMask(updateMask)
.build();
// Call the API.
Source response = client.updateSource(request);
System.out.println("Updated Source: " + response);
return response;
}
}
}
Node.js
// npm install '@google-cloud/security-center'
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
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;
}
const sourceId = await createSampleFinding();
/**
* Required. The source resource to update.
*/
const sourceName = client.organizationSourcePath(organizationId, sourceId);
// Set the update mask to specify which properties should be updated.
// If empty, all mutable fields will be updated.
// For more info on constructing field mask path, see the proto or:
// https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.FieldMask
const updateMask = {
paths: ['display_name'],
};
// Build the request.
const source = {
name: sourceName,
displayName: 'New Display Name',
};
async function updateSource() {
const [response] = await client.updateSource({updateMask, source});
console.log('Updated Source: %j', response);
}
await updateSource();
获取特定来源
使用来源的绝对资源名称来查询 Security Command Center,以验证来源是否已创建或更新:
gcloud
gcloud scc sources describe ORGANIZATION_ID --source=SOURCE_ID
替换以下内容:
ORGANIZATION_ID
:您的组织 ID。SOURCE_ID
:来源 ID。
REST
在 API 中,向 organizations.sources.get
方法发出请求:
GET https://securitycenter.googleapis.com/v2/organizations/ORGANIZATION_ID/sources/SOURCE_ID
替换以下内容:
ORGANIZATION_ID
:您的组织 ID。SOURCE_ID
:来源 ID。
Go
import (
"context"
"fmt"
"io"
securitycenter "cloud.google.com/go/securitycenter/apiv2"
"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
)
// getSource retrieves a source by its resource name and print it to w.
// sourceName is the full resource name of the source to be updated.
func getSource(w io.Writer, sourceName string) error {
// sourceName := "organizations/111122222444/sources/1234"
// 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.GetSourceRequest{
Name: sourceName,
}
source, err := client.GetSource(ctx, req)
if err != nil {
return fmt.Errorf("GetSource: %w", err)
}
fmt.Fprintf(w, "Source: %v\n", source.Name)
fmt.Fprintf(w, "Display Name: %v\n", source.DisplayName)
fmt.Fprintf(w, "Description: %v\n", source.Description)
return nil
}
Java
import com.google.cloud.securitycenter.v2.GetSourceRequest;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.Source;
import com.google.cloud.securitycenter.v2.SourceName;
import java.io.IOException;
public class GetSource {
public static void main(String[] args) throws IOException {
// TODO: Replace the below variables.
// organizationId: Google Cloud Organization id.
String organizationId = "{google-cloud-organization-id}";
// Specify the source-id.
String sourceId = "{source-id}";
getSource(organizationId, sourceId);
}
// Demonstrates how to retrieve a specific source.
public static Source getSource(String organizationId, String sourceId) 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()) {
// Start setting up a request to get a source.
SourceName sourceName = SourceName.ofOrganizationSourceName(organizationId, sourceId);
GetSourceRequest request = GetSourceRequest.newBuilder()
.setName(sourceName.toString())
.build();
// Call the API.
Source response = client.getSource(request);
System.out.println("Source: " + response);
return response;
}
}
}
Node.js
// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
// Create a Security Center 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;
}
const sourceId = await createSampleFinding();
// Relative resource name of the source. Its format is
// "organizations/[organization_id]/source/[source_id]".
const name = `organizations/${organizationId}/sources/${sourceId}`;
// Build the request.
const getSourceRequest = {
name,
};
async function getSource() {
// Call the API.
const [source] = await client.getSource(getSourceRequest);
console.log('Source: %j', source);
}
await getSource();
Python
def get_source(source_name) -> Dict:
"""
Gets the details of an existing source.
Args:
source_name: is the resource path for a source that has been created
Returns:
Dict: returns the details of existing source.
"""
from google.cloud import securitycenter_v2
client = securitycenter_v2.SecurityCenterClient()
# '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 = client.get_source(request={"name": source_name})
print(f"Source: {source}")
return source
列出来源
通过 Security Command Center,您可以列出特定来源,并列出组织中当前可用的所有来源:
REST
在 API 中,向 organizations.sources.list
方法发出请求:
GET https://securitycenter.googleapis.com/v2/organizations/ORGANIZATION_ID/sources
替换以下内容:
ORGANIZATION_ID
:您的组织 ID。
Go
import (
"context"
"fmt"
"io"
securitycenter "cloud.google.com/go/securitycenter/apiv2"
"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
"google.golang.org/api/iterator"
)
// listSources prints all sources in orgID to w. orgID is the numeric
// identifier of the organization.
func listSources(w io.Writer, orgID string) error {
// orgID := "12321311"
// 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.ListSourcesRequest{
// Parent must be in one of the following formats:
// "organizations/{orgId}"
// "projects/{projectId}"
// "folders/{folderId}"
Parent: fmt.Sprintf("organizations/%s", orgID),
}
it := client.ListSources(ctx, req)
for {
source, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
return fmt.Errorf("it.Next: %w", err)
}
fmt.Fprintf(w, "Source Name: %s, ", source.Name)
fmt.Fprintf(w, "Display name: %s, ", source.DisplayName)
fmt.Fprintf(w, "Description: %s\n", source.Description)
}
return nil
}
Java
import com.google.cloud.securitycenter.v2.OrganizationLocationName;
import com.google.cloud.securitycenter.v2.OrganizationName;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.SecurityCenterClient.ListSourcesPagedResponse;
import com.google.cloud.securitycenter.v2.Source;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ListSources {
public static void main(String[] args) throws IOException {
// TODO: Replace the below variables.
// organizationId: Google Cloud Organization id.
String organizationId = "{google-cloud-organization-id}";
listSources(organizationId);
}
// Demonstrates how to list all security sources in an organization.
public static List<Source> listSources(String organizationId) 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()) {
// Start setting up a request to get a source.
OrganizationName parent = OrganizationName.of(organizationId);
// Call the API.
List<Source> sourcesList = new ArrayList<>();
ListSourcesPagedResponse response = client.listSources(parent);
response.iterateAll().forEach(sourcesList::add);
for (Source source : sourcesList) {
System.out.println("List sources: " + source);
}
return sourcesList;
}
}
}
Node.js
// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
const client = new SecurityCenterClient();
// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
// Required. Resource name of the parent of sources to list. Its format should
// be "organizations/[organization_id]", "folders/[folder_id]", or
// "projects/[project_id]".
const parent = `organizations/${organizationId}`;
// Build the request.
const listSourcesRequest = {
parent,
};
async function listAllSources() {
// Call the API.
const iterable = client.listSourcesAsync(listSourcesRequest);
let count = 0;
console.log('Sources:');
for await (const response of iterable) {
console.log(`${++count} ${response.name} ${response.description}`);
}
}
await listAllSources();
后续步骤
详细了解如何使用 SDK 访问 Security Command Center。