Chapter 16

Security Command Center

Scope. This chapter covers Security Command Center as the organization's finding plane: how it is activated, what produces findings, how findings are classified and prioritized, and how they leave the product. It owns the SCC side of SIEM integration — the export mechanism and the payload. What a SIEM does with the stream is §17.17; Cloud Monitoring alerting mechanics are §18.4 and §18.15; incident response procedure is Chapter 34. Prerequisites. Chapter 2 (§2.21 security projects, §2.30 organization policy), Chapter 3 (§3.9 roles, §3.14 resource-level IAM), Chapter 15 (Sensitive Data Protection). Verified against. Google Cloud console and API surface as of 2026-09, Cloud SDK 583.0.0, hashicorp/google provider 8.x; see sources at end.

Every other chapter in this book adds a control. This one adds the thing that tells you whether the controls are actually on. Security Command Center is the organization-scoped store where every Google-run detector writes what it saw — a public bucket, a leaked service account key in use, a cryptominer in a VM's memory — into one schema, addressable by one API, exportable by one mechanism.

That framing matters more than the feature list, because SCC is very easy to activate and then ignore. A default Premium activation produces thousands of findings across a real estate within a day, most of them true and almost none of them urgent. The product's value is not detection; the detectors are good and you did not have to write them. The value is the plumbing you build around them: a mute policy that suppresses what you have consciously accepted, a resource-value configuration that tells the risk engine which projects actually matter, an export that lands in the same place your logs land, and an alerting path that pages a human for exactly the finding classes that deserve it.

The two structural decisions come first and are hard to change later. SCC activates at the organization, so the activation, its service enablement, and its export configuration are organization-level Terraform owned by the platform team, not project-level configuration a workload team can drift. And the export destination is a decision about your whole security operations pipeline, because it determines whether findings are correlated with audit logs (Chapter 17) or live in a second console nobody opens.

16.1 Security Command Center Architecture §

Security Command Center is an organization-scoped service that normalizes the output of many detectors into a single resource — the finding — and provides one API, one console, and one export path over all of them.

Four resource types carry the whole model. Everything you configure in SCC is one of these:

ResourceWhat it isScope it lives at
SourceA producer of findings — a built-in service, or one you register for a third-party toolOrganization
FindingOne observation about one resource, with a class, severity, and stateUnder a source
Mute configA filter that suppresses matching findings from the default viewOrg, folder, or project
Notification config / BigQuery exportA filter plus a destination that streams findings outOrg, folder, or project

Activation is at the organization and the tier gates the detectors. Google documents three tiers, plus a legacy variant of the entry tier:

TierWhat Google says it supports
Standard-legacy"Supports basic security and compliance posture management for Google Cloud only."
Standard"Supports basic security and compliance posture management for Google Cloud only."
Premium"Everything in Standard, plus advanced security and compliance posture management, attack paths, threat detection, and compliance monitoring for Google Cloud only."
Enterprise"(Deprecated) Complete multi-cloud CNAPP security…"

Do not build on the Enterprise tier. Google states plainly: "The Security Command Center Enterprise service tier will shut down on May 21, 2027." If an estate is on Enterprise today, the multi-cloud and case-management capabilities it provides need a replacement plan, not a renewal.

Console. Console → Security → Security Command Center, at console.cloud.google.com/security/command-center. The Overview, Findings, Risk Overview, Compliance, and Posture pages each correspond to an API surface described in the rest of this chapter.

The IAM split this book uses. roles/securitycenter.admin on the organization for the platform team that owns activation and exports; roles/securitycenter.findingsViewer plus roles/securitycenter.assetsViewer for engineers who triage; roles/securitycenter.findingsMuteSetter for the small group allowed to suppress. Never grant a workload service account anything in the securitycenter namespace — findings are read by pipelines, not by applications.

Pitfall. Premium and Enterprise are billed on assets under protection across the whole organization, so a single sandbox folder full of short-lived projects can dominate the bill without producing a finding anyone acts on. Decide the activation scope deliberately; SCC's per-service enablement (§16.6) is the lever, not deleting projects.

16.2 Asset Inventory §

An asset in Security Command Center is a Google Cloud resource that SCC knows about and can attach findings and security marks to. It is not a separate inventory system — it is a view over the resources SCC discovers when it is activated.

