このガイドでは、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
: ソースの説明(最大 1,024 文字)。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 コンソールにソースは表示されません。特定のソースの取得の手順に沿って、作成されたことを確認できます。
ソースの更新
ソースの表示名と説明は作成後に更新できます。また、フィールド マスクを使用して、更新するフィールドを 1 つのみにすることもできます。次の例では、フィールド マスクを使用して表示名のみを更新し、説明は変更していません。
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
: ソースの説明(最大 1,024 文字)。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 へのアクセスについて詳細を確認する。