Security Command Center API를 사용하여 보안 소스 관리

>

이 가이드에서는 Security Command Center API를 사용하여 조직의 발견 항목을 생성할 수 있는 소스를 만드는 방법을 설명합니다. 소스를 추가하면 Security Command Center는 적절한 소스를 만들어 관련 권한을 할당합니다.

시작하기 전에

소스를 설정하기 전에 다음을 완료해야 합니다.

소스 만들기

이 예시에서는 Security Command Center 대시보드에서 사용할 특정 표시 이름과 설명이 있는 소스를 만드는 방법을 보여줍니다.

소스 ID는 서버에서 자동으로 할당됩니다.

Python

from google.cloud import securitycenter

client = securitycenter.SecurityCenterClient()
# organization_id is the numeric ID of the organization. e.g.:
# organization_id = "111122222444"
org_name = "organizations/{org_id}".format(org_id=organization_id)

created = client.create_source(
    org_name,
    {
        "display_name": "Customized Display Name",
        "description": "A new custom source that does X",
    },
)
print("Created Source: {}".format(created.name))

자바

static Source createSource(OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to create a source in an organization.
    // OrganizationName organizationName = OrganizationName.of(/*organizationId=*/"123234324");
    Source source =
        Source.newBuilder()
            .setDisplayName("Customized Display Name")
            .setDescription("A new custom source that does X")
            .build();

    CreateSourceRequest.Builder request =
        CreateSourceRequest.newBuilder().setParent(organizationName.toString()).setSource(source);

    // Call the API.
    Source response = client.createSource(request.build());

    System.out.println("Created Source: " + response);
    return response;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

// 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: %v", 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: %v", err)
	}

	fmt.Fprintf(w, "New source created: %s\n", source.Name)
	fmt.Fprintf(w, "Display Name: %s\n", source.DisplayName)
	return nil
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();
// organizationId is numeric organization identifier.
/*
 * TODO(developer): Uncomment the following lines
 */
// const organizationId = "1234567777";
async function createSource() {
  const [source] = await client.createSource({
    source: {
      displayName: 'Customized Display Name',
      description: 'A new custom source that does X',
    },
    parent: client.organizationPath(organizationId),
  });
  console.log('New Source: %j', source);
}
createSource();

소스는 발견 항목을 생성할 때까지 대시보드에 표시되지 않습니다. 특정 소스 가져오기의 안내에 따라 파일이 생성되었는지 확인할 수 있습니다.

소스 업데이트

소스가 생성된 후 소스의 표시 이름 및 설명을 업데이트할 수 있습니다. 필드 마스크를 사용하여 하나의 필드만 업데이트할 수도 있습니다. 아래 예시에서는 필드 마스크를 사용하여 표시 이름만 업데이트하고 설명은 변경하지 않습니다.

Python

from google.cloud import securitycenter
from google.protobuf import field_mask_pb2

client = securitycenter.SecurityCenterClient()

# Field mask to only update the display name.
field_mask = field_mask_pb2.FieldMask(paths=["display_name"])

# 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"
updated = client.update_source(
    {"name": source_name, "display_name": "Updated Display Name"},
    update_mask=field_mask,
)
print("Updated Source: {}".format(updated))

자바