SCC's own asset commands are largely deprecated. On SDK 583.0.0 the gcloud scc assets group marks describe, get-parent, get-project, group, list, list-marks, and run-discovery as deprecated; only update-marks remains current. The inventory surface you should build automation on is Cloud Asset Inventory, which §29.6 owns for compliance evidence.

Security marks are the part worth keeping. A mark is a key/value label that SCC — and only SCC — understands, and it is writable independently of the resource's own IAM:

gcloud scc findings update-marks FINDING_ID \
  --organization=123456789012 \
  --source=SOURCE_ID \
  --security-marks=owner_team=platform,accepted_risk=false

Marks are useful precisely because they are not resource labels. A project label (§2.12) is editable by whoever administers the project; a security mark is editable only by a principal holding roles/securitycenter.findingSecurityMarksWriter or roles/securitycenter.assetSecurityMarksWriter. That separation lets a security team annotate a resource — "this bucket is a deliberate public artifact mirror" — without the resource owner being able to erase the annotation.

Judgment. Use marks for triage state that must survive a resource owner's edits, and use labels for everything else. Mark taxonomies grow unmanageable fast: three keys is a working set, ten is a project nobody maintains.

Pitfall. Marks are attached to the SCC asset and finding, not to the underlying resource. Delete and recreate the resource and the marks are gone, which makes them useless as a permanent exemption mechanism. Permanent exemptions belong in a mute config (§16.3) whose filter matches on resource name pattern, not on a mark.

16.3 Findings §

A finding is one observation, by one source, about one resource, at one point in time. It carries a category (the detector's own name for what it found), a class, a severity, a state, and a mute state.

Google groups findings into classes, and the class is the field to route on because it says what kind of work the finding implies:

ClassGoogle's definition
Vulnerability"identify a flaw or weakness in software programs that an attacker could use"
Misconfiguration"identify vulnerabilities caused by the incorrect or suboptimal configuration of programs, assets, or other resources"
Threat"identify a potential active attack or other unwanted or malicious activity"
Secret"identify potential security risks caused by plaintext credentials, keys, access tokens, or certificates"
Toxic combination"identify a group of security issues that, when they occur together, create a path"
Chokepoint"identify a resource or resource group where high-risk attack paths converge"
External exposure"identify external-facing IP addresses, hostnames, domain names, URLs, and exposed services"
Posture violation"describe resource configurations that don't align with your organization's security posture or a Compliance Manager cloud control"
Observation"describe an event, configuration detail, or other issue in your environment that might not be a problem in itself"
SCC error"identify a problem in the configuration of Security Command Center or one of its services"

Severity is CRITICAL, HIGH, MEDIUM, or LOW, assigned by the detector; custom modules (§16.5) set it explicitly.

A Threat finding and a Misconfiguration finding are different products with the same schema. A threat says something is happening now and belongs on a pager (§18.17). A misconfiguration says something has been wrong for an unknown length of time and belongs in a backlog. Routing them to the same channel is the single most common reason a team stops reading SCC.

Query findings with the filter language, which supports =, >, <, >=, <=, and : for substring, combined with AND, OR, and - for negation:

gcloud scc findings list --organization=123456789012 \
  --source=- \
  --filter="state=\"ACTIVE\" AND severity=\"CRITICAL\"" \
  --field-mask="finding.category,finding.resourceName,finding.severity"

Muting is the accepted-risk mechanism, and it does not delete anything. A muted finding still exists and is still exported; it is filtered out of the default console view. Mute one finding, or mute a class of them:

gcloud scc findings set-mute FINDING_ID \
  --organization=123456789012 --source=SOURCE_ID --mute=MUTED

gcloud scc muteconfigs create mute-sandbox-public-buckets \
  --organization=123456789012 \
  --description="Sandbox project hosts deliberate public sample data." \
  --type=static \
  --filter="category=\"PUBLIC_BUCKET_ACL\" AND resource.project_display_name=\"rc-saas-sbx-app-01\""

Pitfall. A static mute config with no --expiry-time is permanent and silent. Use --type=dynamic with --expiry-time for anything that is a temporary acceptance, so the finding reappears rather than being quietly buried by an engineer who has since left.

16.4 Vulnerability Detection §

Vulnerability findings in SCC identify a known flaw in software you are running, as distinct from a configuration you chose badly (§16.5).

Two production sources feed this class. Artifact Registry Vulnerability Assessment "Alerts you to vulnerabilities in your deployed container images", available from the Standard tier upward; and OS-level vulnerability findings from VM Manager's OS inventory, which §8.29 covers on the Compute Engine side.

The container path is the one that matters for a container estate, and it is a pipeline, not a scan button: Artifact Analysis scans an image on push and continuously re-evaluates it against new CVE data (§24.6), and SCC surfaces the result as a finding attached to the running workload rather than to the image. That attachment is what makes it actionable — a CVE in an image nobody deploys is noise, and SCC's version tells you which cluster and which namespace.

Finding sourceWhat it coversWhere the detail lives
Artifact Registry Vulnerability AssessmentCVEs in container images you deploy§24.6
VM Manager OS inventoryPackages installed on Compute Engine VMs§8.29
Web Security ScannerReachable web application vulnerabilitiesConsole-driven scan configuration

Judgment. Do not treat the SCC vulnerability count as a work queue. Rank by attack exposure score (§16.10) first, because a HIGH CVE on an internal batch worker behind a perimeter is not the same problem as a MEDIUM one on an internet-facing load balancer backend.

Pitfall. Scanning coverage follows the registry, not the cluster. An image pulled from a public upstream directly onto a node is invisible to Artifact Registry Vulnerability Assessment; the remote-repository pattern in §24.1 is what brings it into scope.

16.5 Misconfiguration Detection §

Security Health Analytics is the detector that "Provides managed scans of your cloud resources to detect common misconfigurations". It runs from the Standard tier upward and produces the bulk of a new activation's findings.

Its findings restate controls this book configures elsewhere — public buckets (§11.9), overly broad firewall rules (§5.13), service account keys in existence (§4.9), disabled audit logs (§17.3). That overlap is the point: SHA is the independent check that the control you wrote in Terraform is actually in effect on the resource.

Custom modules extend it with your own rules, written as a CEL predicate over a resource type, with the severity and remediation text you choose:

gcloud scc manage custom-modules sha create \
  --organization=organizations/123456789012 \
  --display-name="rc_saas_bucket_requires_cmek" \
  --enablement-state="ENABLED" \
  --custom-config-from-file=module.yaml

The same object is manageable as code, which is how this book expects it to be maintained:

resource "google_scc_project_custom_module" "bucket_requires_cmek" {
  project          = "rc-saas-shared-sec-01"
  display_name     = "rc_saas_bucket_requires_cmek"
  enablement_state = "ENABLED"

  custom_config {
    severity    = "HIGH"
    description = "Buckets holding customer data must use a CMEK from kr-us-central1-data."
    recommendation = join(" ", [
      "Recreate the bucket with encryption.default_kms_key_name set to the",
      "regional key named in 14.8, then migrate objects.",
    ])

    resource_selector {
      resource_types = ["storage.googleapis.com/Bucket"]
    }

    predicate {
      expression = "!has(resource.encryption.defaultKmsKeyName)"
    }
  }
}

Judgment. Write a custom module only for a rule that is specific to your estate and cheap to evaluate from resource configuration. Anything requiring correlation across resources is an attack-path or toxic-combination question (§16.10), and anything requiring log history is a log-based metric (§18.15).

Pitfall. Custom modules exist at both the organization/folder level (gcloud scc manage custom-modules sha) and the project level (gcloud scc custom-modules sha, and the Terraform resource above). A module created at the project level does not apply to sibling projects, which is almost never what an author intends. Create estate-wide rules at the organization.

16.6 Threat Detection §

Threat findings assert that something is happening, not that something is configured badly, and they come from three built-in services with three completely different sensors.

ServiceSensorWhat it sees
Event Threat DetectionThe Cloud Logging streamControl-plane and identity abuse
Container Threat DetectionA DaemonSet plus guest-kernel instrumentationProcess and script behavior inside containers
VM Threat DetectionThe hypervisor, agentlessGuest memory and persistent-disk contents

All three are Premium-tier services, and all three are enabled or disabled per service through one command group:

gcloud scc manage services list --organization=organizations/123456789012

gcloud scc manage services update container-threat-detection \
  --organization=organizations/123456789012 \
  --enablement-state=ENABLED

Enablement is inheritable and overridable, since the same command takes --folder, --project, or a generic --parent. That is the mechanism for the cost problem in §16.1: enable the expensive runtime detectors on production folders and leave them off in a sandbox, rather than turning them off everywhere.

Judgment. These three services are the strongest argument for Premium. Security Health Analytics tells you what an auditor would have told you; Event Threat Detection tells you a leaked key is being used right now. If the budget only stretches to one thing, buy the threat detectors and script the misconfiguration checks yourself.

Pitfall. --validate-only on gcloud scc manage services update checks the request without applying it. Use it in a pipeline before applying an enablement change across a folder, because disabling a detector produces no finding and no alert — the absence of threat findings looks identical to safety.

16.7 Event Threat Detection §

Event Threat Detection is, in Google's words, "a built-in service for the Security Command Center Premium tier that continuously monitors your organization or projects and identifies threats within your systems in near-real time."

Its sensor is your log stream, specifically the Cloud Logging stream for the organization or project, and it can additionally monitor Google Workspace logs. It reads the same audit logs Chapter 17 routes; it does not require you to export anything to it.

Its detectors are named in MITRE ATT&CK tactic order, which makes routing straightforward. Google's published examples include:

  • Initial Access: Leaked Service Account Key Used — authentication with a key that has been found publicly exposed
  • Persistence: IAM Anomalous Grant — a suspicious privilege grant to a user or service account
  • Privilege Escalation: External Member Added To Privileged Group — an external identity joining a sensitive group
  • Defense Evasion: Modify VPC Service Control — a change that reduces the protection of a perimeter (Chapter 20)
  • Discovery: Service Account Self-Investigation — a service account enumerating its own permissions
  • Exfiltration: BigQuery Data Exfiltration — BigQuery resources moved outside the organization
  • Brute force SSH — successful SSH access obtained by brute force
  • Active Scan: Log4j Vulnerable to RCE — scanner activity detected through DNS queries

Two of those detectors depend on logs you must turn on. Data Access logs are disabled by default (§17.3), and detectors that reason about data reads — the BigQuery exfiltration rule among them — see nothing without them. This is the most common reason Event Threat Detection appears quiet in a new activation.

Judgment. The Persistence: IAM Anomalous Grant and Initial Access: Leaked Service Account Key Used detectors are the two that justify a pager route on their own. Both indicate an identity compromise in progress, and both are cheap to act on: revoke the grant, disable the key (§4.9).

Pitfall. Event Threat Detection findings name the principal and the resource but do not stop anything. The containment step is yours, and §34.5 owns the credential revocation runbook.

16.8 Container Threat Detection §

Container Threat Detection "continuously monitors the state of Container-Optimized OS node images", watching what processes inside containers actually do rather than what the image contains.

The instrumentation is a user-mode DaemonSet fed by guest-kernel collection, which sends low-level behavior and executed scripts to a detector service outside the cluster. There is nothing to install per workload; the requirement is on the node image.

Its detectors describe container-specific escape and execution behavior. Google names, among many: Added Binary Executed (a binary not present in the original image ran), Reverse Shell (a process redirecting its streams to a remote socket), Unexpected Child Shell, Container Escape, Malicious Python Executed, Suspicious Crypto Mining, and Base64 Encoded Shell Script Executed.

Added Binary Executed is the detector that pays for the service, because it is the direct runtime observation of the thing immutable infrastructure (§1.15) is supposed to prevent. A container that downloads and runs a binary at runtime has either a live intruder or a deployment practice that must stop.

The prerequisite is a node image choice, and it is one this book already made. §9.5 selects Container-Optimized OS for node pools; Ubuntu node images do not get this service. If a cluster runs a different node image for a driver or kernel-module reason, record it as an accepted detection gap rather than assuming coverage.

Pitfall. Detection is per node image, but enablement is per parent resource. A single Ubuntu node pool inside an otherwise Container-Optimized OS cluster is an unmonitored island, and nothing in the SCC console tells you the gap exists.

16.9 VM Threat Detection §

VM Threat Detection "scans virtual machines to detect potentially malicious applications, such as cryptocurrency mining software, kernel-mode rootkits, and malware running in compromised cloud environments."

It is agentless and reads from below the guest. Memory scanning works "from the hypervisor into the memory of a running guest VM without pausing operation of the guest", and disk scanning uses "short-lived clones of your VM's persistent disk, without disrupting your workloads". Google states it requires "no guest agents or special configuration of the guest operating system" — which also means an intruder inside the guest cannot disable it.

The scan cadence is published and bounds your detection latency:

ScanCadence Google documents
Memory"immediately after the instance is created", then "every 30 minutes"
Persistent disk"at least daily"
Cryptomining findings"one finding per process, per VM, per day"
Kernel-mode rootkit findings"one finding per category, per VM, every three days"

Three configurations are not covered, and two of them are configurations this book otherwise recommends: Confidential VMs, whose memory encryption is precisely what prevents hypervisor introspection; Arm-based processors; and disks encrypted with customer-supplied or customer-managed keys.

That conflict is real and you must choose per workload. A Confidential VM (Chapter 36) protects data in use from the platform; VM Threat Detection protects you from an intruder in the guest. You cannot have both on the same instance, so decide by threat model: confidential computing for workloads whose data must be opaque to the operator, VM Threat Detection for general fleet defense.

Pitfall. CMEK on a boot disk (§14.8) silently removes disk scanning coverage. Estates that mandate CMEK everywhere lose this detector for every VM without any finding announcing the loss.

16.10 Attack Paths §

An attack path is, in Google's definition, "an interactive, visual depiction of one or more potential paths that a hypothetical attacker could take to get from the public internet to one of your high-value resource instances."

The Risk Engine produces them, and Google restricts the capability by tier: "To use attack exposure scores and attack paths, you must activate the Security Command Center Premium or Enterprise tier at the organization level." Project-level activation does not produce attack paths, because the reachability graph spans projects by definition.

The score is a number attached to the path's endpoint. "An attack exposure score is a measure of how exposed resources are to potential attack if a malicious actor were to gain access to your Google Cloud environment." The range is bounded for resources and unbounded for findings: "For resources, attack exposure scores can be in the range from 0 to 10. For findings, scores don't have a fixed upper limit."

Two related finding classes come out of the same engine. A Toxic combination finding identifies "a group of security issues that, when they occur together, create a path"; a Chokepoint finding identifies "a resource or resource group where high-risk attack paths converge". The chokepoint is the more useful of the two operationally, because fixing one chokepoint closes many paths.

Judgment. Attack paths are the only SCC output that answers "which of these four thousand findings do I fix first" with a defensible argument rather than a severity label. Make the chokepoint list the standing agenda item of a monthly security review, and leave the raw finding count alone.

Pitfall. Attack path quality is entirely determined by whether you told SCC what is valuable (§16.11). With no resource value configuration, the engine falls back to its own guesses and produces paths to resources nobody cares about — which is how the feature acquires a reputation for being noise.

16.11 Risk Prioritization §

Risk prioritization in SCC means declaring which resources matter, so the Risk Engine can rank findings by consequence rather than by severity label.

The declaration is a resource value configuration, defining what Google calls a high-value resource set — "a defined collection of the resources in your Google Cloud environment that are the most important to secure and protect". Configurations are managed at the organization by principals holding roles/securitycenter.resourceValueConfigsEditor, and read with roles/securitycenter.resourceValueConfigsViewer.

Express value by tag, not by resource name. This book's estate already labels every project with env and data-class (§2.12), and a value configuration that selects on those labels stays correct as projects are created and destroyed. A configuration enumerating bucket names is stale the week after it is written.

Signal in this estateHigh-value set it should drive
env=prod on the projectBaseline production value
data-class=restricted (§15.2)Highest value; drives the top of the attack-path list
Membership of the perimeter in §20.11Value consistent with the data perimeter's own scope

The consuming views are Risk Overview and the attackExposure field on findings, plus the roles/securitycenter.riskReportsViewer and roles/securitycenter.valuedResourcesViewer roles for read-only access to them. Both are Premium.

Judgment. Configure at most three value tiers. Every additional tier is a distinction that has to be maintained forever and that nobody will use when triaging at two in the morning.

Pitfall. Marking everything high value is identical to marking nothing high value, and it is the default failure mode when the configuration is written by a team that does not want to be blamed for omitting something. Write it with the business owner, and put the "not valuable" list in writing too.

16.12 Security Posture Management §

The Security Posture Service "Lets you define, assess, and monitor the overall status of your security in Google Cloud" — a declarative bundle of policies applied to a scope, which then reports drift as Posture violation findings.

Three resources make up the model, and each has a gcloud surface:

ResourceCommand groupWhat it holds
Posturegcloud scc posturesA versioned set of policies, defined in YAML
Posture templategcloud scc posture-templatesA Google-authored starting posture you copy
Posture deploymentgcloud scc posture-deploymentsA binding of one posture revision to one target
gcloud scc postures create rc-saas-prod-baseline \
  --organization=123456789012 \
  --location=global \
  --posture-from-file=posture-prod-baseline.yaml

gcloud scc posture-deployments create deploy-prod-baseline \
  --organization=123456789012 \
  --location=global \
  --posture-name=organizations/123456789012/locations/global/postures/rc-saas-prod-baseline \
  --posture-revision-id=REVISION_ID \
  --target-resource=folders/FOLDER_ID \
  --description="Production folder security baseline."

A posture is versioned and a deployment pins a revision, which is the useful property: changing the posture does not silently change what is enforced until you deploy the new revision. That is the same discipline §26.x applies to Terraform modules, and it makes posture changes reviewable.

Where postures fit against organization policy. Organization policy (§2.30) prevents; a posture observes and reports. They overlap deliberately — a posture that asserts the same constraint an organization policy enforces is a control test, and a Posture violation finding on it means the policy was overridden or an exception was granted.

Pitfall. A posture deployed to a folder does not retroactively assess resources that predate it in any different way than new ones, but it also does not block anything. Teams read "posture" as "enforcement" and discover months later that a posture violation is a report. If you need prevention, write the organization policy as well.

16.13 Compliance Monitoring §

SCC maps findings to control frameworks so that a misconfiguration finding can be read as a failed control rather than as an isolated defect. Compliance Manager "Creates findings for the detective and preventive cloud controls that you deploy", and the compliance views are read with roles/securitycenter.complianceReportsViewer and roles/securitycenter.complianceSnapshotsViewer.

Two different things are both called compliance in the console. Distinguishing them prevents a great deal of confused reporting:

  • Framework mapping on findings — each Security Health Analytics detector is annotated with the framework controls it relates to, so a filtered finding list becomes a control-failure list.
  • Compliance Manager cloud controls — a declared control that produces its own findings, including preventive controls, and reports on their state.

The framework list is not stable enough to print. Google's release notes name ISO 27001 and PCI DSS among the supported frameworks, and the set expands. Read the current list from the console's Compliance page rather than from any document, including this one. Chapter 30 covers what each framework demands; §29.2 covers turning these views into evidence an auditor accepts.

Judgment. SCC's compliance view is a gap-finder, not an attestation. It reports on the controls Google's detectors can observe in Google Cloud, which is a subset of any real framework's scope — nothing in it speaks to your change management, your personnel controls, or anything outside GCP. Treat a clean compliance page as necessary and nowhere near sufficient.

Pitfall. Muting a finding (§16.3) removes it from compliance reporting as well as from the findings list. A mute config written to reduce console noise can silently produce a passing control report, which is the kind of defect that surfaces during an audit rather than before one.

16.14 Findings Export §

Findings leave Security Command Center by exactly two mechanisms, and every downstream integration is built on one of them.

MechanismDestinationShapeUse it for
Notification configA Pub/Sub topicOne message per finding create/updateReal-time routing, automation, SIEM
BigQuery exportA BigQuery datasetStreaming rowsAnalysis, reporting, long-term retention

Both take a filter, and the filter is the whole design. An unfiltered export streams every finding update in the organization, including the thousands of low-severity misconfiguration findings that update whenever a resource is touched. Filter at the export, not at the consumer, because you pay for what you move.

gcloud scc notifications create scc-threats-critical \
  --organization=123456789012 \
  --pubsub-topic=projects/rc-saas-shared-sec-01/topics/scc-findings \
  --description="Active threat-class findings, high and critical." \
  --filter="state=\"ACTIVE\" AND (severity=\"HIGH\" OR severity=\"CRITICAL\")"

gcloud scc bqexports create scc-all-findings \
  --organization=123456789012 \
  --dataset=projects/rc-saas-shared-sec-01/datasets/scc_findings \
  --description="All active findings for analysis and retention." \
  --filter="state=\"ACTIVE\""

Both destinations live in the security project rc-saas-shared-sec-01 (§2.21), not in a workload project, and both are created as code:

resource "google_scc_notification_config" "threats" {
  config_id    = "scc-threats-critical"
  organization = "123456789012"
  description  = "Active threat-class findings, high and critical."
  pubsub_topic = google_pubsub_topic.scc_findings.id

  streaming_config {
    filter = "state=\"ACTIVE\" AND (severity=\"HIGH\" OR severity=\"CRITICAL\")"
  }
}

resource "google_scc_organization_scc_big_query_export" "all_findings" {
  big_query_export_id = "scc-all-findings"
  organization        = "123456789012"
  dataset             = google_bigquery_dataset.scc_findings.id
  description         = "All active findings for analysis and retention."
  filter              = "state=\"ACTIVE\""
}

The v2 API adds a location for data residency, defaulting to global; the gcloud commands take --location and the google_scc_v2_* Terraform resources expose it. Use the v2 resources only if you have a residency requirement that names a location, because the v1 resources are simpler and equally current for a global deployment.

Pitfall. A notification config publishes on create and update. A finding whose state flips as a resource is reconfigured produces repeated messages for the same underlying problem, so any automation on the topic must be idempotent and keyed on the finding name (§16.16).

16.15 SIEM Integration §

This section owns the producer half of SIEM integration: what Security Command Center puts on the wire and how you shape it. What a SIEM does with the stream — connectors, ingestion, correlation with logs, and cost — is §17.17.

The contract is a Pub/Sub topic carrying one message per finding event. Every SIEM integration, first-party or third-party, subscribes to a topic fed by a notification config (§16.14). There is no separate SIEM API and no push connector inside SCC.

Shape the stream at the notification config, in three decisions:

  1. Which findings. A SIEM is for things an analyst investigates. Export the Threat, Secret, and Toxic combination classes and the high-severity end of everything else; leave the long tail of misconfiguration findings in the BigQuery export where they belong.
  2. How many topics. One topic per routing destination, not one topic for everything with filtering at the subscriber. Separate topics let you give the SIEM connector's principal roles/pubsub.subscriber on exactly the stream it should see.
  3. Which parent. An organization-scoped config sees the whole estate. Folder- and project-scoped configs exist for delegating a stream to a business unit without exposing the rest.

The publishing identity is a Google-managed service agent, addressed as service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com. Google states it "is created when you create your first NotificationConfig and is automatically granted the securitycenter.notificationServiceAgent role on the IAM policy for PUBSUB_TOPIC when creating the notification config." So the grant is made for you — but verify it, because a topic whose IAM is subsequently managed by Terraform with an authoritative policy resource will have it removed, and the stream then goes silent with no error:

gcloud pubsub topics get-iam-policy scc-findings \
  --project=rc-saas-shared-sec-01 --format="yaml(bindings)"

Consumers authenticate with Workload Identity Federation, never with a key. A SIEM running outside Google Cloud federates its own identity into a service account holding only roles/pubsub.subscriber on the one subscription (§4.13). A downloaded service account key for a SIEM connector is a long-lived credential to your entire finding stream.

Pitfall. Pub/Sub retains undelivered messages for a bounded period — seven days by default. A SIEM connector that breaks over a holiday weekend loses findings permanently unless the BigQuery export (§16.14) is also running as the durable copy. Run both; they cost different things and fail differently.

16.16 Automated Remediation §

Automated remediation means subscribing to the finding stream and having code change the resource — closing a public bucket, disabling a key, quarantining an instance — without a human in the loop.

The shape is always the same: notification config → Pub/Sub topic → a Cloud Run service or Cloud Run function in the security project, running as a dedicated service account with narrowly scoped cross-project permissions.

Four properties separate a remediation that helps from one that causes an incident:

  • Idempotent. Findings update and republish (§16.14), so the handler must key on the finding name and tolerate acting twice.
  • Narrowly permissioned. The remediation service account holds one role, granted at the resource or folder level — roles/storage.admin on a folder to close bucket ACLs, not organization-wide administrative rights.
  • Reversible and logged. Every action writes what it did and what the prior state was, into the same log sink as everything else (§17.9), so the change is visible in the audit trail as an automated actor rather than an anonymous one.
  • Scoped by environment. Automate in production only after the same handler has run for weeks in dry-run mode across non-production, reporting what it would have done.

Automate revocation, not repair. Disabling a leaked key, removing an allUsers binding, or deleting a firewall rule that opens SSH to the internet are safe because the failure mode is an outage you can diagnose. Anything that mutates data, resizes infrastructure, or deletes a resource belongs behind a human approval, and Chapter 34 owns that runbook.

Judgment. The highest-value automation in most estates is not remediation at all — it is enrichment: a handler that takes a finding, looks up the owning team from the project's labels (§2.12), and opens a ticket in the right queue with the resource, the severity, and the attack exposure score already attached.

Pitfall. A remediation handler subscribed to an unfiltered topic will eventually receive a finding class it was never designed for and take an action nobody predicted. Filter at the notification config, and have the handler assert the finding category matches its own allowlist before acting.

Chapter Summary §

  • Security Command Center normalizes every Google detector's output into one resource, the finding, with one API and one export path.
  • Activation is at the organization; the tier determines which detectors run, and the Enterprise tier is deprecated with a stated shutdown date of 2027-05-21.
  • Findings carry a class, and the class — not the severity — is the correct routing key: Threat pages a human, Misconfiguration fills a backlog.
  • Muting suppresses a finding from the default view without deleting or un-exporting it, and it also removes the finding from compliance reporting.
  • Security Health Analytics is the misconfiguration detector, extensible with CEL-predicate custom modules created at the organization rather than the project.
  • The three threat detectors use three unrelated sensors: logs for Event Threat Detection, a node DaemonSet for Container Threat Detection, and the hypervisor for VM Threat Detection.
  • Container Threat Detection requires Container-Optimized OS node images; VM Threat Detection does not work on Confidential VMs, Arm processors, or CMEK-encrypted disks.
  • Data Access logs are off by default, and several Event Threat Detection detectors see nothing until they are enabled.
  • Attack paths and attack exposure scores require Premium at the organization and are only as good as the resource value configuration behind them.
  • Postures observe and report; organization policy prevents. Needing both is the normal case.
  • Exports are Pub/Sub notification configs and BigQuery exports; filter at the export, run both, and put both destinations in the security project.
  • The notification service agent is granted on the topic automatically when the first notification config is created; an authoritative Terraform IAM policy on that topic silently removes it.
  • SIEM connectors federate with Workload Identity Federation; a downloaded key for a connector is a long-lived credential to the whole finding stream.
  • Automate revocation, not repair, and make every handler idempotent, narrowly permissioned, and logged.

Security Checklist §

ControlWhy it mattersHow to verify (CLI + Console)
SCC activated at the organizationProject-scoped activation produces no attack paths and no cross-project correlationgcloud scc manage services list --organization=organizations/ORG_ID; Security Command Center → Settings
Threat detectors enabled on productionMisconfiguration scanning without threat detection sees nothing happening nowgcloud scc manage services describe event-threat-detection --organization=organizations/ORG_ID
Data Access logs enabledSeveral Event Threat Detection detectors depend on them (§17.3)gcloud projects get-iam-policy PROJECT_ID --format="yaml(auditConfigs)"
Notification config exists and is filteredAn unfiltered stream is unusable and expensive; no stream means no alertinggcloud scc notifications list --organization=ORG_ID
Notification service agent binding still present on the topicIt is granted automatically, and an authoritative Terraform IAM policy removes itgcloud pubsub topics get-iam-policy TOPIC --project=rc-saas-shared-sec-01
BigQuery export running alongside Pub/SubPub/Sub retention is bounded; the export is the durable copygcloud scc bqexports list --organization=ORG_ID
Mute configs are time-boundedA permanent static mute hides both the finding and the failed controlgcloud scc muteconfigs list --organization=ORG_ID
Resource value configuration writtenWithout it, attack exposure scores rank the wrong things firstSecurity Command Center → Risk Overview → Resource value configurations
No workload service account holds an SCC roleFindings are read by pipelines, not applicationsgcloud organizations get-iam-policy ORG_ID --flatten="bindings[].members"
Detection gaps recordedNon-COS node pools, Confidential VMs, and CMEK disks are uncovered by designCompare node image and disk encryption inventory against §16.8 and §16.9

Sources §