static Source updateSource(SourceName sourceName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to update a source.
    // SourceName sourceName = SourceName.of(/*organization=*/"123234324",/*source=*/
    // "423432321");
    Source source =
        Source.newBuilder()
            .setDisplayName("Updated Display Name")
            .setName(sourceName.toString())
            .build();
    FieldMask updateMask = FieldMask.newBuilder().addPaths("display_name").build();

    UpdateSourceRequest.Builder request =
        UpdateSourceRequest.newBuilder().setSource(source).setUpdateMask(updateMask);

    // Call the API.
    Source response = client.updateSource(request.build());

    System.out.println("Updated Source: " + response);
    return response;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
	"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: %v", 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: %v", 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
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();
// sourceName is the full resource path to the update target.
/*
 * TODO(developer): Uncomment the following lines
 */
// const sourceName = "organizations/111122222444/sources/1234";
async function updateSource() {
  const [source] = await client.updateSource({
    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: {paths: ['display_name']},
  });
  console.log('Updated source: %j', source);
}

updateSource();

소스에 IAM 정책 설정

소스를 생성한 후 ID 및 액세스 관리(IAM) 정책을 업데이트하여 허용합니다.

Python

from google.cloud import securitycenter
from google.iam.v1 import policy_pb2

client = securitycenter.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"
# Get the old policy so we can do an incremental update.
old_policy = client.get_iam_policy(source_name)
print("Old Policy: {}".format(old_policy))

# Setup a new IAM binding.
binding = policy_pb2.Binding()
binding.role = "roles/securitycenter.findingsEditor"
# user_email is an e-mail address known to Cloud IAM (e.g. a gmail address).
# user_mail = user@somedomain.com
binding.members.append("user:{}".format(user_email))

# Setting the e-tag avoids over-write existing policy
updated = client.set_iam_policy(
    source_name, {"etag": old_policy.etag, "bindings": [binding]}
)

print("Updated Policy: {}".format(updated))

자바

static Policy setIamPolicySource(SourceName sourceName, String userEmail) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // userEmail = "someuser@domain.com"
    // Set up IAM Policy for the user userMail to use the role findingsEditor.
    // The user must be a valid google account.
    Policy oldPolicy = client.getIamPolicy(sourceName.toString());
    Binding bindings =
        Binding.newBuilder()
            .setRole("roles/securitycenter.findingsEditor")
            .addMembers("user:" + userEmail)
            .build();
    Policy policy = oldPolicy.toBuilder().addBindings(bindings).build();

    // Start setting up a request to set IAM policy for a source.
    // SourceName sourceName = SourceName.of("123234324", "423432321");
    SetIamPolicyRequest.Builder request =
        SetIamPolicyRequest.newBuilder().setPolicy(policy).setResource(sourceName.toString());

    // Call the API.
    Policy response = client.setIamPolicy(request.build());

    System.out.println("Policy: " + response);
    return response;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	iam "google.golang.org/genproto/googleapis/iam/v1"
)

// setSourceIamPolicy grants user roles/securitycenter.findingsEditor permision
// for a source. sourceName is the full resource name of the source to be
// updated. user is an email address that IAM can grant permissions to.
func setSourceIamPolicy(w io.Writer, sourceName string, user string) error {
	// sourceName := "organizations/111122222444/sources/1234"
	// user := "someuser@some_domain.com
	// 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: %v", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	// Retrieve the existing policy so we can update only a specific
	// field.
	existing, err := client.GetIamPolicy(ctx, &iam.GetIamPolicyRequest{
		Resource: sourceName,
	})
	if err != nil {
		return fmt.Errorf("GetIamPolicy(%s): %v", sourceName, err)
	}

	req := &iam.SetIamPolicyRequest{
		Resource: sourceName,
		Policy: &iam.Policy{
			// Enables partial update of existing policy
			Etag: existing.Etag,
			Bindings: []*iam.Binding{{
				Role: "roles/securitycenter.findingsEditor",
				// New IAM Binding for the user.
				Members: []string{fmt.Sprintf("user:%s", user)},
			},
			},
		},
	}
	policy, err := client.SetIamPolicy(ctx, req)
	if err != nil {
		return fmt.Errorf("SetIamPolicy(%s, %v): %v", sourceName, req.Policy, err)
	}

	fmt.Fprint(w, "Bindings:\n")
	for _, binding := range policy.Bindings {
		for _, member := range binding.Members {
			fmt.Fprintf(w, "Principal: %s Role: %s\n", member, binding.Role)
		}
	}
	return nil
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();

async function setSourceIamPolicy() {
  // sourceName is the full resource name of the source to be
  // updated.
  // user is an email address that IAM can grant permissions to.
  /*
   * TODO(developer): Uncomment the following lines
   */
  // const sourceName = "organizations/111122222444/sources/1234";
  // const user = "someuser@domain.com";
  const [existingPolicy] = await client.getIamPolicy({
    resource: sourceName,
  });

  const [updatedPolicy] = await client.setIamPolicy({
    resource: sourceName,
    policy: {
      // Enables partial update of existing policy
      etag: existingPolicy.etag,
      bindings: [
        {
          role: 'roles/securitycenter.findingsEditor',
          // New IAM Binding for the user.
          members: [`user:${user}`],
        },
      ],
    },
  });
  console.log('Updated policy: %j', updatedPolicy);
}
setSourceIamPolicy();

특정 소스 가져오기

소스의 절대 리소스 이름으로 Security Command Center를 쿼리하면 소스가 적절하게 생성되었거나 업데이트되었는지 확인할 수 있습니다.

gcloud

  # Note: For GCloud you can use either full resource name or just ID Flags.
  # In this example, we are using ID Flags.
  # ORGANIZATION_ID=12344321
  # SOURCE_ID=43211234

  gcloud scc sources describe $ORGANIZATION_ID --source=$SOURCE_ID

더 많은 예시를 보려면 다음을 실행하세요.

  gcloud scc sources describe --help

Python

from google.cloud import securitycenter

client = securitycenter.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(source_name)

print("Source: {}".format(source))

자바

static Source getSource(SourceName sourceName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to get a source.
    // SourceName sourceName = SourceName.of(/*organization=*/"123234324",/*source=*/
    // "423432321");
    GetSourceRequest.Builder request =
        GetSourceRequest.newBuilder().setName(sourceName.toString());

    // Call the API.
    Source response = client.getSource(request.build());

    System.out.println("Source: " + response);
    return response;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

// 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: %v", 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: %v", 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
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();
// sourceName is the full resource name of the source to be retrieved.
/*
 * TODO(developer): Uncomment the following lines
 */
// const sourceName = "organizations/111122222444/sources/1234";
async function getSource() {
  const [source] = await client.getSource({name: sourceName});
  console.log('Source: %j', source);
}

getSource();

소스 나열

Security Command Center를 사용하면 특정 소스를 나열하고 현재 조직에서 사용할 수 있는 모든 소스를 나열할 수 있습니다.

Python

from google.cloud import securitycenter

# Create a new client.
client = securitycenter.SecurityCenterClient()
# organization_id is the numeric ID of the organization. e.g.:
# organization_id = "111122222444"
org_name = "organizations/{org_id}".format(org_id=organization_id)

# Call the API and print out each existing source.
for i, source in enumerate(client.list_sources(org_name)):
    print(i, source)

자바

static ImmutableList<Source> listSources(OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to list sources in an organization.
    // OrganizationName organizationName = OrganizationName.of(/*organizationId=*/"123234324");
    ListSourcesRequest.Builder request =
        ListSourcesRequest.newBuilder().setParent(organizationName.toString());

    // Call the API.
    ListSourcesPagedResponse response = client.listSources(request.build());

    // This creates one list for all sources.  If your organization has a large number of sources
    // this can cause out of memory issues.  You can process them batches by returning
    // the Iterable returned response.iterateAll() directly.
    ImmutableList<Source> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("Sources:");
    System.out.println(results);
    return results;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"google.golang.org/api/iterator"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

// 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: %v", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.ListSourcesRequest{
		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: %v", 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
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();
//  organizationId is the numeric ID of the organization.
/*
 * TODO(developer): Uncomment the following lines
 */
// const organizaionId = "111122222444";
const orgName = client.organizationPath(organizationId);
// Call the API with automatic pagination.
async function listSources() {
  const [response] = await client.listSources({parent: orgName});
  let count = 0;
  console.log('Sources:');
  Array.from(response).forEach(source =>
    console.log('%d %j', ++count, source)
  );
}

listSources();

IAM 정책 가져오기

Security Command Center에서 현재 IAM 정책 데이터를 가져와 소스에 적절한 IAM 정책이 적용되었는지 확인할 수 있습니다.

Python

from google.cloud import securitycenter

client = securitycenter.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"
# Get the old policy so we can do an incremental update.
policy = client.get_iam_policy(source_name)
print("Policy: {}".format(policy))

자바

static Policy getIamPolicySource(SourceName sourceName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to get IAM policy for a source.
    // SourceName sourceName = SourceName.of(/*organization=*/"123234324",/*source=*/
    // "423432321");
    GetIamPolicyRequest request =
        GetIamPolicyRequest.newBuilder().setResource(sourceName.toString()).build();

    // Call the API.
    Policy response = client.getIamPolicy(request);

    System.out.println("Policy: " + response);
    return response;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	iam "google.golang.org/genproto/googleapis/iam/v1"
)

// getSourceIamPolicy prints the policy for sourceName to w and return it.
// sourceName is the full resource name of the source with the policy of interest.
func getSourceIamPolicy(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: %v", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &iam.GetIamPolicyRequest{
		Resource: sourceName,
	}

	policy, err := client.GetIamPolicy(ctx, req)
	if err != nil {
		return fmt.Errorf("GetIamPolicy(%s): %v", sourceName, err)
	}

	fmt.Fprintf(w, "Policy: %v", policy)
	return nil
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center');

// Creates a new client.
const client = new SecurityCenterClient();

async function getSourceIamPolicy() {
  // sourceName is the full resource name to retrieve the policy for.
  /*
   * TODO(developer): Uncomment the following lines
   */
  // const sourceName = "organizations/111122222444/sources/1234";

  const [existingPolicy] = await client.getIamPolicy({
    resource: sourceName,
  });

  console.log('Current policy: %j', existingPolicy);
}
getSourceIamPolicy();