diff --git a/fast/stages/0-org-setup/README.md b/fast/stages/0-org-setup/README.md index ef0b6cc21..13607dc66 100644 --- a/fast/stages/0-org-setup/README.md +++ b/fast/stages/0-org-setup/README.md @@ -13,6 +13,7 @@ - [Provider setup and final apply cycle](#provider-setup-and-final-apply-cycle) - [Default factory datasets](#default-factory-datasets) - ["Classic FAST" dataset](#classic-fast-dataset) + - ["Hardened" dataset](#hardened-dataset) - ["Minimal" dataset (TBD)](#minimal-dataset-tbd) - ["Tenants" dataset (TBD)](#tenants-dataset-tbd) - [Detailed configuration](#detailed-configuration) @@ -77,12 +78,12 @@ If this configuration matches requirements, no changes are necessary at this sta # create a file named 0-org-setup.auto.tfvars containing the following # and replace paths by pointing them to the desired data folder factories_config = { - billing_accounts = "data/billing-accounts" - cicd = "data/cicd.yaml" - defaults = "data/defaults.yaml" - folders = "data/folders" - organization = "data/organization" - projects = "data/projects" + billing_accounts = "datasets/classic/billing-accounts" + cicd = "datasets/classic/cicd.yaml" + defaults = "datasets/classic/defaults.yaml" + folders = "datasets/classic/folders" + organization = "datasets/classic/organization" + projects = "datasets/classic/projects" } ``` @@ -253,6 +254,12 @@ The organizational layout mirrors the consolidated FAST one, where shared infras Classic FAST organization-level diagram.

+### "Hardened" dataset + +This dataset implements a hardened design focusing on strict security and compliance requirements. It expands on the "Classic FAST" layout by incorporating more advanced and granular preventive and detective controls from the start. + +This dataset provides a stronger and centrally-managed security baseline, ensuring that projects and resources deployed adhere to stricter security and compliance from inception. It includes both **preventive controls** (organization policies and custom constraints) and **detective controls** (monitoring alerts and Security Command Center custom module detectors). For more details on the content of this hardened dataset and the various controls provisioned, refer to the [hardened dataset documentation](./datasets/hardened/README.md). + ### "Minimal" dataset (TBD) This dataset is meant as a minimalistic starting point for organizations where a security baseline and a project factory are all that's needed, at least initially. The design can then organically grow to support more functionality, converging to the Classic or other types of layouts. @@ -293,28 +300,28 @@ The resources created by this stage are controlled by several factories, which p The default paths point to the dataset in the `data` folder which deploys a FAST-compliant configuration. These are the available factories in this stage, with file-level factories based on a single YAML file, and folder-level factories based on sets of YAML files contained within a filesystem folder: -- **defaults** (`data/defaults.yaml`) \ +- **defaults** (`datasets/classic/defaults.yaml`) \ file-level factory to define stage defaults (organization id, locations, prefix, etc.) and static context mappings -- **billing_accounts** (`data/billing-accounts`) \ +- **billing_accounts** (`datasets/classic/billing-accounts`) \ folder-level factory where each YAML file defines billing-account level IAM for one billing account; only used for externally managed accounts -- **organization** (`data/organization/.config.yaml`) \ +- **organization** (`datasets/classic/organization/.config.yaml`) \ file-level factory to define organization IAM and log sinks - - **custom roles** (`data/organization/custom-roles`) \ + - **custom roles** (`datasets/classic/organization/custom-roles`) \ folder-level factory to define organization-level custom roles - - **org policies** (`data/organization/org-policies`) \ + - **org policies** (`datasets/classic/organization/org-policies`) \ folder-level factory to define organization-level org policies - - **tags** (`data/organization/tags`) \ + - **tags** (`datasets/classic/organization/tags`) \ folder-level factory to define organization-level resource management tags -- **folders** (`data/folders`) \ +- **folders** (`datasets/classic/folders`) \ folder-level factory to define the resource management hierarchy and individual folder attributes (IAM, org policies, tag bindings, etc.); also supports defining folder-level IaC resources -- **projects** (`data/projects`) \ +- **projects** (`datasets/classic/projects`) \ folder-level factory to define projects and their attributes (projejct factory) -- **cicd** (`data/cicd.yaml`) \ +- **cicd** (`datasets/classic/cicd.yaml`) \ file-level factory to define CI/CD configurations for this and subsequent stages ### Defaults configuration -The prerequisite configuration for this stage is done via a `defaults.yaml` file, which implements part or all of the [relevant JSON schema](./schemas/defaults.schema.json). The location of the file defaults to `data/defaults.yaml` but can be easily changed via the `factories_config.defaults` variable. +The prerequisite configuration for this stage is done via a `defaults.yaml` file, which implements part or all of the [relevant JSON schema](./schemas/defaults.schema.json). The location of the file defaults to `datasets/classic/defaults.yaml` but can be easily changed via the `factories_config.defaults` variable. This is a commented example of a defaults file, showing a minimal working configuration. Refer to the YAML schema for all available options. @@ -422,7 +429,7 @@ Principal expansion leverages the `$iam_principals:` context, which is populated ```yaml # example principal-level context interpolation -# file: data/organization/.config.yaml +# file: datasets/classic/organization/.config.yaml iam_by_principals: # statically defined principal (via defaults.yaml) $iam_principals:gcp-organization-admins: @@ -445,7 +452,7 @@ Log sinks can refer to project-level destination via different contexts. ```yaml # example log sinks showing different destination contexts -# file: data/organization/.config.yaml +# file: datasets/classic/organization/.config.yaml logging: storage_location: $locations:default sinks: @@ -475,7 +482,7 @@ Context-based expansion is not limited to the organization's `.config.yaml` file ```yaml # example usage of context interpolation in tag values IAM -# file: data/organization/tags/environment.yaml +# file: datasets/classic/organization/tags/environment.yaml description: "Organization-level environments." values: development: @@ -515,7 +522,7 @@ The folder hierarchy is managed via a filesystem tree of YAML configuration file The default dataset implements a classic FAST layout, with top-level folders for stage 2 and stage 3, and can be easily tweaked by adding or removing any needed folder. ```bash -data/folders +datasets/classic/folders ├── networking │   ├── .config.yaml │   ├── dev @@ -542,7 +549,7 @@ As with the factories described above, context replacements can be used in folde As with other examples before, the main use case is to infer IAM principals from either the static or internally defined context. One additional context which is often useful here is tag values, which allows defining a scope for organization-level conditional IAM bindings or org policies. ```yaml -# file: data/folders/teams/.config.yaml +# file: datasets/classic/folders/teams/.config.yaml name: Teams iam_by_principals: $iam_principals:service_accounts/iac-0/iac-pf-rw: diff --git a/fast/stages/0-org-setup/datasets/classic/organization/.config.yaml b/fast/stages/0-org-setup/datasets/classic/organization/.config.yaml index d1bb3e90a..1677e3eee 100644 --- a/fast/stages/0-org-setup/datasets/classic/organization/.config.yaml +++ b/fast/stages/0-org-setup/datasets/classic/organization/.config.yaml @@ -14,7 +14,7 @@ # TODO: data access logs -# yaml-language-server: $schema=../../schemas/organization.schema.json +# yaml-language-server: $schema=../../../schemas/organization.schema.json id: $defaults:organization/id contacts: @@ -119,4 +119,4 @@ logging: # these are internally merged with IAM by principal iam: # reset default role on new organizations - roles/billing.creator: [] + roles/billing.creator: [] \ No newline at end of file diff --git a/fast/stages/0-org-setup/datasets/hardened/README.md b/fast/stages/0-org-setup/datasets/hardened/README.md new file mode 100644 index 000000000..9d29d6bb1 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/README.md @@ -0,0 +1,269 @@ +# Hardened Dataset for FAST Organization Setup + +This hardened dataset contains a set of compliance controls that can be applied to your Google Cloud environment. +It includes preventive controls (custom constraints and organization policies) and detective controls (Security Command Center custom module detectors and observability alerts). + +## Prerequisites + +This dataset configuration configures a set of compliance and security controls based on recommendations gathered from various customer engagements. + +The **preventive controls** are based on a recommended list of organization policies and custom organization policies. Many of these help enforce CIS Benchmarks and PCI-DSS requirements and are broadly applicable. + +The **detective controls** are based on the following: + - Security Health Analytics (SHA) and Custom SHA modules: These require **a Security Command Center (SCC) Premium or Enterprise subscription.** + - Log-based metrics and Monitoring Alerts: These can be used by any organization. + +## High level architecture + +The dataset contains the configurations for various controls, which are consumed by the Terraform modules using the factory configuration. + +| | Organization Policies | Custom Constraint | Monitoring Alerts | SCC SHA | SCC Custom SHA | +|:-----------------------------------: |:---------------------: |:-----------------------: |:------------------: |:--------------------------------------------: |:---------------------------: | +| **Type of controls** | Preventive | Preventive | Detective | Detective | Detective | +| **Factory folder** | data/org-policies | data/custom-constraints | data/observability | Already included as part of SCC Subscription | data/scc-custom-sha-modules | +| **Requires SCC Premium or Enterprise ?** | NO | NO | NO | YES | YES | + +The diagram below shows the relationships between the components: + +![image](assets/diagram.png) + +## Usage + +To use this `hardened` dataset, create a `0-org-setup.auto.tfvars` file in the `fast/stages/0-org-setup` directory and override the `factories_config` variable as shown below: + +```tfvars +factories_config = { + organization = "datasets/hardened/organization" +} +``` + +For organizations not using **SCC Premium or Enterprise**, the following error will appear: +``` +╷ +│ Error: Error creating OrganizationSecurityHealthAnalyticsCustomModule: googleapi: Error 403: Security Command Center Management API has not been used in project 111111111111 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/securitycentermanagement.googleapis.com/overview?project=111111111111 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry. +``` + +In that case, the controls placed in the `organization/scc-sha-custom-modules` folder need to be removed to ensure they are provisionned. + +## Controls + +### Preventive Controls + +#### Organization Policies +| Policy | Description | Compliance Mapping | +|---|---|---| +| `ainotebooks.disableFileDownloads` | Prevent file downloads on new Vertex AI Workbench instances. | | +| `ainotebooks.disableRootAccess` | Prevent root access on new Vertex AI Workbench user-managed notebooks and instances. | | +| `ainotebooks.restrictPublicIp` | Restrict public IP access on new Vertex AI Workbench notebooks and instances. | | +| `ainotebooks.restrictVpcNetworks` | Restrict VPC networks on new Vertex AI Workbench instances. | | +| `appengine.disableCodeDownload` | Prevent the download of source code from App Engine. | | +| `bigquery.disableBQOmniAWS` | Prevent the creation of BigQuery Omni tables for AWS. | | +| `bigquery.disableBQOmniAzure` | Prevent the creation of BigQuery Omni tables for Azure. | | +| `cloudbuild.allowedIntegrations` | Restrict Cloud Build integrations to an approved list. | | +| `cloudbuild.allowedWorkerPools` | Restrict Cloud Build jobs to an authorized list of worker pools. | | +| `cloudbuild.disableCreateDefaultServiceAccount` | Prevent Default Service Account for Cloud Build to be created | | +| `cloudfunctions.allowedVpcConnectorEgressSettings` | Ensure Cloud Functions Gen1 only allows internal and load balancer traffic. | | +| `cloudfunctions.requireVPCConnector` | Ensure Cloud Functions Gen1 are configured with a VPC connector. | | +| `compute.disableGuestAttributesAccess` | Prevent the use of Guest Attributes for Compute Engine instance metadata. | | +| `compute.disableInternetNetworkEndpointGroup` | Prevent configuration of internet network endpoint groups. | | +| `compute.disableNestedVirtualization` | Prevent the creation of Compute Engine instances with nested virtualization enabled. | | +| `compute.disableSerialPortAccess` | Prevent the enablement of serial port access for VM instances. | **CIS Controls 8.0**: 4.8
**PCI-DSS 4.0**: 1.2.1, 1.4.1
**NIST 800-53 R5**: CM-6, CM-7
**ISO-2700-1 v2022**: A.8.9
**SOC2 v2017**: CC6.6.1, CC6.6.3, CC6.6.4 | +| `compute.disableVpcExternalIpv6` | Prevent configuration of subnets with external IPv6 ranges. | | +| `compute.managed.blockPreviewFeatures` | Ensures that preview feature updates are blocked unless explicitly allowed | | +| `compute.requireOsLogin` | Enforce the use of OS Login for all Compute Engine instances. | **CIS Controls 8.0**: 5.6, 6.7
**PCI-DSS 4.0**: 1.2.5,
2.2.4
6.4.1
**NIST 800-53 R5**: AC-2
**ISO-2700-1 v2022**: A.5.15
**SOC2 v2017**: CC6.1.4, CC6.1.6, CC6.1.8, CC6.1.9 | +| `compute.requireShieldedVm` | Enforce the use of Shielded VM for all Compute Engine instances. | | +| `compute.requireSslPolicy` | Prevent the use of weak cipher suites and TLS versions on HTTPS and SSL Proxy load balancers. | **NIST 800-53 R4**: SC-7
**ISO-2700-1 v2013**: A.14.1.3 | +| `compute.restrictDedicatedInterconnectUsage` | Restrict the use of Dedicated Interconnect. | | +| `compute.restrictLoadBalancerCreationForTypes` | Restrict the creation of load balancers based on type. | | +| `compute.restrictPartnerInterconnectUsage` | Restrict the use of Partner Interconnect. | | +| `compute.restrictProtocolForwardingCreationForTypes` | Restrict the creation of forwarding rules based on type. | | +| `compute.restrictVpcPeering` | Restrict the use of VPC peering. | | +| `compute.setNewProjectDefaultToZonalDNSOnly` | Ensure project created use Zonal DNS instead of global. | | +| `compute.skipDefaultNetworkCreation` | Prevent the automatic creation of the default VPC network in new projects. | **CIS Controls 8.0**: 4.2
**NIST 800-53 R5**: AC-18, CM-2, CM-6, CM-7, CM-9
**NIST Cybersecurity Framework 1.0**: PR-IP-1
**ISO-2700-1 v2022**: A.8.9
**SOC2 v2017**: CC5.2.2
**Cloud Controls Matrix 4**: ISV-04 | +| `compute.trustedImageProjects` | Restrict the use of VM images to an authorized list of projects. | | +| `compute.vmExternalIpAccess` | Prevent Compute Engine instances from having public IP addresses. | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R4**: CA-3, SC-7
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `container.managed.disableABAC` | Require that Attribute-Based Access Control is disabled | | +| `container.managed.disableLegacyClientCertificateIssuance` | Prevent the use of legacy authentication methods for GKE API servers. | **CIS for GKE 1.5**: 2.1.1
5.8.1
**PCI-DSS 4.0**: 4.1 | +| `container.managed.enableCloudLogging` | Enforce that GKE clusters logging is enabled | **CIS for GKE 1.5**: 5.7.1
**PCI-DSS 4.0**: 10.2 | +| `container.managed.enableNetworkPolicy` | Enforce that GKE clusters are configured with Network Policy enabled | **CIS for GKE 1.5**: 5.6.7
**PCI-DSS 4.0**: 1.2,1.1,1.4
**ISO-2700-1 v2013**: A.13.1.1 | +| `container.managed.enablePrivateNodes` | Enforce that GKE clusters are created as private clusters with private nodes | **CIS for GKE 1.5**: 5.6.5
**PCI-DSS 4.0**: 1.3.1 | +| `container.managed.enableShieldedNodes` | Enforce that GKE nodes is configured with shielded GKE nodes | **CIS for GKE 1.5**: 5.5.5 | +| `container.managed.enableWorkloadIdentityFederation` | Enforce that GKE clusters are enabled with Workload Identity | **CIS for GKE 1.5**: 5.2.2
**PCI-DSS 4.0**: 7.2.2 | +| `essentialcontacts.allowedContactDomains` | Restrict essential contact domains to an authorized list. | | +| `gcp.restrictTLSCipherSuites` | Prevent the use of weak cipher suites and TLS versions on HTTPS and SSL Proxy load balancers. | **NIST 800-53 R4**: SC-7
**ISO-2700-1 v2013**: A.14.1.3 | +| `gcp.restrictTLSVersion` | Prevent the use of weak cipher suites and TLS versions on HTTPS and SSL Proxy load balancers. | **NIST 800-53 R4**: SC-7
**ISO-2700-1 v2013**: A.14.1.3 | +| `iam.allowedPolicyMemberDomains` | Restrict domain sharing to authorized domains. | **NIST 800-53 R4**: AC-3
**ISO-2700-1 v2013**: A.9.2.3 | +| `iam.automaticIamGrantsForDefaultServiceAccounts` | Prevent the automatic granting of IAM roles to default service accounts. | **PCI-DSS 4.0**: 2.2.2
2.3.1 | +| `iam.disableAuditLoggingExemption` | Prevent the use of audit logging exemptions. Detect also if audit logging are has been disabled. | | +| `iam.disableServiceAccountKeyCreation` | Enforce the use of only GCP-managed service account keys. | | +| `iam.disableServiceAccountKeyUpload` | Prevent the uploading of service account keys. | | +| `iam.managed.disableServiceAccountApiKeyCreation` | Prevent the creation of service account API key bindings. | | +| `iam.serviceAccountKeyExposureResponse` | Enforce Google to disable the service keys if a service account linked key is detected to be exposed publicly. | | +| `iam.workloadIdentityPoolAwsAccounts` | Prevent creation of workload identity pools using AWS accounts, except if expliicitely allowed. | | +| `iam.workloadIdentityPoolProviders` | Prevent creation of any workload identity pools except if expliicitely allowed. | | +| `run.allowedBinaryAuthorizationPolicies` | Restrict Cloud Run services and jobs to an authorized list of Binary Authorization policies. | | +| `run.allowedIngress` | Ensure Cloud Run services only allow internal and load balancer traffic. | | +| `run.allowedVPCEgress` | Ensure all traffic from Cloud Run services and jobs is routed through a VPC connector. | | +| `run.managed.requireInvokerIam` | Enforce an IAM invoker check for Cloud Run services. | | +| `sql.restrictAuthorizedNetworks` | Prevent the ability to add Authorized Networks for unproxied database access to Cloud SQL instances. | | +| `sql.restrictPublicIp` | Ensure That Cloud SQL Database Instances Do Not Have Public IPs | **CIS Controls 8.0**: 3.3, 4.6
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MA-4, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.2, CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `storage.publicAccessPrevention` | Prevent anonymous or public access to Cloud Storage buckets. | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R4**: AC-2
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2013**: A.14.1.3, A.8.2.3
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `storage.restrictAuthTypes` | Restrict authentication types for Cloud Storage. | | +| `storage.secureHttpTransport` | Restrict unencrypted HTTP access to Cloud Storage. | | +| `storage.uniformBucketLevelAccess` | Enforce the enablement of uniform bucket-level access to Cloud Storage buckets. | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | + +**Note:** For organizations with strict requirements to ensure all resources are created and stored within specific geographic regions (e.g., for data sovereignty or regulatory compliance), the `gcp.resourceLocations` Organization Policy present in file [gcp.yaml](organization/org-policies/gcp.yaml) can be enabled. + +#### Custom Constraints +| Constraint | Description | Compliance Mapping | +|---|---|---| +| `accesscontextmanagerDisableBridgePerimeters` | Ensure no perimeter bridges are used. Instead, use ingress and egress rules. | | +| `cloudrunDisableEnvironmentVariablePattern` | Prevent secrets from being stored in Cloud Run environment variables. | | +| `cloudsqlDisablePublicAuthorizedNetworks` | Ensure That Cloud SQL Database Instances Do Not Implicitly Whitelist All Public IP Addresses | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R4**: CA-3, SC-7
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2013**: A.13.1.3, A.14.1.3, A.8.2.3
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `cloudsqlEnforcePasswordComplexity` | Enforce password complexity for Cloud SQL instance users. | | +| `cloudsqlRequireAutomatedBackup` | Ensure That Cloud SQL Database Instances Are Configured With Automated Backups | **CIS Controls 8.0**: 11.2
**NIST 800-53 R4**: CP-9
**NIST 800-53 R5**: CP-10, CP-9
**NIST Cybersecurity Framework 1.0**: PR-IP-4
**ISO-2700-1 v2013**: A.12.3.1
**ISO-2700-1 v2022**: A.8.13
**HIPAA**: 164.308(a)(7)(ii) | +| `cloudsqlRequireMySQLDatabaseFlags` | Ensure ‘Skip_show_database’ Database Flag for Cloud SQL MySQL Instance Is Set to ‘On’ | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `cloudsqlRequirePointInTimeRecovery` | Enforce point-in-time recovery for all Cloud SQL backup configurations. | | +| `cloudsqlRequirePostgreSQLDatabaseFlags` | Ensure That the ‘Log_connections’ Database Flag for Cloud SQL PostgreSQL Instance Is Set to ‘On’ | **CIS Controls 8.0**: 8.5
**PCI-DSS 4.0**: 10.2.1, 10.2.1.2, 10.2.1.5, 9.4.5
**NIST 800-53 R5**: AU-12, AU-3, AU-7
**NIST Cybersecurity Framework 1.0**: DE-AE-3, DE-CM-1
**ISO-2700-1 v2022**: A.5.28, A.8.15
**SOC2 v2017**: CC5.2.3, CC7.2.1, CC7.2.2, CC7.2.3
**Cloud Controls Matrix 4**: DSP-17 | +| `cloudsqlRequireRootPassword` | Ensure That a MySQL Database Instance Does Not Allow Anyone To Connect With Administrative Privileges | **NIST 800-53 R4**: AC-3
**ISO-2700-1 v2013**: A.8.2.3, A.9.4.2
**ISO-2700-1 v2022**: A.8.5 | +| `cloudsqlRequireSQLServerDatabaseFlags` | Ensure 'external scripts enabled' database flag for Cloud SQL SQL Server instance is set to 'off' | **CIS Controls 8.0**: 2.7
**PCI-DSS 4.0**: 1.2.5, 2.2.4, 6.4.3
**NIST 800-53 R5**: CM-7, SI-7
**NIST Cybersecurity Framework 1.0**: PR-IP-1, PR-PT-3
**SOC2 v2017**: CC5.2.1, CC5.2.2, CC5.2.3, CC5.2.4 | +| `cloudsqlRequireSSLConnection` | Ensure That the Cloud SQL Database Instance Requires All Incoming Connections To Use SSL | **NIST 800-53 R4**: SC-7
**ISO-2700-1 v2013**: A.13.2.1, A.14.1.3, A.8.2.3 | +| `dnsAllowedSigningAlgorithms` | Prevent the use of the RSASHA1 algorithm for the Key-Signing Key in Cloud DNS DNSSEC. | **PCI-DSS 4.0**: 1.1.1, 1.2.1, 1.2.6, 1.2.7, 1.4.2, 1.5.1, 2.1.1, 2.2.1
**NIST 800-53 R4**: 4.2
**NIST 800-53 R5**: AC-18, CM-2, CM-6, CM-7, CM-9
**NIST Cybersecurity Framework 1.0**: PR-IP-1
**ISO-2700-1 v2022**: A.8.9
**SOC2 v2017**: CC5.2.2
**Cloud Controls Matrix 4**: IVS-04 | +| `dnsRequireManageZoneDNSSEC` | Enforce the enablement of DNSSEC for all Cloud DNS zones. | **CIS Controls 8.0**: 4.2
**PCI-DSS 4.0**: 1.1.1, 1.2.1, 1.2.6, 1.2.7, 1.4.2, 1.5.1, 2.1.1, 2.2.1
**NIST 800-53 R5**: AC-18, CM-2, CM-6, CM-7, CM-9
**NIST Cybersecurity Framework 1.0**: PR-IP-1
**ISO-2700-1 v2013**: A.8.2.3
**ISO-2700-1 v2022**: A.8.9
**SOC2 v2017**: CC5.2.2
**Cloud Controls Matrix 4**: ISV-04 | +| `dnsRequirePolicyLogging` | Enforce the enablement of Cloud DNS logging for all VPC networks. | **PCI-DSS 4.0**: 10.4.1, 10.4.1.1, 10.4.2, 10.4.3
**NIST 800-53 R5**: AU-6, AU-7
**NIST Cybersecurity Framework 1.0**: DE-AE-2, PR-PT-1, RS-AN-1
**ISO-2700-1 v2022**: A.5.25
**SOC2 v2017**: CC4.1.1, CC4.1.2, CC4.1.3, CC4.1.4, CC4.1.5, CC4.1.6, CC4.1.7, CC4.1.8, CC7.3.1, CC7.3.2, CC7.3.3, CC7.3.4, CC7.3.5
**HIPAA**: 164.308(a)(1)(ii), 164.312(b)
**Cloud Controls Matrix 4**: LOG-05 | +| `firewallRestrictOpenWorldRule` | Prevent the creation of VPC firewall rules with a source or destination of `0.0.0.0/0`. | | +| `firewallRestrictRdpPolicyRule` | Prevent RDP access from the internet via firewall policies. | **CIS Controls 8.0**: 4.4, 4.5
**PCI-DSS 4.0**: 1.2.1, 1.4.1
**NIST 800-53 R4**: SC-7
**NIST 800-53 R5**: CA-9, SC-7
**ISO-2700-1 v2013**: A.13.1.1
**SOC2 v2017**: CC6.6.1, CC6.6.4 | +| `firewallRestrictSshPolicyRule` | Prevent SSH access from the internet via firewall policies. | **CIS Controls 8.0**: 4.4, 4.5
**PCI-DSS 4.0**: 1.2.1, 1.4.1
**NIST 800-53 R4**: SC-7
**NIST 800-53 R5**: CA-9, SC-7
**ISO-2700-1 v2013**: A.13.1.1
**SOC2 v2017**: CC6.6.1, CC6.6.4 | +| `gkeAllowedNodePoolImages` | Enforce that GKE nodes are using authorized node images | **CIS for GKE 1.5**: 5.5.1
**PCI-DSS 4.0**: 2.2.6, 5.2, 6.2.1 | +| `gkeAllowedReleaseChannels` | Enfore that GKE cluster are using authorized release channels | **CIS for GKE 1.5**: 5.5.4 | +| `gkeDisableAlphaCluster` | Prevent the use of alpha features for GKE clusters in production workloads. | **CIS for GKE 1.5**: 5.10.2 | +| `gkeDisableKubernetesDashboard` | Prevent the enablement of the GKE Web UI dashboard. | **CIS for GKE 1.5**: 5.10.1
**PCI-DSS 4.0**: 6.4 | +| `gkeDisableLegacyAbac` | Enforce that GKE clusters is configured with no legacy ABAC enabled | **CIS for GKE 1.5**: 5.8.3
**PCI-DSS 4.0**: 4.1 | +| `gkeDisableLegacyMetadataEndpoints` | Enforce that GKE clusters are created with legacy metadata endpoints disabled | **CIS for GKE 1.5**: 5.4.1 | +| `gkeRequireCOSImage` | Enforce the nodes pool are using Container-Optimized OS for running containers | **PCI-DSS 4.0**: 2.2.6 | +| `gkeRequireDataplaneV2` | Enforce that the GKE clusters is configured to use dataplane v2 | | +| `gkeRequireGKEMetadataServer` | Enforce that GKE clusters are configured with GKE metadata server enabled | **CIS for GKE 1.5**: 5.4.2 | +| `gkeRequireIntegrityMonitoring` | Enforce that GKE nodes are configured with integrity monitoring enabled | **CIS for GKE 1.5**: 5.5.6 | +| `gkeRequireMonitoring` | Enforce that GKE clusters monitoring is enabled | **CIS for GKE 1.5**: 5.7.1
**PCI-DSS 4.0**: 10.2 | +| `gkeRequireNodePoolAutoRepair` | Enforce that GKE clusters are configured with node auto-repair enabled | **CIS for GKE 1.5**: 5.5.2
**PCI-DSS 4.0**: 2.2.6 | +| `gkeRequireNodePoolAutoUpgrade` | Enforce that GKE clusters are configured with node auto-upgrade enabled | **CIS for GKE 1.5**: 5.5.3
**PCI-DSS 4.0**: 2.2.6 | +| `gkeRequireRegionalClusters` | Enforce the creation of regional GKE clusters | | +| `gkeRequireSecureBoot` | Enforce that GKE nodes are configured with secure boot enabled | **CIS for GKE 1.5**: 5.5.7 | +| `gkeRequireVPCNativeCluster` | Enforce that GKE clusters are created with VPC-native | **CIS for GKE 1.5**: 5.6.2
**PCI-DSS 4.0**: 1.4.3 | +| `iamDisablePublicBindings` | Ensure That BigQuery Datasets Are Not Anonymously or Publicly Accessible | **CIS Controls 8.0**: 3.3
**PCI-DSS 4.0**: 1.3.1
**NIST 800-53 R4**: AC-2
**NIST 800-53 R5**: AC-3, AC-5, AC-6, MP-2
**NIST Cybersecurity Framework 1.0**: PR-AC-4
**ISO-2700-1 v2013**: A.14.1.3, A.8.2.3
**ISO-2700-1 v2022**: A.5.10, A.5.15, A.8.3, A.8.4
**SOC2 v2017**: CC5.2.3, CC6.1.3, CC6.1.7
**HIPAA**: 164.308(a)(3)(i), 164.308(a)(3)(ii), 164.312(a)(1)
**Cloud Controls Matrix 4**: DSP-17 | +| `networkDisableTargetHTTPProxy` | Prevent the use of weak SSL policies on HTTPS and SSL Proxy load balancers. | | +| `networkDisableWeakSSLPolicy` | Prevent the use of weak SSL policies on HTTPS and SSL Proxy load balancers. | | +| `networkRequireCustomModeVpc` | Ensure That the Default Network Does Not Exist in a Project | **CIS for GKE 1.5**: 3.1
**CIS Controls 8.0**: 4.2
**PCI-DSS 4.0**: 1.1.1, 1.2.1, 1.2.6, 1.2.7, 1.4.2, 1.5.1, 2.1.1, 2.2.1
**NIST 800-53 R5**: AC-18, CM-2, CM-6, CM-7, CM-9
**NIST Cybersecurity Framework 1.0**: PR-IP-1
**ISO-2700-1 v2022**: A.8.9
**SOC2 v2017**: CC5.2.2
**Cloud Controls Matrix 4**: ISV-04 | +| `networkRequireSubnetPrivateGoogleAccess` | Enforce Private Google Access for all VPC network subnets. | | + + +### Detective Controls + +#### SCC Built-in Modules Detectors +SCC SHA Detectors are available only for organization have subscribed to SCC Premium or Enterprise. Refer to https://cloud.google.com/security-command-center/docs/service-tiers for more information. + + +Complete list of built-in SCC SHA detectors is available here https://cloud.google.com/security-command-center/docs/concepts-vulnerabilities-findings. + + +#### SCC Custom Modules Detectors +SCC Custom SHA Detectors are available only for organization have subscribed to SCC Premium or Enterprise. Refer to https://cloud.google.com/security-command-center/docs/service-tiers for more information. + + +| Module | Description | Compliance Mapping | +|---|---|---| +| `cloudfunctionsV1RequireIngressInternalAndLoadBalancer` | Ensure Cloud Functions Gen1 only allows internal and load balancer traffic. | | +| `cloudfunctionsV1RequireVPCConnector` | Ensure Cloud Functions Gen1 are configured with a VPC connector. | | +| `cloudrunRequireBinaryAuthorization` | Restrict Cloud Run services and jobs to an authorized list of Binary Authorization policies. | | +| `cloudrunRequireEgressAllTraffic` | Ensure all traffic from Cloud Run services and jobs is routed through a VPC connector. | | +| `cloudrunRequireIngressInternalAndLoadBalancer` | Ensure Cloud Run services only allow internal and load balancer traffic. | | +| `cloudsqlRequirePointInTimeRecovery` | Enforce point-in-time recovery for all Cloud SQL backup configurations. | | +| `computeDisableNestedVirtualization` | Prevent the creation of Compute Engine instances with nested virtualization enabled. | | +| `gkeDisableClientCertificateAuth` | Prevent the use of legacy authentication methods for GKE API servers. | **CIS for GKE 1.5**: 2.1.1
5.8.1
**PCI-DSS 4.0**: 4.1 | +| `gkeRequireDataplaneV2` | Enforce that the GKE clusters is configured to use dataplane v2 | | +| `gkeRequireRegionalCluster` | Enforce the creation of regional GKE clusters | | + + +#### Observability +| Alert | Description | Compliance Mapping | +|---|---|---| +| `auditConfigChanges` | Ensure log metric filters and alerts exist for audit configuration changes. | **PCI-DSS 4.0**: 10.2.1, 10.2.1.1, 10.2.1.2, 10.2.1.3, 10.2.1.4, 10.2.1.5, 10.2.1.6, 10.2.1.7, 10.2.2, 5.3.4, 6.4.1, 6.4.2 | +| `customRoleChanges` | Ensure log metric filters and alerts exist for custom role changes. | **PCI-DSS 4.0**: 10.2.1, 10.2.1.1, 10.2.1.2, 10.2.1.3, 10.2.1.4, 10.2.1.5, 10.2.1.6, 10.2.1.7, 10.2.2, 5.3.4, 6.4.1, 6.4.2 | +| `projectOwnershipChange` | Ensure log metric filters and alerts exist for project ownership changes. | **PCI-DSS 4.0**: 10.2.1, 10.2.1.1, 10.2.1.2, 10.2.1.3, 10.2.1.4, 10.2.1.5, 10.2.1.6, 10.2.1.7, 10.2.2, 5.3.4, 6.4.1, 6.4.2 | + +## Troubleshooting + +### Custom Organization Policy Concurrency Issue + +The following error below might appears when you are trying to create multiple custom organization policies concurrently. +As per October 2025, a bug exits providing misleading error message `Error 409: Requested entity already exists`. + +``` +│ Error: Error creating Policy: googleapi: Error 409: Requested entity already exists +│ +│ with module.organization-iam[0].google_org_policy_policy.default["custom.gkeRequireVPCNativeCluster"], +│ on ../../../modules/organization/organization-policies.tf line 105, in resource "google_org_policy_policy" "default": +│ 105: resource "google_org_policy_policy" "default" { +``` + +As per now, the workaround is to force terraform do not use concurrent requests. To fix this, you can run `terraform apply` with parallelism set to 1 the first time the custom organization policies are provisionned. + +```bash +terraform apply -parallelism=1 +``` + + +### Custom Constraint Deletion + +If you delete a custom constraint, any policies that have been created using that constraint continue to exist, but are ignored. You can't create another custom constraint with the same name than a previously deleted custom constraint. + +See https://cloud.google.com/resource-manager/docs/organization-policy/creating-managing-custom-constraints#delete_custom_constraint for more information. + +As per October 2025, a feature request is still opened to fix that behavior https://issuetracker.google.com/issues/434909712. +Meanwhile, we recommend to not remove any custom constraint created except if this is certain that the constraint will never be used anymore. + +If you need to cleanup Fabric FAST Stage 0, and want to avoid issues during next reprovisionning, it is recommended to remove from Terraform state custom constraints to avoid any future issue later. + +Retrieve the custom constraint part of Terraform state +```bash +$ terraform state list | grep google_org_policy_custom_constraint +module.organization[0].google_org_policy_custom_constraint.constraint["custom.accesscontextmanagerDisableBridgePerimeters"] +module.organization[0].google_org_policy_custom_constraint.constraint["custom.cloudrunDisableEnvironmentVariablePattern"] +module.organization[0].google_org_policy_custom_constraint.constraint["custom.cloudrunJobRequireBinaryAuthorization"] +module.organization[0].google_org_policy_custom_constraint.constraint["custom.cloudrunServiceRequireBinaryAuthorization"] +... +``` + +Remove the constraints from the state. You can do that for every constraints. Do not execute this part if permanent removal is needed. +```bash +for x in $(terraform state list | grep google_org_policy_custom_constraint); do + terraform state rm "$x"; +done +``` + +### Security Command Center Management API not enabled + +For organizations not using **SCC Premium or Enterprise**, the kind of error error appear when `securitycentermanagement.googleapis.com` has not been enabled. +``` +│ Error: Error creating OrganizationSecurityHealthAnalyticsCustomModule: googleapi: Error 403: Security Command Center Management API has not been used in project 111111111111 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/securitycentermanagement.googleapis.com/overview?project=111111111111 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry. +``` + +In the case you do not want to use SCC detectors and do not have an SCC Premium or Enterprise subscription, **the controls placed in the `organization/scc-sha-custom-modules` folder need to be removed to ensure they are not provisioned.** + +In the case you want to use SCC detectors and have an SCC Premium or Enterprise subscription, **ensure that the API `securitycentermanagement.googleapis.com`** has been enabled successfully. + + +### Security Command Center Premium or Enterprise not enabled + +If you get this kind of error, it means that Security Command Center Premium or Enterprise is not enabled on your organization. + +```bash +Error: Error creating OrganizationSecurityHealthAnalyticsCustomModule: googleapi: Error 404: Parent resource "organizations/1234567890/locations/global" not found. +│ +│ with module.organization[0].google_scc_management_organization_security_health_analytics_custom_module.scc_organization_custom_module["cloudfunctionsV1RequireIngressInternalAndLoadBalancer"], +│ on ../../../modules/organization/scc-sha-custom-modules.tf line 49, in resource "google_scc_management_organization_security_health_analytics_custom_module" "scc_organization_custom_module": +│ 49: resource "google_scc_management_organization_security_health_analytics_custom_module" "scc_organization_custom_module" { +``` + +In the case you want to use SCC detectors and have an SCC Premium or Enterprise subscription, **ensure that the Security Command Center Premium or Enterprise`** has been enabled successfully enabled on the organization. + diff --git a/fast/stages/0-org-setup/datasets/hardened/assets/diagram.excalidraw.gz b/fast/stages/0-org-setup/datasets/hardened/assets/diagram.excalidraw.gz new file mode 100644 index 000000000..48a1f25bb Binary files /dev/null and b/fast/stages/0-org-setup/datasets/hardened/assets/diagram.excalidraw.gz differ diff --git a/fast/stages/0-org-setup/datasets/hardened/assets/diagram.png b/fast/stages/0-org-setup/datasets/hardened/assets/diagram.png new file mode 100644 index 000000000..24e8aa351 Binary files /dev/null and b/fast/stages/0-org-setup/datasets/hardened/assets/diagram.png differ diff --git a/fast/stages/0-org-setup/datasets/hardened/defaults.yaml b/fast/stages/0-org-setup/datasets/hardened/defaults.yaml new file mode 100644 index 000000000..6a86ae90c --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/defaults.yaml @@ -0,0 +1,92 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../schemas/defaults.schema.json + +global: + # use `gcloud beta billing accounts list` to populate + billing_account: ABCDEF-0123456-ABCDEF + organization: + # use `gcloud organizations list`` to populate + domain: fast-test-00.example.com + id: 1234567890 + customer_id: abcd123456 +projects: + defaults: + # prefix must be unique and less than 9 characters + prefix: test00 + locations: + bigquery: $locations:primary + logging: $locations:primary + storage: $locations:primary + overrides: {} +context: + # you can populate context variables here for use in YAML replacements + iam_principals: + # this is the default group used in boostrap, initial user must be a member + gcp-organization-admins: group:gcp-organization-admins@example.com + locations: + primary: europe-west1 +output_files: + # local path is optional but recommended when starting + local_path: ~/fast-config/fast-test-00 + storage_bucket: $storage_buckets:iac-0/iac-outputs + providers: + 0-org-setup: + bucket: $storage_buckets:iac-0/iac-org-state + service_account: $iam_principals:service_accounts/iac-0/iac-org-rw + 0-org-setup-ro: + bucket: $storage_buckets:iac-0/iac-org-state + service_account: $iam_principals:service_accounts/iac-0/iac-org-ro + 1-vpcsc: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 1-vpcsc + service_account: $iam_principals:service_accounts/iac-0/iac-vpcsc-rw + 1-vpcsc-ro: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 1-vpcsc + service_account: $iam_principals:service_accounts/iac-0/iac-vpcsc-ro + 2-networking: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-networking + service_account: $iam_principals:service_accounts/iac-0/iac-networking-rw + 2-networking-ro: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-networking + service_account: $iam_principals:service_accounts/iac-0/iac-networking-ro + 2-security: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-security + service_account: $iam_principals:service_accounts/iac-0/iac-security-rw + 2-security-ro: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-security + service_account: $iam_principals:service_accounts/iac-0/iac-security-ro + 2-project-factory: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-project-factory + service_account: $iam_principals:service_accounts/iac-0/iac-pf-rw + 2-project-factory-ro: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 2-project-factory + service_account: $iam_principals:service_accounts/iac-0/iac-pf-ro + 3-data-platform-dev: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 3-data-platform-dev + service_account: $iam_principals:service_accounts/iac-0/iac-dp-dev-rw + 3-data-platform-dev-ro: + bucket: $storage_buckets:iac-0/iac-stage-state + prefix: 3-data-platform-dev + service_account: $iam_principals:service_accounts/iac-0/iac-dp-dev-ro + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/.config.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/.config.yaml new file mode 100644 index 000000000..2c1571f36 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/.config.yaml @@ -0,0 +1,123 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: data access logs + +# yaml-language-server: $schema=../../../schemas/organization.schema.json + +id: $defaults:organization/id +contacts: + default: + - $iam_principals:gcp-organization-admins +# conditional authoritative IAM bindings +iam_bindings: + # these don't conflict with IAM / IAM by principal + pf_org_policy_admin: + role: roles/orgpolicy.policyAdmin + members: + - $iam_principals:service_accounts/iac-0/iac-pf-rw + condition: + expression: resource.matchTag('${organization.id}/context', 'project-factory') + title: Project factory org policy admin + pf_org_policy_viewer: + role: roles/orgpolicy.policyViewer + members: + - $iam_principals:service_accounts/iac-0/iac-pf-ro + condition: + expression: resource.matchTag('${organization.id}/context', 'project-factory') + title: Project factory org policy viewer +# authoritative IAM bindings by principal +iam_by_principals: + $iam_principals:gcp-organization-admins: + - roles/cloudasset.owner + - roles/cloudsupport.admin + - roles/compute.osAdminLogin + - roles/compute.osLoginExternalUser + - roles/compute.xpnAdmin + - roles/orgpolicy.policyAdmin + - roles/owner + - roles/resourcemanager.folderAdmin + - roles/resourcemanager.organizationAdmin + - roles/resourcemanager.projectCreator + - roles/resourcemanager.tagAdmin + - roles/iam.workforcePoolAdmin + $iam_principals:service_accounts/iac-0/iac-org-rw: + - roles/accesscontextmanager.policyAdmin + - roles/cloudasset.viewer + - roles/essentialcontacts.admin + - roles/iam.organizationRoleAdmin + - roles/iam.workforcePoolAdmin + - roles/logging.admin + - roles/orgpolicy.policyAdmin + - roles/resourcemanager.folderAdmin + - roles/resourcemanager.organizationAdmin + - roles/resourcemanager.projectCreator + - roles/resourcemanager.projectMover + - roles/resourcemanager.tagAdmin + - roles/resourcemanager.tagUser + - roles/securitycentermanagement.customModulesEditor + $iam_principals:service_accounts/iac-0/iac-org-ro: + - roles/cloudasset.viewer + - roles/essentialcontacts.viewer + - roles/iam.organizationRoleViewer + - roles/iam.workforcePoolViewer + - roles/logging.viewer + - roles/orgpolicy.policyViewer + - roles/resourcemanager.folderViewer + - roles/resourcemanager.tagViewer + - roles/serviceusage.serviceUsageViewer + - $custom_roles:organization_admin_viewer + - $custom_roles:tag_viewer + $iam_principals:service_accounts/iac-0/iac-networking-rw: + - roles/compute.orgFirewallPolicyAdmin + - roles/compute.xpnAdmin + $iam_principals:service_accounts/iac-0/iac-networking-ro: + - roles/compute.orgFirewallPolicyUser + - roles/compute.viewer + $iam_principals:service_accounts/iac-0/iac-security-rw: + - roles/cloudasset.viewer + $iam_principals:service_accounts/iac-0/iac-vpcsc-rw: + - roles/accesscontextmanager.policyAdmin + - roles/cloudasset.viewer + $iam_principals:service_accounts/iac-0/iac-vpcsc-ro: + - roles/accesscontextmanager.policyReader + - roles/cloudasset.viewer +logging: + # disable_default_log_sink: false + storage_location: $locations:primary + sinks: + audit-logs: + # description: foo + # exclusions: {} + destination: $log_buckets:log-0/audit-logs + filter: | + log_id("cloudaudit.googleapis.com/activity") OR + log_id("cloudaudit.googleapis.com/system_event") OR + log_id("cloudaudit.googleapis.com/policy") OR + log_id("cloudaudit.googleapis.com/access_transparency") + iam: + destination: $log_buckets:log-0/iam + filter: | + protoPayload.serviceName="iamcredentials.googleapis.com" OR + protoPayload.serviceName="iam.googleapis.com" OR + protoPayload.serviceName="sts.googleapis.com" + vpc-sc: + destination: $log_buckets:log-0/vpc-sc + filter: | + protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" +# authoritative IAM bindings by role +# these are internally merged with IAM by principal +iam: + # reset default role on new organizations + roles/billing.creator: [] \ No newline at end of file diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.accesscontextmanagerDisableBridgePerimeters.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.accesscontextmanagerDisableBridgePerimeters.yaml new file mode 100644 index 000000000..7e72e8fb5 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.accesscontextmanagerDisableBridgePerimeters.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.accesscontextmanagerDisableBridgePerimeters: + action_type: DENY + condition: |- + resource.perimeterType == 'PERIMETER_TYPE_BRIDGE' + description: Ensure no perimeter bridges are used. Instead, use ingress and egress + rules. + display_name: Deny usage of perimeter bridges + method_types: + - CREATE + - UPDATE + resource_types: + - accesscontextmanager.googleapis.com/ServicePerimeter diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunDisableEnvironmentVariablePattern.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunDisableEnvironmentVariablePattern.yaml new file mode 100644 index 000000000..ff3c47f52 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunDisableEnvironmentVariablePattern.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudrunDisableEnvironmentVariablePattern: + action_type: DENY + condition: |- + resource.spec.template.spec.containers.exists(container, container.env.exists(env, ["[sS][eE][cC][rR][eE][tT]", "[kK][eE][yY]", "[pP][aA][sS][sS][wW][oO][rR][dD]", "[tT][oO][kK][eE][nN]"].exists(pattern, env.name.matches(pattern)))) + description: Enforce that certain patterns are not used in environment variables + of Cloud Run Service or Cloud Run Functions + display_name: Disable usage of certain patterns in Cloud Run Service or Cloud Run + Functions environment variables + method_types: + - CREATE + - UPDATE + resource_types: + - run.googleapis.com/Service diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunJobRequireBinaryAuthorization.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunJobRequireBinaryAuthorization.yaml new file mode 100644 index 000000000..124742a94 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunJobRequireBinaryAuthorization.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudrunJobRequireBinaryAuthorization: + action_type: DENY + condition: |- + !('run.googleapis.com/binary-authorization' in resource.metadata.annotations) + description: Enforce that Cloud Run Job are using binary authorization + display_name: Disable creation of Cloud Run Job without Binary Authorization + method_types: + - CREATE + - UPDATE + resource_types: + - run.googleapis.com/Job diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunServiceRequireBinaryAuthorization.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunServiceRequireBinaryAuthorization.yaml new file mode 100644 index 000000000..52df5e670 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudrunServiceRequireBinaryAuthorization.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudrunServiceRequireBinaryAuthorization: + action_type: DENY + condition: |- + !('run.googleapis.com/binary-authorization' in resource.metadata.annotations) + description: Enforce that Cloud Run Service are using binary authorization + display_name: Disable creation of Cloud Run Service without Binary Authorization + method_types: + - CREATE + - UPDATE + resource_types: + - run.googleapis.com/Service diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlDisablePublicAuthorizedNetworks.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlDisablePublicAuthorizedNetworks.yaml new file mode 100644 index 000000000..1e6cfeb57 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlDisablePublicAuthorizedNetworks.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlDisablePublicAuthorizedNetworks: + action_type: DENY + condition: |- + resource.settings.ipConfiguration.authorizedNetworks.exists(network, network.value == '0.0.0.0/0') + description: Ensure That Cloud SQL database instances do not implicitly whitelist + all public IP addresses + display_name: Require Cloud SQL database instances to not whitelist all public IP + addresses + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlEnforcePasswordComplexity.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlEnforcePasswordComplexity.yaml new file mode 100644 index 000000000..d4abe112f --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlEnforcePasswordComplexity.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlEnforcePasswordComplexity: + action_type: DENY + condition: |- + resource.settings.passwordValidationPolicy.complexity != "COMPLEXITY_DEFAULT" || resource.settings.passwordValidationPolicy.minLength < 12 + description: Ensure that Cloud SQL instance is configured with a password complexity + to be combination of lowercase, uppercase, numeric, and non-alphanumeric characters + display_name: Require Cloud SQL instances to configure password complexity to COMPLEXITY_DEFAULT + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireAutomatedBackup.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireAutomatedBackup.yaml new file mode 100644 index 000000000..0abe78c6e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireAutomatedBackup.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequireAutomatedBackup: + action_type: DENY + condition: |- + resource.settings.backupConfiguration.enabled != true + description: Ensure that Cloud SQL instance have automated backup enabled + display_name: Require Cloud SQL instances to have automated backup enabled + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireMySQLDatabaseFlags.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireMySQLDatabaseFlags.yaml new file mode 100644 index 000000000..dc2a0b401 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireMySQLDatabaseFlags.yaml @@ -0,0 +1,30 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequireMySQLDatabaseFlags: + action_type: DENY + condition: |- + resource.databaseVersion.startsWith('MYSQL') && ( + (resource.settings.databaseFlags.exists(flag, flag.name == 'skip_show_database' && flag.value == 'on') == false) || + (resource.settings.databaseFlags.exists(flag, flag.name == 'local_infile' && flag.value == 'off') == false) + ) + description: Ensure Cloud SQL for MySQL instance database flags are set correctly + (e.g skip_show_database, local_infile) + display_name: Require Cloud SQL for MySQL instance database flags to be configured + correctly (e.g skip_show_database, local_infile) + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePointInTimeRecovery.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePointInTimeRecovery.yaml new file mode 100644 index 000000000..a813c1fc9 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePointInTimeRecovery.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequirePointInTimeRecovery: + action_type: DENY + condition: |- + (resource.databaseVersion.contains("POSTGRES") || resource.databaseVersion.contains("SQLSERVER")) && resource.settings.backupConfiguration.pointInTimeRecoveryEnabled == false + description: Ensure that Cloud SQL instance is configure enable point in time recovery + in the backup configuration. This setting is possibly for Postgres and SQLServer + databases. + display_name: Require Cloud SQL instances to enable point in time recovery + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseAdditionalFlags.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseAdditionalFlags.yaml new file mode 100644 index 000000000..2820223c0 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseAdditionalFlags.yaml @@ -0,0 +1,31 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequirePostgreSQLDatabaseAdditionalFlags: + action_type: DENY + condition: |- + resource.databaseVersion.startsWith('POSTGRES') && ( + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_checkpoints' && flag.value == 'on') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_executor_stats' && flag.value == 'off') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_lock_waits' && flag.value == 'on') + ) + description: Ensure Cloud SQL for PostgreSQL instance database flags are set correctly + (e.g log_checkpoints, log_executor_stats, log_lock_waits) + display_name: Require Cloud SQL for PostgreSQL instance database flags to be configured + correctly (e.g log_checkpoints, log_executor_stats, log_lock_waits) + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseFlags.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseFlags.yaml new file mode 100644 index 000000000..f7c756a08 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequirePostgreSQLDatabaseFlags.yaml @@ -0,0 +1,36 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequirePostgreSQLDatabaseFlags: + action_type: DENY + condition: |- + resource.databaseVersion.startsWith('POSTGRES') && ( + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_connections' && flag.value == 'on') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_disconnections' && flag.value == 'on') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'log_min_duration_statement' && flag.value == '-1') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'cloudsql.enable_pgaudit' && flag.value == 'on') || + resource.settings.databaseFlags.exists(flag, flag.name == 'log_min_messages' && flag.value in ['error' , 'log', 'fatal', 'panic']) || + resource.settings.databaseFlags.exists(flag, flag.name == 'log_min_error_statement' && flag.value in ['log', 'fatal', 'panic']) || + resource.settings.databaseFlags.exists(flag, flag.name == 'log_error_verbosity' && flag.value in ['terse']) || + resource.settings.databaseFlags.exists(flag, flag.name == 'log_statement' && flag.value in ['none']) + ) + description: Ensure Cloud SQL for PostgreSQL instance database flags are set correctly + (e.g log_connections) + display_name: Require Cloud SQL for PostgreSQL instance database flags to be configured + correctly (e.g log_connections) + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireRootPassword.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireRootPassword.yaml new file mode 100644 index 000000000..cce520793 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireRootPassword.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequireRootPassword: + action_type: DENY + condition: |- + resource.settings.passwordValidationPolicy.minLength == 0 + description: Ensure that Cloud SQL instance is configured to use a root password + display_name: Require Cloud SQL instances to configure root password + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSQLServerDatabaseFlags.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSQLServerDatabaseFlags.yaml new file mode 100644 index 000000000..dff0b551e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSQLServerDatabaseFlags.yaml @@ -0,0 +1,35 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequireSQLServerDatabaseFlags: + action_type: DENY + condition: |- + resource.databaseVersion.startsWith('SQLSERVER') && ( + resource.settings.databaseFlags.exists(flag, flag.name == 'external scripts enabled' && flag.value == 'on') || + resource.settings.databaseFlags.exists(flag, flag.name == 'cross db ownership chaining' && flag.value == 'on') || + resource.settings.databaseFlags.exists(flag, flag.name == 'contained database authentication' && flag.value == 'on') || + resource.settings.databaseFlags.exists(flag, flag.name == 'user connections' && flag.value != '0') || + resource.settings.databaseFlags.exists(flag, flag.name == 'user options' && flag.value != '0') || + !resource.settings.databaseFlags.exists(flag, flag.name == 'remote access' && flag.value == 'off') || + !resource.settings.databaseFlags.exists(flag, flag.name == '3625' && flag.value == 'on') + ) + description: Ensure Cloud SQL for SQLServer instance database flags are set correctly + (e.g external scripts enabled ...) + display_name: Require Cloud SQL for SQLServer instance database flags to be configured + correctly (e.g external scripts enabled ...) + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSSLConnection.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSSLConnection.yaml new file mode 100644 index 000000000..c1a58b39c --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.cloudsqlRequireSSLConnection.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.cloudsqlRequireSSLConnection: + action_type: DENY + condition: |- + resource.settings.ipConfiguration.sslMode in ['ENCRYPTED_ONLY', 'TRUSTED_CLIENT_CERTIFICATE_REQUIRED'] == false + description: Ensure that Cloud SQL instance is configured to allow only connections + that are encrypted with SSL/TLS + display_name: Require Cloud SQL instances to allow only connections that are encrypted + with SSL/TLS + method_types: + - CREATE + - UPDATE + resource_types: + - sqladmin.googleapis.com/Instance diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsAllowedSigningAlgorithms.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsAllowedSigningAlgorithms.yaml new file mode 100644 index 000000000..60ae1e55c --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsAllowedSigningAlgorithms.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.dnsAllowedSigningAlgorithms: + action_type: DENY + condition: |- + resource.visibility == "PUBLIC" && resource.dnssecConfig.state == "ON" && resource.dnssecConfig.defaultKeySpecs.exists(spec, spec.algorithm in ["ECDSAP256SHA256"] == false) + description: Ensure that allowed signing algorithms are used for the Key-Signing + key and Zone-Signing key in Cloud DNS DNSSEC + display_name: Require Cloud DNS DNSSEC configured to use only allowed algorithms + in Cloud DNS DNSSEC + method_types: + - CREATE + - UPDATE + resource_types: + - dns.googleapis.com/ManagedZone diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequireManageZoneDNSSEC.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequireManageZoneDNSSEC.yaml new file mode 100644 index 000000000..c1ffe64d7 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequireManageZoneDNSSEC.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.dnsRequireManageZoneDNSSEC: + action_type: DENY + condition: |- + resource.visibility == "PUBLIC" && (resource.dnssecConfig.state in ["ON", "TRANSFER"] == false) + description: Ensure that Cloud DNS DNSSEC is enabled when configuring a DNS Public + Managed Zone + display_name: Require Cloud DNS DNSSEC enabled when configuring a DNS Public Managed + Zone + method_types: + - CREATE + - UPDATE + resource_types: + - dns.googleapis.com/ManagedZone diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequirePolicyLogging.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequirePolicyLogging.yaml new file mode 100644 index 000000000..5ab51b295 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.dnsRequirePolicyLogging.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.dnsRequirePolicyLogging: + action_type: DENY + condition: |- + resource.enableLogging != true + description: Ensure that Cloud DNS logging is enabled when configuring a DNS Policy + display_name: Require Cloud DNS logging enabled when configuring a DNS Policy + method_types: + - CREATE + - UPDATE + resource_types: + - dns.googleapis.com/Policy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforcePolicyRuleLogging.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforcePolicyRuleLogging.yaml new file mode 100644 index 000000000..abcc0eb1a --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforcePolicyRuleLogging.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallEnforcePolicyRuleLogging: + action_type: DENY + condition: |- + resource.rules.exists(rule, rule.action != 'goto_next' && rule.enableLogging == false) + description: Ensure that Firewall Policy rules have logging enabled + display_name: Require Firewall Policy rules to have logging enabled + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/FirewallPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforceRuleLogging.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforceRuleLogging.yaml new file mode 100644 index 000000000..c625f51ff --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallEnforceRuleLogging.yaml @@ -0,0 +1,33 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallEnforceRuleLogging: + action_type: DENY + condition: |- + ( + (has(resource.logConfig) == false || resource.logConfig.enable == false) && + !resource.name.startsWith("gke-") && + !resource.name.startsWith("k8s-") && + !resource.name.endsWith("-hc") && + !resource.name.startsWith("k8s2-") && + !resource.name.startsWith("gkegw1-l7-") && + !resource.name.startsWith("gkemcg1-l7-") + ) + description: Ensure that VPC Firewall rules have logging enabled + display_name: Require VPC Firewall rules to have logging enabled + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/Firewall diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictOpenWorldRule.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictOpenWorldRule.yaml new file mode 100644 index 000000000..2f4f60b70 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictOpenWorldRule.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallRestrictOpenWorldRule: + action_type: DENY + condition: |- + (size(resource.allowed) > 0) && (resource.sourceRanges.exists(range, range == '0.0.0.0/0') || resource.destinationRanges.exists(range, range == '0.0.0.0/0')) + description: Prevent the creation of VPC firewall rule with source or destination + any IP address (0.0.0.0/0) + display_name: Restrict VPC Firewall rule creation that are open to the world + method_types: + - CREATE + resource_types: + - compute.googleapis.com/Firewall diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpPolicyRule.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpPolicyRule.yaml new file mode 100644 index 000000000..a13c82dc0 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpPolicyRule.yaml @@ -0,0 +1,36 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallRestrictRdpPolicyRule: + action_type: DENY + condition: |- + resource.rules.exists(rule, + rule.priority < 2147483644 && + rule.direction == 'INGRESS' && + !rule.match.srcIpRanges.all(ipRange, + ipRange.startsWith('192.168.') || ipRange == '35.235.240.0/20' || ipRange.startsWith('10.') + ) && + rule.match.layer4Configs.all(l4config, + l4config.ipProtocol == 'tcp' && + l4config.ports.all(port, port == '3389') + ) + ) + description: Ensure that RDP access is restricted from the Internet when using Firewall + Policy Rule + display_name: Restrict Firewall Policy rules allowing RDP access from the Internet + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/FirewallPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpRule.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpRule.yaml new file mode 100644 index 000000000..a53c3e9e5 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictRdpRule.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallRestrictRdpRule: + action_type: DENY + condition: |- + resource.direction.matches('INGRESS') && resource.allowed.containsFirewallPort('tcp', '3389') && !resource.sourceRanges.all(range, range == '35.235.240.0/20' || range.startsWith('10.') || range.startsWith('192.168.')) + description: Ensure that RDP access is restricted from the Internet when using VPC + Firewall Rule + display_name: Restrict VPC Firewall rules allowing RDP access from the Internet + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/Firewall diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshPolicyRule.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshPolicyRule.yaml new file mode 100644 index 000000000..21d43b9c3 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshPolicyRule.yaml @@ -0,0 +1,36 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallRestrictSshPolicyRule: + action_type: DENY + condition: |- + resource.rules.exists(rule, + rule.priority < 2147483644 && + rule.direction == 'INGRESS' && + !rule.match.srcIpRanges.all(ipRange, + ipRange.startsWith('192.168.') || ipRange == '35.235.240.0/20' || ipRange.startsWith('10.') + ) && + rule.match.layer4Configs.all(l4config, + l4config.ipProtocol == 'tcp' && + l4config.ports.all(port, port == '22') + ) + ) + description: Ensure that SSH access is restricted from the Internet when using Firewall + Policy Rule + display_name: Restrict Firewall Policy rules allowing SSH access from the Internet + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/FirewallPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshRule.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshRule.yaml new file mode 100644 index 000000000..0d62fb1a9 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.firewallRestrictSshRule.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.firewallRestrictSshRule: + action_type: DENY + condition: |- + resource.direction.matches('INGRESS') && resource.allowed.containsFirewallPort('tcp', '22') && !resource.sourceRanges.all(range, range == '35.235.240.0/20' || range.startsWith('10.') || range.startsWith('192.168.')) + description: Ensure that SSH access is restricted from the Internet when using VPC + Firewall Rule + display_name: Restrict VPC Firewall rules allowing SSH access from the Internet + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/Firewall diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedNodePoolImages.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedNodePoolImages.yaml new file mode 100644 index 000000000..afe36af55 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedNodePoolImages.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeAllowedNodePoolImages: + action_type: DENY + condition: |- + resource.config.imageType in ["COS_CONTAINERD"] == false + description: Enforce that GKE nodes are using authorized node images + display_name: Allow only authorized node pool images + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedReleaseChannels.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedReleaseChannels.yaml new file mode 100644 index 000000000..bc5bdc7d6 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeAllowedReleaseChannels.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeAllowedReleaseChannels: + action_type: DENY + condition: |- + resource.releaseChannel.channel in ["REGULAR", "STABLE"] == false + description: Enfore that GKE cluster are using authorized release channels + display_name: Allow only authorized release channels + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableAlphaCluster.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableAlphaCluster.yaml new file mode 100644 index 000000000..e0c354ee9 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableAlphaCluster.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeDisableAlphaCluster: + action_type: DENY + condition: |- + resource.enableKubernetesAlpha == true + description: Enforce that GKE clusters are not using alpha features for production + workloads + display_name: Disable alpha features for production workloads + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableKubernetesDashboard.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableKubernetesDashboard.yaml new file mode 100644 index 000000000..053dff095 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableKubernetesDashboard.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeDisableKubernetesDashboard: + action_type: DENY + condition: |- + resource.addonsConfig.kubernetesDashboard.disabled == false + description: Enforce that GKE clusters does not have Web UI dashboard enabled + display_name: Disable Web UI dashboard + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyAbac.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyAbac.yaml new file mode 100644 index 000000000..69a0e4294 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyAbac.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeDisableLegacyAbac: + action_type: DENY + condition: |- + resource.legacyAbac.enabled == true + description: Enforce that GKE clusters is configured with no legacy ABAC enabled + display_name: Disable legacy ABAC + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyMetadataEndpoints.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyMetadataEndpoints.yaml new file mode 100644 index 000000000..fcb79f4da --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeDisableLegacyMetadataEndpoints.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeDisableLegacyMetadataEndpoints: + action_type: DENY + condition: |- + ('disable-legacy-endpoints' in resource.config.metadata && resource.config.metadata['disable-legacy-endpoints'] == 'false') + description: Enforce that GKE clusters are created with legacy metadata endpoints + disabled + display_name: Disable legacy metadata endpoints + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireCOSImage.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireCOSImage.yaml new file mode 100644 index 000000000..099e6e4c8 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireCOSImage.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireCOSImage: + action_type: DENY + condition: |- + resource.config.imageType != "COS_CONTAINERD" + description: Enforce the nodes pool are using Container-Optimized OS for running + containers + display_name: Require Container-Optimized OS on node pools + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireDataplaneV2.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireDataplaneV2.yaml new file mode 100644 index 000000000..1242373a8 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireDataplaneV2.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireDataplaneV2: + action_type: DENY + condition: |- + resource.networkConfig.datapathProvider != 'ADVANCED_DATAPATH' + description: Enforce that the GKE clusters is configured to use dataplane v2 + display_name: Require dataplane v2 + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireGKEMetadataServer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireGKEMetadataServer.yaml new file mode 100644 index 000000000..8fad83b2a --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireGKEMetadataServer.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireGKEMetadataServer: + action_type: DENY + condition: |- + resource.config.workloadMetadataConfig.mode != 'GKE_METADATA' + description: Enforce that GKE clusters are configured with GKE metadata server enabled + display_name: Require GKE metadata server + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntegrityMonitoring.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntegrityMonitoring.yaml new file mode 100644 index 000000000..928ebdac0 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntegrityMonitoring.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireIntegrityMonitoring: + action_type: DENY + condition: |- + resource.config.shieldedInstanceConfig.enableIntegrityMonitoring == false + description: Enforce that GKE nodes are configured with integrity monitoring enabled + display_name: Enable integrity monitoring + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntraNodeVisibility.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntraNodeVisibility.yaml new file mode 100644 index 000000000..2863cbc36 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireIntraNodeVisibility.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireIntraNodeVisibility: + action_type: DENY + condition: |- + resource.networkConfig.enableIntraNodeVisibility == false + description: Enforce that GKE clusters intranode visibility is enabled + display_name: Enable intranode visibility + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMasterAuthorizedNetworks.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMasterAuthorizedNetworks.yaml new file mode 100644 index 000000000..ba496bbfc --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMasterAuthorizedNetworks.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireMasterAuthorizedNetworks: + action_type: DENY + condition: |- + resource.masterAuthorizedNetworksConfig.enabled == false + description: Enforce that GKE clusters restrict network access to the control planes + by configuring master authorized networks with authorized CIDR IP ranges + display_name: Require master authorized network with authorized CIDR IP ranges + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMonitoring.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMonitoring.yaml new file mode 100644 index 000000000..2962a2f21 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireMonitoring.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireMonitoring: + action_type: DENY + condition: |- + resource.monitoringService != 'monitoring.googleapis.com/kubernetes' + description: Enforce that GKE clusters monitoring is enabled + display_name: Enable monitoring + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoRepair.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoRepair.yaml new file mode 100644 index 000000000..491c52d6e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoRepair.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireNodePoolAutoRepair: + action_type: DENY + condition: |- + resource.management.autoRepair == false + description: Enforce that GKE clusters are configured with node auto-repair enabled + display_name: Enable node auto-repair + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoUpgrade.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoUpgrade.yaml new file mode 100644 index 000000000..9d62cfb02 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolAutoUpgrade.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireNodePoolAutoUpgrade: + action_type: DENY + condition: |- + resource.management.autoUpgrade == false + description: Enforce that GKE clusters are configured with node auto-upgrade enabled + display_name: Enable node auto-upgrade + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolCMEKEncryption.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolCMEKEncryption.yaml new file mode 100644 index 000000000..5054042c2 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolCMEKEncryption.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireNodePoolCMEKEncryption: + action_type: DENY + condition: |- + has(resource.config.bootDiskKmsKey) == false + description: Enforce that GKE nodes are configured with CMEK Encryption + display_name: Require NodePool CMEK Encryption + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolSandbox.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolSandbox.yaml new file mode 100644 index 000000000..9b60179bf --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireNodePoolSandbox.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireNodePoolSandbox: + action_type: DENY + condition: |- + resource.name.matches("default-pool") == false && has(resource.config.sandboxConfig) == false && resource.config.sandboxConfig.type != 'GVISOR' + description: Enforce that the GKE clusters nodes are isolated using GKE sandbox + (excepting the default node pool) + display_name: Require GKE Sandbox runtime + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequirePrivateEndpoint.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequirePrivateEndpoint.yaml new file mode 100644 index 000000000..6c8f81a51 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequirePrivateEndpoint.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequirePrivateEndpoint: + action_type: DENY + condition: |- + resource.privateClusterConfig.enablePrivateEndpoint == false + description: Enforce that GKE clusters are created as private clusters with public + endpoint disabled + display_name: Disable public endpoints + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireRegionalClusters.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireRegionalClusters.yaml new file mode 100644 index 000000000..9f0ea5c90 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireRegionalClusters.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireRegionalClusters: + action_type: DENY + condition: |- + resource.location.matches("^[a-z]+(-[a-z, 1-9]+)$") == false + description: Enforce the creation of regional GKE clusters + display_name: Require regional GKE cluster + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireSecureBoot.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireSecureBoot.yaml new file mode 100644 index 000000000..6bae09764 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireSecureBoot.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireSecureBoot: + action_type: DENY + condition: |- + resource.config.shieldedInstanceConfig.enableSecureBoot == false + description: Enforce that GKE nodes are configured with secure boot enabled + display_name: Enable secure boot + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/NodePool diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireVPCNativeCluster.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireVPCNativeCluster.yaml new file mode 100644 index 000000000..e7171b9ee --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.gkeRequireVPCNativeCluster.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.gkeRequireVPCNativeCluster: + action_type: DENY + condition: |- + resource.ipAllocationPolicy.useIpAliases == false + description: Enforce that GKE clusters are created with VPC-native + display_name: Require VPC-native + method_types: + - CREATE + - UPDATE + resource_types: + - container.googleapis.com/Cluster diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamAllowedMembers.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamAllowedMembers.yaml new file mode 100644 index 000000000..9443cd4df --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamAllowedMembers.yaml @@ -0,0 +1,29 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.iamAllowedMembers: + action_type: DENY + condition: |- + resource.bindings.exists(binding, + binding.members.exists(member, + !MemberSubjectEndsWith(member, ['@${organization.domain}', '.gserviceaccount.com']) + ) + ) + description: Ensure no binding are done with members outside the organization domain + display_name: Deny principals and members outside the organization domain + method_types: + - CREATE + - UPDATE + resource_types: + - iam.googleapis.com/AllowPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisablePublicBindings.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisablePublicBindings.yaml new file mode 100644 index 000000000..4d6167628 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisablePublicBindings.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.iamDisablePublicBindings: + action_type: DENY + condition: |- + resource.bindings.exists(binding, binding.members.exists(member, MemberSubjectMatches(member, ['allUsers', 'allAuthenticatedUsers']))) + description: Ensure no use of public bindings (allUsers, allAuthenticatedUsers) + display_name: Deny use of public access bindings with allUsers or allAuthenticatedUsers + method_types: + - CREATE + - UPDATE + resource_types: + - iam.googleapis.com/AllowPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisableRedisAdminRoles.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisableRedisAdminRoles.yaml new file mode 100644 index 000000000..c4e63e2ef --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.iamDisableRedisAdminRoles.yaml @@ -0,0 +1,34 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.iamDisableRedisAdminRoles: + action_type: DENY + condition: |- + resource.bindings.exists(binding, + binding.members.exists(member, + !MemberSubjectMatches(member, []) && + ( + RoleNameMatches(binding.role, ['roles/redis.admin']) || + RoleNameMatches(binding.role, ['roles/redis.editor']) || + RoleNameContains(binding.role, ['roles/redis.viewer']) + ) + ) + ) + description: Ensure no use of the basic roles (viewer, editor and owner) + display_name: Deny use of the basic roles + method_types: + - CREATE + - UPDATE + resource_types: + - iam.googleapis.com/AllowPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableTargetHTTPProxy.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableTargetHTTPProxy.yaml new file mode 100644 index 000000000..2d8c63ce5 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableTargetHTTPProxy.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.networkDisableTargetHTTPProxy: + action_type: DENY + condition: |- + true == true + description: Ensure Target HTTP Proxy are not used + display_name: Deny usage and creation of Target HTTP Proxy + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/TargetHttpProxy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableWeakSSLPolicy.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableWeakSSLPolicy.yaml new file mode 100644 index 000000000..7fda224f9 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkDisableWeakSSLPolicy.yaml @@ -0,0 +1,39 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.networkDisableWeakSSLPolicy: + action_type: DENY + condition: |- + (resource.profile == "COMPATIBLE") || (resource.profile == "CUSTOM" && + resource.customFeatures.exists(feature, feature in [ + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + ]) + ) || (resource.profile == "CUSTOM" && + resource.minTlsVersion in ["TLS_1_2", "TLS_1_3"] == false + ) || (resource.profile == "MODERN" && + resource.minTlsVersion in ["TLS_1_2", "TLS_1_3"] == false + ) || (resource.profile == "RESTRICTED" && + resource.minTlsVersion in ["TLS_1_2", "TLS_1_3"] == false + ) + description: Ensure SSL Policies created does not have weak cipher suites + display_name: Deny usage of SSL Policies with weak cipher suites + method_types: + - CREATE + - UPDATE + resource_types: + - compute.googleapis.com/SslPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireCustomModeVpc.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireCustomModeVpc.yaml new file mode 100644 index 000000000..a4a604936 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireCustomModeVpc.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.networkRequireCustomModeVpc: + action_type: DENY + condition: |- + resource.autoCreateSubnetworks == true + description: Enforce that the subnets creation is using custom mode for a VPC network + display_name: Require custom mode VPC network + method_types: + - CREATE + resource_types: + - compute.googleapis.com/Network diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireSubnetPrivateGoogleAccess.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireSubnetPrivateGoogleAccess.yaml new file mode 100644 index 000000000..ee0ea17d0 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.networkRequireSubnetPrivateGoogleAccess.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.networkRequireSubnetPrivateGoogleAccess: + action_type: DENY + condition: |- + resource.privateIpGoogleAccess == false + description: Enforce that the VPC network subnets are configured with private Google + access + display_name: Require Private Google Access + method_types: + - CREATE + resource_types: + - compute.googleapis.com/Subnetwork diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.storageRequireBucketObjectVersionning.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.storageRequireBucketObjectVersionning.yaml new file mode 100644 index 000000000..fe80d3dd3 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-constraints/custom.storageRequireBucketObjectVersionning.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +custom.storageRequireBucketObjectVersionning: + action_type: DENY + condition: |- + resource.versioning.enabled == false + description: Enforce Cloud Storage bucket object versioning to be configured + display_name: Require object versioning + method_types: + - CREATE + - UPDATE + resource_types: + - storage.googleapis.com/Bucket diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/network_firewall_policies_admin.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/network_firewall_policies_admin.yaml new file mode 100644 index 000000000..2d5f872e6 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/network_firewall_policies_admin.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json + +name: networkFirewallPoliciesAdmin +includedPermissions: + - compute.networks.setFirewallPolicy + - networksecurity.firewallEndpointAssociations.create + - networksecurity.firewallEndpointAssociations.delete + - networksecurity.firewallEndpointAssociations.get + - networksecurity.firewallEndpointAssociations.list + - networksecurity.firewallEndpointAssociations.update diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_admin.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_admin.yaml new file mode 100644 index 000000000..38b4ee7b6 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_admin.yaml @@ -0,0 +1,49 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# this is used by the networking SA to deploy NGFW Enterprise through the addon + +name: ngfwEnterpriseAdmin +includedPermissions: + - networksecurity.firewallEndpoints.create + - networksecurity.firewallEndpoints.delete + - networksecurity.firewallEndpoints.get + - networksecurity.firewallEndpoints.list + - networksecurity.firewallEndpoints.update + - networksecurity.firewallEndpoints.use + - networksecurity.locations.get + - networksecurity.locations.list + - networksecurity.operations.cancel + - networksecurity.operations.delete + - networksecurity.operations.get + - networksecurity.operations.list + - networksecurity.securityProfileGroups.create + - networksecurity.securityProfileGroups.delete + - networksecurity.securityProfileGroups.get + - networksecurity.securityProfileGroups.list + - networksecurity.securityProfileGroups.update + - networksecurity.securityProfileGroups.use + - networksecurity.securityProfiles.create + - networksecurity.securityProfiles.delete + - networksecurity.securityProfiles.get + - networksecurity.securityProfiles.list + - networksecurity.securityProfiles.update + - networksecurity.securityProfiles.use + - networksecurity.tlsInspectionPolicies.create + - networksecurity.tlsInspectionPolicies.delete + - networksecurity.tlsInspectionPolicies.get + - networksecurity.tlsInspectionPolicies.list + - networksecurity.tlsInspectionPolicies.update + - networksecurity.tlsInspectionPolicies.use diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_viewer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_viewer.yaml new file mode 100644 index 000000000..3e814ab9f --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/ngfw_enterprise_viewer.yaml @@ -0,0 +1,35 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# this is used by the networking SA to deploy NGFW Enterprise through the addon + +name: ngfwEnterpriseViewer +includedPermissions: + - networksecurity.firewallEndpoints.get + - networksecurity.firewallEndpoints.list + - networksecurity.firewallEndpoints.use + - networksecurity.locations.get + - networksecurity.locations.list + - networksecurity.operations.get + - networksecurity.operations.list + - networksecurity.securityProfileGroups.get + - networksecurity.securityProfileGroups.list + - networksecurity.securityProfileGroups.use + - networksecurity.securityProfiles.get + - networksecurity.securityProfiles.list + - networksecurity.securityProfiles.use + - networksecurity.tlsInspectionPolicies.get + - networksecurity.tlsInspectionPolicies.list + - networksecurity.tlsInspectionPolicies.use diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_admin_viewer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_admin_viewer.yaml new file mode 100644 index 000000000..b3008abc1 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_admin_viewer.yaml @@ -0,0 +1,34 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# this is used by the plan-only admin SA + +name: organizationAdminViewer +includedPermissions: + - essentialcontacts.contacts.get + - essentialcontacts.contacts.list + - logging.settings.get + - orgpolicy.constraints.list + - orgpolicy.policies.list + - orgpolicy.policy.get + - resourcemanager.folders.get + - resourcemanager.folders.getIamPolicy + - resourcemanager.folders.list + - resourcemanager.organizations.get + - resourcemanager.organizations.getIamPolicy + - resourcemanager.projects.get + - resourcemanager.projects.getIamPolicy + - resourcemanager.projects.list + - storage.buckets.getIamPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_iam_admin.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_iam_admin.yaml new file mode 100644 index 000000000..24f2de838 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/organization_iam_admin.yaml @@ -0,0 +1,22 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# this is needed for use in additive IAM bindings, to avoid conflicts + +name: organizationIamAdmin +includedPermissions: + - resourcemanager.organizations.get + - resourcemanager.organizations.getIamPolicy + - resourcemanager.organizations.setIamPolicy diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/project_iam_viewer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/project_iam_viewer.yaml new file mode 100644 index 000000000..b02b3ae38 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/project_iam_viewer.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# this is used by the plan-only admin SA + +name: projectIamViewer +includedPermissions: +- iam.policybindings.get +- iam.policybindings.list +- resourcemanager.projects.get +- resourcemanager.projects.getIamPolicy +- resourcemanager.projects.searchPolicyBindings diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/service_project_network_admin.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/service_project_network_admin.yaml new file mode 100644 index 000000000..809435090 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/service_project_network_admin.yaml @@ -0,0 +1,33 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json + +name: serviceProjectNetworkAdmin +includedPermissions: + - compute.globalOperations.get + # compute.networks.updatePeering and compute.networks.get are + # used by automation service accounts who manage service + # projects where peering creation might be needed (e.g. GKE). If + # you remove them your network administrators should create + # peerings for service projects + - compute.networks.updatePeering + - compute.networks.get + - compute.organizations.disableXpnResource + - compute.organizations.enableXpnResource + - compute.projects.get + - compute.subnetworks.getIamPolicy + - compute.subnetworks.setIamPolicy + - dns.networks.bindPrivateDNSZone + - resourcemanager.projects.get diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/storage_viewer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/storage_viewer.yaml new file mode 100644 index 000000000..faa31936b --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/storage_viewer.yaml @@ -0,0 +1,33 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# the following permissions are a descoped version of storage.admin + +name: storageViewer +includedPermissions: + - storage.buckets.get + - storage.buckets.getIamPolicy + - storage.buckets.getObjectInsights + - storage.buckets.list + - storage.buckets.listEffectiveTags + - storage.buckets.listTagBindings + - storage.managedFolders.get + - storage.managedFolders.getIamPolicy + - storage.managedFolders.list + - storage.multipartUploads.list + - storage.multipartUploads.listParts + - storage.objects.get + - storage.objects.getIamPolicy + - storage.objects.list diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/tag_viewer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/tag_viewer.yaml new file mode 100644 index 000000000..926ee7168 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/custom-roles/tag_viewer.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/custom-role.schema.json +# the following permissions are a descoped version of tagAdm + +name: tagViewer +includedPermissions: + - resourcemanager.tagHolds.list + - resourcemanager.tagKeys.get + - resourcemanager.tagKeys.getIamPolicy + - resourcemanager.tagKeys.list + - resourcemanager.tagValues.get + - resourcemanager.tagValues.getIamPolicy + - resourcemanager.tagValues.list diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/observability/auditConfigChanges.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/observability/auditConfigChanges.yaml new file mode 100644 index 000000000..242042242 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/observability/auditConfigChanges.yaml @@ -0,0 +1,76 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +alerts: + auditConfigChanges: + combiner: OR + conditions: + - condition_threshold: + aggregations: + - alignment_period: 60s + cross_series_reducer: REDUCE_SUM + group_by_fields: + - metric.label.principal + - metric.label.method_name + - metric.label.organization_id + - metric.label.folder_id + - metric.label.project_id + per_series_aligner: ALIGN_SUM + comparison: COMPARISON_GT + duration: 0s + filter: resource.type = "logging_bucket" AND metric.type = "logging.googleapis.com/user/auditConfigChanges" + threshold_value: 0 + trigger: + count: 1 + display_name: 'Log match condition: Audit Configuration Changes' + display_name: Audit Configuration Changes + documentation: + content: 'Log-based alerting policy in project ${project} detected audit configuration + changes. + + This alert helps track GCP services audit log configuration changes to ensure + appropriate audit logs are being collected. ``` protoPayload.methodName="SetIamPolicy" + AND protoPayload.serviceData.policyDelta.auditConfigDeltas:* ```' + mime_type: text/markdown +logging_metrics: + auditConfigChanges: + bucket_name: log-0/audit-logs + description: Audit Configuration Changes + filter: protoPayload.methodName="SetIamPolicy" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:* + label_extractors: + folder_id: EXTRACT(labels.folder_id) + method_name: EXTRACT(protoPayload.methodName) + organization_id: EXTRACT(labels.organization_id) + principal: EXTRACT(protoPayload.authenticationInfo.principalEmail) + project_id: EXTRACT(labels.project_id) + metric_descriptor: + labels: + - description: principal + key: principal + value_type: STRING + - description: method_name + key: method_name + value_type: STRING + - description: organization_id + key: organization_id + value_type: STRING + - description: folder_id + key: folder_id + value_type: STRING + - description: project_id + key: project_id + value_type: STRING + metric_kind: DELTA + unit: '1' + value_type: INT64 diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/observability/customRoleChanges.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/observability/customRoleChanges.yaml new file mode 100644 index 000000000..0deb4d50e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/observability/customRoleChanges.yaml @@ -0,0 +1,78 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +alerts: + customRoleChanges: + combiner: OR + conditions: + - condition_threshold: + aggregations: + - alignment_period: 60s + cross_series_reducer: REDUCE_SUM + group_by_fields: + - metric.label.principal + - metric.label.method_name + - metric.label.organization_id + - metric.label.project_id + - metric.label.role_name + per_series_aligner: ALIGN_SUM + comparison: COMPARISON_GT + duration: 0s + filter: resource.type = "logging_bucket" AND metric.type = "logging.googleapis.com/user/customRoleChanges" + threshold_value: 0 + trigger: + count: 1 + display_name: 'Log match condition: custom role changes' + display_name: Custom Role Changes + documentation: + content: "Log-based alerting policy in project ${project} detected custom IAM\ + \ role creation, deletion or update activities.\nThis alert helps ensure security\ + \ by monitoring changes to Identity and Access Management (IAM) roles. ```\n\ + \ resource.type=\"iam_role\" AND \n (\n protoPayload.methodName=\"google.iam.admin.v1.CreateRole\"\ + \ OR \n protoPayload.methodName=\"google.iam.admin.v1.UpdateRole\" OR \n\ + \ protoPayload.methodName=\"google.iam.admin.v1.DeleteRole\"\n )\n```" + mime_type: text/markdown +logging_metrics: + customRoleChanges: + bucket_name: log-0/audit-logs + description: Custom Role Changes + filter: "resource.type=\"iam_role\" AND (\n protoPayload.methodName=\"google.iam.admin.v1.CreateRole\"\ + \ OR\n protoPayload.methodName=\"google.iam.admin.v1.UpdateRole\" OR\n protoPayload.methodName=\"\ + google.iam.admin.v1.DeleteRole\"\n)" + label_extractors: + method_name: EXTRACT(protoPayload.methodName) + organization_id: EXTRACT(labels.organization_id) + principal: EXTRACT(protoPayload.authenticationInfo.principalEmail) + project_id: EXTRACT(labels.project_id) + role_name: EXTRACT(labels.role_name) + metric_descriptor: + labels: + - description: principal + key: principal + value_type: STRING + - description: method_name + key: method_name + value_type: STRING + - description: organization_id + key: organization_id + value_type: STRING + - description: project_id + key: project_id + value_type: STRING + - description: role_name + key: role_name + value_type: STRING + metric_kind: DELTA + unit: '1' + value_type: INT64 diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/observability/projectOwnershipChange.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/observability/projectOwnershipChange.yaml new file mode 100644 index 000000000..d064e5df8 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/observability/projectOwnershipChange.yaml @@ -0,0 +1,82 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +alerts: + projectOwnershipChange: + combiner: OR + conditions: + - condition_threshold: + aggregations: + - alignment_period: 60s + cross_series_reducer: REDUCE_SUM + group_by_fields: + - metric.label.principal + - metric.label.method_name + - metric.label.organization_id + - metric.label.folder_id + - metric.label.project_id + per_series_aligner: ALIGN_SUM + comparison: COMPARISON_GT + duration: 0s + filter: resource.type = "logging_bucket" AND metric.type = "logging.googleapis.com/user/projectOwnershipChange" + threshold_value: 0 + trigger: + count: 1 + display_name: Project Ownership Changes + display_name: Project Ownership Changes + documentation: + content: "Log-based alerting policy in project ${project} detected a project\ + \ ownership assignments or changes. ``` (protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\"\ + ) AND (ProjectOwnership OR projectOwnerInvitee) OR (\n protoPayload.serviceData.policyDelta.bindingDeltas.action=\"\ + REMOVE\" AND \n protoPayload.serviceData.policyDelta.bindingDeltas.role=\"\ + roles/owner\"\n) OR (\n protoPayload.serviceData.policyDelta.bindingDeltas.action=\"\ + ADD\" AND \n protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\"\ + \n) ```" + mime_type: text/markdown +logging_metrics: + projectOwnershipChange: + bucket_name: log-0/audit-logs + description: Project Ownership Changes + filter: "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\") AND\ + \ (ProjectOwnership OR projectOwnerInvitee) OR (\n protoPayload.serviceData.policyDelta.bindingDeltas.action=\"\ + REMOVE\" AND\n protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\"\ + \n) OR (\n protoPayload.serviceData.policyDelta.bindingDeltas.action=\"ADD\"\ + \ AND\n protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\"\ + \n)" + label_extractors: + folder_id: EXTRACT(labels.folder_id) + method_name: EXTRACT(protoPayload.methodName) + organization_id: EXTRACT(labels.organization_id) + principal: EXTRACT(protoPayload.authenticationInfo.principalEmail) + project_id: EXTRACT(labels.project_id) + metric_descriptor: + labels: + - description: principal + key: principal + value_type: STRING + - description: method_name + key: method_name + value_type: STRING + - description: organization_id + key: organization_id + value_type: STRING + - description: folder_id + key: folder_id + value_type: STRING + - description: project_id + key: project_id + value_type: STRING + metric_kind: DELTA + unit: '1' + value_type: INT64 diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/accesscontextmanager.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/accesscontextmanager.yaml new file mode 100644 index 000000000..58a0c960a --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/accesscontextmanager.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +custom.accesscontextmanagerDisableBridgePerimeters: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/appengine.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/appengine.yaml new file mode 100644 index 000000000..6ec545dcf --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/appengine.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +appengine.disableCodeDownload: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/bigquery.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/bigquery.yaml new file mode 100644 index 000000000..3285de8d9 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/bigquery.yaml @@ -0,0 +1,32 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +bigquery.disableBQOmniAWS: + rules: + - enforce: true + +bigquery.disableBQOmniAzure: + rules: + - enforce: true + +custom.iamDisablePublicBindings: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/cloudbuild.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/cloudbuild.yaml new file mode 100644 index 000000000..6077bbd1e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/cloudbuild.yaml @@ -0,0 +1,35 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +cloudbuild.allowedIntegrations: + rules: + - deny: + all: true + +cloudbuild.allowedWorkerPools: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + +cloudbuild.disableCreateDefaultServiceAccount: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/compute.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/compute.yaml new file mode 100644 index 000000000..3ca84e0fb --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/compute.yaml @@ -0,0 +1,132 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +compute.disableGuestAttributesAccess: + rules: + - enforce: true + +compute.disableInternetNetworkEndpointGroup: + rules: + - enforce: true + +compute.disableNestedVirtualization: + rules: + - enforce: true + +compute.disableSerialPortAccess: + rules: + - enforce: true + +compute.disableVpcExternalIpv6: + rules: + - enforce: true + +compute.managed.blockPreviewFeatures: + rules: + - enforce: true + +compute.requireOsLogin: + rules: + - enforce: true + +compute.requireShieldedVm: + rules: + - enforce: true + +compute.requireSslPolicy: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + +compute.restrictLoadBalancerCreationForTypes: + rules: + - allow: + values: + - "in:INTERNAL" + +compute.restrictProtocolForwardingCreationForTypes: + rules: + - allow: + values: + - "is:INTERNAL" + +compute.setNewProjectDefaultToZonalDNSOnly: + rules: + - enforce: true + +compute.skipDefaultNetworkCreation: + rules: + - enforce: true + +compute.trustedImageProjects: + rules: + - allow: + values: + - "is:projects/centos-cloud" + - "is:projects/cos-cloud" + - "is:projects/debian-cloud" + - "is:projects/fedora-cloud" + - "is:projects/fedora-coreos-cloud" + - "is:projects/opensuse-cloud" + - "is:projects/rhel-cloud" + - "is:projects/rhel-sap-cloud" + - "is:projects/rocky-linux-cloud" + - "is:projects/suse-cloud" + - "is:projects/suse-sap-cloud" + - "is:projects/ubuntu-os-cloud" + - "is:projects/ubuntu-os-pro-cloud" + - "is:projects/windows-cloud" + - "is:projects/windows-sql-cloud" + - "is:projects/confidential-vm-images" + - "is:projects/confidential-space-images" + - "is:projects/backupdr-images" + - "is:projects/deeplearning-platform-release" + - "is:projects/serverless-vpc-access-images" + - "is:projects/gke-node-images" + - "is:projects/gke-windows-node-images" + - "is:projects/ubuntu-os-gke-cloud" + +compute.vmExternalIpAccess: + rules: + - deny: + all: true + +custom.networkRequireSubnetPrivateGoogleAccess: + rules: + - enforce: true + +gcp.restrictTLSCipherSuites: + rules: + - allow: + values: + - "in:NIST-800-52-recommended-ciphers" + +gcp.restrictTLSVersion: + rules: + - deny: + values: + - "TLS_VERSION_1" + - "TLS_VERSION_1_1" + +iam.automaticIamGrantsForDefaultServiceAccounts: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/dns.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/dns.yaml new file mode 100644 index 000000000..e612f0b97 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/dns.yaml @@ -0,0 +1,32 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +custom.dnsAllowedSigningAlgorithms: + rules: + - enforce: true + +custom.dnsRequireManageZoneDNSSEC: + rules: + - enforce: true + +custom.dnsRequirePolicyLogging: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/essentialcontacts.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/essentialcontacts.yaml new file mode 100644 index 000000000..6f3d6bab6 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/essentialcontacts.yaml @@ -0,0 +1,36 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +essentialcontacts.allowedContactDomains: + rules: + - allow: + values: + - '@${organization.domain}' + condition: + title: Restrict essential contacts domains + expression: | + !resource.matchTag('${organization.id}/org-policies', 'allowed-essential-contacts-domains-all') + - allow: + all: true + condition: + title: Allow essential contacts from any domain + expression: | + resource.matchTag('${organization.id}/org-policies', 'allowed-essential-contacts-domains-all') + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/firewall.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/firewall.yaml new file mode 100644 index 000000000..be6f066c5 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/firewall.yaml @@ -0,0 +1,32 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +custom.firewallRestrictOpenWorldRule: + rules: + - enforce: true + +custom.firewallRestrictRdpPolicyRule: + rules: + - enforce: true + +custom.firewallRestrictSshPolicyRule: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gcp.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gcp.yaml new file mode 100644 index 000000000..b41b0ca04 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gcp.yaml @@ -0,0 +1,29 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +# gcp.resourceLocations: +# rules: +# - allow: +# values: +# - "global" +# - "in:eu-locations" +# - "in:europe-west1-locations" +# - "in:europe-west4-locations" + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gke.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gke.yaml new file mode 100644 index 000000000..d85766ead --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/gke.yaml @@ -0,0 +1,112 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +container.managed.disableABAC: + rules: + - enforce: true + +container.managed.disableLegacyClientCertificateIssuance: + rules: + - enforce: true + +container.managed.enableCloudLogging: + rules: + - enforce: true + +container.managed.enableNetworkPolicy: + rules: + - enforce: true + +container.managed.enablePrivateNodes: + rules: + - enforce: true + +container.managed.enableShieldedNodes: + rules: + - enforce: true + +container.managed.enableWorkloadIdentityFederation: + rules: + - enforce: true + +custom.gkeAllowedNodePoolImages: + rules: + - enforce: true + +custom.gkeAllowedReleaseChannels: + rules: + - enforce: true + +custom.gkeDisableAlphaCluster: + rules: + - enforce: true + +custom.gkeDisableKubernetesDashboard: + rules: + - enforce: true + +custom.gkeDisableLegacyAbac: + rules: + - enforce: true + +custom.gkeDisableLegacyMetadataEndpoints: + rules: + - enforce: true + +custom.gkeRequireCOSImage: + rules: + - enforce: true + +custom.gkeRequireDataplaneV2: + rules: + - enforce: true + +custom.gkeRequireGKEMetadataServer: + rules: + - enforce: true + +custom.gkeRequireIntegrityMonitoring: + rules: + - enforce: true + +custom.gkeRequireMonitoring: + rules: + - enforce: true + +custom.gkeRequireNodePoolAutoRepair: + rules: + - enforce: true + +custom.gkeRequireNodePoolAutoUpgrade: + rules: + - enforce: true + +custom.gkeRequireRegionalClusters: + rules: + - enforce: true + +custom.gkeRequireSecureBoot: + rules: + - enforce: true + +custom.gkeRequireVPCNativeCluster: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/iam.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/iam.yaml new file mode 100644 index 000000000..5784dc49b --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/iam.yaml @@ -0,0 +1,68 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +iam.allowedPolicyMemberDomains: + rules: + - allow: + values: + - is:${organization.customer_id} + condition: + title: Restrict member domains + expression: | + !resource.matchTag('${organization.id}/org-policies', 'allowed-policy-member-domains-all') + - allow: + all: true + condition: + title: Allow any member domain + expression: | + resource.matchTag('${organization.id}/org-policies', 'allowed-policy-member-domains-all') + +iam.disableAuditLoggingExemption: + rules: + - enforce: true + +iam.disableServiceAccountKeyCreation: + rules: + - enforce: true + +iam.disableServiceAccountKeyUpload: + rules: + - enforce: true + +iam.managed.disableServiceAccountApiKeyCreation: + rules: + - enforce: true + +iam.serviceAccountKeyExposureResponse: + rules: + - allow: + values: + - "is:DISABLE_KEY" + +iam.workloadIdentityPoolAwsAccounts: + rules: + - deny: + all: true + +iam.workloadIdentityPoolProviders: + rules: + - deny: + all: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/network.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/network.yaml new file mode 100644 index 000000000..0d1bd0c27 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/network.yaml @@ -0,0 +1,50 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +compute.restrictDedicatedInterconnectUsage: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + +compute.restrictPartnerInterconnectUsage: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + +compute.restrictVpcPeering: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + +custom.networkDisableTargetHTTPProxy: + rules: + - enforce: true + +custom.networkDisableWeakSSLPolicy: + rules: + - enforce: true + +custom.networkRequireCustomModeVpc: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/serverless.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/serverless.yaml new file mode 100644 index 000000000..b7e9ba0eb --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/serverless.yaml @@ -0,0 +1,56 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +cloudfunctions.allowedVpcConnectorEgressSettings: + rules: + - allow: + values: + - "ALL_TRAFFIC" + +cloudfunctions.requireVPCConnector: + rules: + - enforce: true + +custom.cloudrunDisableEnvironmentVariablePattern: + rules: + - enforce: true + +run.allowedBinaryAuthorizationPolicies: + rules: + - allow: + values: + - "default" + +run.allowedIngress: + rules: + - allow: + values: + - "is:internal-and-cloud-load-balancing" + +run.allowedVPCEgress: + rules: + - allow: + values: + - "all-traffic" + +run.managed.requireInvokerIam: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/sql.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/sql.yaml new file mode 100644 index 000000000..37ccbbd7b --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/sql.yaml @@ -0,0 +1,64 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +custom.cloudsqlDisablePublicAuthorizedNetworks: + rules: + - enforce: true + +custom.cloudsqlEnforcePasswordComplexity: + rules: + - enforce: true + +custom.cloudsqlRequireAutomatedBackup: + rules: + - enforce: true + +custom.cloudsqlRequireMySQLDatabaseFlags: + rules: + - enforce: true + +custom.cloudsqlRequirePointInTimeRecovery: + rules: + - enforce: true + +custom.cloudsqlRequirePostgreSQLDatabaseFlags: + rules: + - enforce: true + +custom.cloudsqlRequireRootPassword: + rules: + - enforce: true + +custom.cloudsqlRequireSQLServerDatabaseFlags: + rules: + - enforce: true + +custom.cloudsqlRequireSSLConnection: + rules: + - enforce: true + +sql.restrictAuthorizedNetworks: + rules: + - enforce: true + +sql.restrictPublicIp: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/storage.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/storage.yaml new file mode 100644 index 000000000..612e8e174 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/storage.yaml @@ -0,0 +1,38 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +storage.publicAccessPrevention: + rules: + - enforce: true + +storage.restrictAuthTypes: + rules: + - deny: + values: + - "in:ALL_HMAC_SIGNED_REQUESTS" + +storage.secureHttpTransport: + rules: + - enforce: true + +storage.uniformBucketLevelAccess: + rules: + - enforce: true + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/vertexai.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/vertexai.yaml new file mode 100644 index 000000000..bf6171952 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/org-policies/vertexai.yaml @@ -0,0 +1,38 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +# sample subset of useful organization policies, edit to suit requirements +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/org-policies.schema.json + +ainotebooks.disableFileDownloads: + rules: + - enforce: true + +ainotebooks.disableRootAccess: + rules: + - enforce: true + +ainotebooks.restrictPublicIp: + rules: + - enforce: true + +ainotebooks.restrictVpcNetworks: + rules: + - allow: + values: + - "under:organizations/${organization.id}" + diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireIngressInternalAndLoadBalancer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireIngressInternalAndLoadBalancer.yaml new file mode 100644 index 000000000..2fb646ea1 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireIngressInternalAndLoadBalancer.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cloudfunctionsV1RequireIngressInternalAndLoadBalancer: + description: Detect if Gen1 Cloud Functions are not configured to allow only internal + traffic and traffic from load balancer + predicate: + expression: (!resource.ingressSettings.matches("ALLOW_INTERNAL_AND_GCLB")) + recommendation: Ensure Gen1 Cloud Functions are configured to allow only internal + traffic and traffic from load balancer + resource_selector: + resource_types: + - cloudfunctions.googleapis.com/CloudFunction + severity: MEDIUM diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireVPCConnector.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireVPCConnector.yaml new file mode 100644 index 000000000..516ee36c2 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudfunctionsV1RequireVPCConnector.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cloudfunctionsV1RequireVPCConnector: + description: Detect if Gen1 Cloud Functions are configured without any VPC Connector + predicate: + expression: (!has(resource.vpcConnector)) + recommendation: Ensure Gen1 Cloud Functions are configured with VPC Connector + resource_selector: + resource_types: + - cloudfunctions.googleapis.com/CloudFunction + severity: MEDIUM diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireBinaryAuthorization.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireBinaryAuthorization.yaml new file mode 100644 index 000000000..108d91494 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireBinaryAuthorization.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cloudrunRequireBinaryAuthorization: + description: Detect if Cloud Run services are configured without Binary Authorization + enabled + predicate: + expression: (!resource.metadata.annotations.exists(data, data == 'run.googleapis.com/binary-authorization')) + recommendation: Ensure that Binary Authorization is enabled for all Cloud Run services + and that the project's default Binary Authorization policy requires attestation + resource_selector: + resource_types: + - run.googleapis.com/Job + - run.googleapis.com/Service + severity: HIGH diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireIngressInternalAndLoadBalancer.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireIngressInternalAndLoadBalancer.yaml new file mode 100644 index 000000000..2223c065e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudrunRequireIngressInternalAndLoadBalancer.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cloudrunRequireIngressInternalAndLoadBalancer: + description: Detect if Cloud Run services are not configured to allow only internal + traffic and traffic from load balancer + predicate: + expression: (!resource.metadata.annotations['run.googleapis.com/ingress'].matches('internal-and-cloud-load-balancing')) + recommendation: Ensure Cloud Run services are configured to allow only internal + traffic and traffic from load balancer + resource_selector: + resource_types: + - run.googleapis.com/Service + severity: HIGH diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudsqlRequirePointInTimeRecovery.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudsqlRequirePointInTimeRecovery.yaml new file mode 100644 index 000000000..c0b38dc0b --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/cloudsqlRequirePointInTimeRecovery.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cloudsqlRequirePointInTimeRecovery: + description: Detect if the CloudSQL instances have point in time recovery disabled + predicate: + expression: (!resource.settings.backupConfiguration.binaryLogEnabled && !resource.settings.backupConfiguration.pointInTimeRecoveryEnabled + ) + recommendation: Ensure the CloudSQL instances have point in time recovery enabled + resource_selector: + resource_types: + - sqladmin.googleapis.com/Instance + severity: HIGH diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/computeDisableNestedVirtualization.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/computeDisableNestedVirtualization.yaml new file mode 100644 index 000000000..31ad54aa8 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/computeDisableNestedVirtualization.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +computeDisableNestedVirtualization: + description: Detect Compute Instances with nested virtualization enabled + predicate: + expression: resource.advancedMachineFeatures.enableNestedVirtualization + recommendation: Ensure Compute Instance does not have nested virtualization enabled + resource_selector: + resource_types: + - compute.googleapis.com/Instance + severity: MEDIUM diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeDisableClientCertificateAuth.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeDisableClientCertificateAuth.yaml new file mode 100644 index 000000000..a9d6b510c --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeDisableClientCertificateAuth.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +gkeDisableClientCertificateAuth: + description: Detect if any GKE clusters uses client certificate authentication + predicate: + expression: resource.masterAuth.clientCertificateConfig.issueClientCertificate + == true + recommendation: Ensure that control plane does not use client certificate authentication + resource_selector: + resource_types: + - container.googleapis.com/Cluster + severity: CRITICAL diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireDataplaneV2.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireDataplaneV2.yaml new file mode 100644 index 000000000..c574f034a --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireDataplaneV2.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +gkeRequireDataplaneV2: + description: Detect if GKE clusters are configured with a version different than + Dataplane V2 + predicate: + expression: resource.networkConfig.datapathProvider == 'ADVANCED_DATAPATH' + recommendation: Ensure only GKE Dataplane V2 are configured + resource_selector: + resource_types: + - container.googleapis.com/Cluster + severity: MEDIUM diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireRegionalCluster.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireRegionalCluster.yaml new file mode 100644 index 000000000..1238a185e --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/scc-sha-custom-modules/gkeRequireRegionalCluster.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +gkeRequireRegionalCluster: + description: Detect if any non regional GKE clusters are used + predicate: + expression: (!resource.location.matches("^[a-z]+(-[a-z, 1-9]+)$")) + recommendation: Ensure GKE clusters are configured to be regional + resource_selector: + resource_types: + - container.googleapis.com/Cluster + severity: MEDIUM diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/tags/context.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/tags/context.yaml new file mode 100644 index 000000000..0ecf1c1a5 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/tags/context.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/tags.schema.json + +description: "Organization-level contexts." +# iam: +# "roles/resourcemanager.tagViewer": +# - "group:finance-team@example.com" +values: + project-factory: + description: "Project factory." diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/tags/environment.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/tags/environment.yaml new file mode 100644 index 000000000..f004043f6 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/tags/environment.yaml @@ -0,0 +1,43 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/tags.schema.json + +description: "Organization-level environments." +# iam: +# "roles/resourcemanager.tagViewer": +# - "group:finance-team@example.com" +values: + development: + description: "Development." + iam: + "roles/resourcemanager.tagUser": + - $iam_principals:service_accounts/iac-0/iac-networking-rw + - $iam_principals:service_accounts/iac-0/iac-security-rw + - $iam_principals:service_accounts/iac-0/iac-pf-rw + "roles/resourcemanager.tagViewer": + - $iam_principals:service_accounts/iac-0/iac-networking-ro + - $iam_principals:service_accounts/iac-0/iac-security-ro + - $iam_principals:service_accounts/iac-0/iac-pf-ro + production: + description: "Production." + iam: + "roles/resourcemanager.tagUser": + - $iam_principals:service_accounts/iac-0/iac-networking-rw + - $iam_principals:service_accounts/iac-0/iac-security-rw + - $iam_principals:service_accounts/iac-0/iac-pf-rw + "roles/resourcemanager.tagViewer": + - $iam_principals:service_accounts/iac-0/iac-networking-ro + - $iam_principals:service_accounts/iac-0/iac-security-ro + - $iam_principals:service_accounts/iac-0/iac-pf-ro diff --git a/fast/stages/0-org-setup/datasets/hardened/organization/tags/org-policies.yaml b/fast/stages/0-org-setup/datasets/hardened/organization/tags/org-policies.yaml new file mode 100644 index 000000000..ebf85412f --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/organization/tags/org-policies.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/tags.schema.json + +description: "Organization policy condition tags." +# iam: +# "roles/resourcemanager.tagViewer": +# - "group:finance-team@example.com" +values: + allowed-essential-contacts-domains-all: + description: "Allow all domains in essntial contacts org policy." + allowed-policy-member-domains-all: + description: "Allow all domains in DRS org policy." diff --git a/fast/stages/0-org-setup/datasets/hardened/projects/core/billing-0.yaml b/fast/stages/0-org-setup/datasets/hardened/projects/core/billing-0.yaml new file mode 100644 index 000000000..29070bbc2 --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/projects/core/billing-0.yaml @@ -0,0 +1,29 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/project.schema.json + +name: prod-billing-exp-0 +iam_by_principals: + $iam_principals:service_accounts/iac-0/iac-org-ro: + - roles/viewer + $iam_principals:service_accounts/iac-0/iac-org-rw: + - roles/owner +services: + - bigquery.googleapis.com + - bigquerydatatransfer.googleapis.com + - storage.googleapis.com +datasets: + billing_export: + friendly_name: Billing export diff --git a/fast/stages/0-org-setup/datasets/hardened/projects/core/iac-0.yaml b/fast/stages/0-org-setup/datasets/hardened/projects/core/iac-0.yaml new file mode 100644 index 000000000..9f9aa24cb --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/projects/core/iac-0.yaml @@ -0,0 +1,179 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/project.schema.json + +# TODO: data access logs configuration +name: prod-iac-core-0 +iam_by_principals: + $iam_principals:gcp-organization-admins: + - roles/iam.serviceAccountTokenCreator + - roles/iam.workloadIdentityPoolAdmin + $iam_principals:service_accounts/iac-0/iac-org-ro: + - roles/browser + - roles/cloudbuild.builds.viewer + - roles/iam.serviceAccountViewer + - roles/iam.workloadIdentityPoolViewer + - $custom_roles:storage_viewer + - roles/viewer + $iam_principals:service_accounts/iac-0/iac-org-rw: + - roles/cloudbuild.builds.editor + - roles/iam.serviceAccountAdmin + - roles/iam.workloadIdentityPoolAdmin + - roles/owner + - roles/storage.admin +services: + - accesscontextmanager.googleapis.com + - bigquery.googleapis.com + - bigqueryreservation.googleapis.com + - bigquerystorage.googleapis.com + - billingbudgets.googleapis.com + - cloudasset.googleapis.com + - cloudbilling.googleapis.com + - cloudbuild.googleapis.com + - cloudkms.googleapis.com + - cloudquotas.googleapis.com + - cloudresourcemanager.googleapis.com + - compute.googleapis.com + - container.googleapis.com + - datacatalog.googleapis.com + - essentialcontacts.googleapis.com + - iam.googleapis.com + - iamcredentials.googleapis.com + - logging.googleapis.com + - monitoring.googleapis.com + - networksecurity.googleapis.com + - orgpolicy.googleapis.com + - pubsub.googleapis.com + - securitycentermanagement.googleapis.com + - servicenetworking.googleapis.com + - serviceusage.googleapis.com + - storage-component.googleapis.com + - storage.googleapis.com + - sts.googleapis.com +org_policies: + iam.workloadIdentityPoolProviders: + rules: + - allow: + values: + - https://token.actions.githubusercontent.com + - https://gitlab.com + - https://app.terraform.io +buckets: + # Terraform state bucket for this stage + iac-org-state: + description: Terraform state for the org-level automation. + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-org-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-org-ro + # Terraform state bucket for additional FAST stages + iac-stage-state: + description: Terraform state for stage automation. + managed_folders: + 1-vpcsc: + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-vpcsc-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-vpcsc-ro + 2-networking: + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-networking-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-networking-ro + 2-security: + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-security-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-security-ro + 2-project-factory: + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-pf-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-pf-ro + 3-data-platform-dev: + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-dp-dev-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-dp-dev-ro + # Terraform state bucket for FAST outputs + iac-outputs: + description: Terraform state for the org-level automation. + iam: + roles/storage.admin: + - $iam_principals:service_accounts/iac-0/iac-org-rw + - $iam_principals:service_accounts/iac-0/iac-dp-dev-rw + - $iam_principals:service_accounts/iac-0/iac-networking-rw + - $iam_principals:service_accounts/iac-0/iac-security-rw + - $iam_principals:service_accounts/iac-0/iac-pf-rw + - $iam_principals:service_accounts/iac-0/iac-vpcsc-rw + $custom_roles:storage_viewer: + - $iam_principals:service_accounts/iac-0/iac-org-ro + - $iam_principals:service_accounts/iac-0/iac-dp-dev-ro + - $iam_principals:service_accounts/iac-0/iac-networking-ro + - $iam_principals:service_accounts/iac-0/iac-security-ro + - $iam_principals:service_accounts/iac-0/iac-pf-ro + - $iam_principals:service_accounts/iac-0/iac-vpcsc-ro + - $iam_principals:service_accounts/iac-0/iac-org-cicd-rw + - $iam_principals:service_accounts/iac-0/iac-org-cicd-ro +service_accounts: + # IaC service accounts for this stage + iac-org-ro: + display_name: IaC service account for org setup (read-only). + iac-org-rw: + display_name: IaC service account for org setup (read-write). + # CI/CD service accounts for this stage + iac-org-cicd-ro: + display_name: IaC service account for org setup CI/CD (read-only). + iam_sa_roles: + $service_account_ids:iac-0/iac-org-ro: + - roles/iam.workloadIdentityUser + - roles/iam.serviceAccountTokenCreator + iac-org-cicd-rw: + display_name: IaC service account for org setup CI/CD (read-write). + iam_sa_roles: + $service_account_ids:iac-0/iac-org-rw: + - roles/iam.workloadIdentityUser + - roles/iam.serviceAccountTokenCreator + # IaC service accounts for vpc-sc stage + iac-vpcsc-ro: + display_name: IaC service account for VPC service controls (read-only). + iac-vpcsc-rw: + display_name: IaC service account for VPC service controls (read-write). + # IaC service accounts for networking stage + iac-networking-ro: + display_name: IaC service account for networking (read-only). + iac-networking-rw: + display_name: IaC service account for networking (read-write). + # IaC service accounts for security stage + iac-security-ro: + display_name: IaC service account for security (read-only). + iac-security-rw: + display_name: IaC service account for security (read-write). + # IaC service accounts for project factory stage + iac-pf-ro: + display_name: IaC service account for project factory (read-only). + iac-pf-rw: + display_name: IaC service account for project factory (read-write). + # IaC service accounts for data platform (dev) stage + iac-dp-dev-ro: + display_name: IaC service account for data platform dev (read-only). + iac-dp-dev-rw: + display_name: IaC service account for data platform dev (read-write). diff --git a/fast/stages/0-org-setup/datasets/hardened/projects/core/log-0.yaml b/fast/stages/0-org-setup/datasets/hardened/projects/core/log-0.yaml new file mode 100644 index 000000000..71088bf2d --- /dev/null +++ b/fast/stages/0-org-setup/datasets/hardened/projects/core/log-0.yaml @@ -0,0 +1,35 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../../schemas/project.schema.json + +name: prod-audit-logs-0 +iam_by_principals: + $iam_principals:service_accounts/iac-0/iac-org-ro: + - roles/viewer + $iam_principals:service_accounts/iac-0/iac-org-rw: + - roles/owner +services: + - logging.googleapis.com + - pubsub.googleapis.com + - storage.googleapis.com +log_buckets: + audit-logs: {} + iam: {} + vpc-sc: + log_analytics: + enable: true + retention: 31 +factories_config: + observability: datasets/hardened/organization/observability/ diff --git a/fast/stages/0-org-setup/organization.tf b/fast/stages/0-org-setup/organization.tf index 582f67b21..3a6064d76 100644 --- a/fast/stages/0-org-setup/organization.tf +++ b/fast/stages/0-org-setup/organization.tf @@ -85,6 +85,7 @@ module "organization" { org_policy_custom_constraints = "${local.paths.organization}/custom-constraints" custom_roles = "${local.paths.organization}/custom-roles" tags = "${local.paths.organization}/tags" + scc_sha_custom_modules = "${local.paths.organization}/scc-sha-custom-modules" } tags_config = { ignore_iam = true diff --git a/fast/stages/1-vpcsc/README.md b/fast/stages/1-vpcsc/README.md index f539e1142..b7528d6fb 100644 --- a/fast/stages/1-vpcsc/README.md +++ b/fast/stages/1-vpcsc/README.md @@ -45,7 +45,7 @@ The stage is designed to allow defining additional perimeters via the `perimeter Restricted services, access levels, ingress and egress policies can all be configured via YAML-based files, which allow intuitive editing and minimize the complexity of running operations. -The default setup only contains a single access level and an initial list of restricted services in the `data/access-levels` folder and the `data/restricted-services.yaml` file. +The default setup only contains a single access level and an initial list of restricted services in the `datasets/classic/access-levels` folder and the `datasets/classic/restricted-services.yaml` file. To configure ingress and egress policies simply add `ingress_policies` and/or `egress_policies` folders under `data`, or point the factories to your own folders by changing the `factories_config` variable values. @@ -55,7 +55,7 @@ Examples on how to write access level and policy YAML files are provided further The way we set up the perimeter for broad access is via a single geo-based access level, which is configured to allow access from one or more countries and deny all other traffic coming from outside the perimeter. -The [`data/access-levels/geo.yaml`](data/access-levels/geo.yaml) file serves as an example and **should be edited to contain the countries you need** (or replaced/removed for more granular configuration). +The [`datasets/classic/access-levels/geo.yaml`](datasets/classic/access-levels/geo.yaml) file serves as an example and **should be edited to contain the countries you need** (or replaced/removed for more granular configuration). ```yaml conditions: @@ -167,7 +167,7 @@ The stage creates the org-level access policy by default. A pre-existing policy The default perimeter is exposed via the `perimeters.default` variable which allows customizing most of its features. -The only exception is the list of restricted services, which is configured via a YAML file with a list of services. To configure restricted services edit the list in `data/restricted-services.yaml`, or set the list of services in the `restricted_services` perimeter attribute. +The only exception is the list of restricted services, which is configured via a YAML file with a list of services. To configure restricted services edit the list in `datasets/classic/restricted-services.yaml`, or set the list of services in the `restricted_services` perimeter attribute. Note that it's not enough to define access levels and ingress/egress policies via their variables or via factory files: in order for them to be deployed they also need to be referenced by name in the perimeter via the attributes shown in this example. @@ -220,14 +220,14 @@ access_levels = { And the same defined instead via factory files. ```yaml -# data/access-levels/a1.yaml +# datasets/classic/access-levels/a1.yaml conditions: - members: - "user:user1@example.com" ``` ```yaml -# data/access-levels/a2.yaml +# datasets/classic/access-levels/a2.yaml combining_function: OR conditions: - regions: @@ -246,7 +246,7 @@ Like access levels, ingress and egress policies can be defined via tfvars or fac This is an example ingress policy defined in yaml: ```yaml -# data/ingress-policies/sa-tf-test.yaml +# datasets/classic/ingress-policies/sa-tf-test.yaml from: access_levels: - "*" @@ -265,7 +265,7 @@ to: And this is an example egress policy: ```yaml -# data/egress-policies/gcs-sa-foo.yaml +# datasets/classic/egress-policies/gcs-sa-foo.yaml from: identities: - serviceAccount:foo@myproject.iam.gserviceaccount.com @@ -307,7 +307,7 @@ Some references that might be useful in setting up this stage: | [access_policy](variables.tf#L67) | Access policy id (used for tenant-level VPC-SC configurations). | number | | null | | | [context](variables.tf#L73) | External context used in replacements. | object({…}) | | {} | | | [egress_policies](variables.tf#L85) | Egress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | | -| [factories_config](variables.tf#L128) | Paths to folders that enable factory functionality. | object({…}) | | {} | | +| [factories_config](variables.tf#L128) | Paths to folders that enable factory functionality. | object({…}) | | {} | | | [iam_principals](variables-fast.tf#L26) | Org-level IAM principals. | map(string) | | {} | 0-org-setup | | [ingress_policies](variables.tf#L141) | Ingress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | | | [logging](variables-fast.tf#L34) | Log writer identities for organization / folders. | object({…}) | | null | 0-org-setup | diff --git a/fast/stages/1-vpcsc/data/access-levels/geo.yaml b/fast/stages/1-vpcsc/datasets/classic/access-levels/geo.yaml similarity index 90% rename from fast/stages/1-vpcsc/data/access-levels/geo.yaml rename to fast/stages/1-vpcsc/datasets/classic/access-levels/geo.yaml index 96a3d6857..55d2e40e7 100644 --- a/fast/stages/1-vpcsc/data/access-levels/geo.yaml +++ b/fast/stages/1-vpcsc/datasets/classic/access-levels/geo.yaml @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -# yaml-language-server: $schema=../../schemas/access-level.schema.json +# yaml-language-server: $schema=../../../schemas/access-level.schema.json # this is just an example that reflects the FAST core team members' locations # and needs to be edited, or not referenced in the perimeter variable conditions: - regions: - ES + - ID - IT diff --git a/fast/stages/1-vpcsc/data/ingress-policies/fast-org-log-sinks.yaml b/fast/stages/1-vpcsc/datasets/classic/ingress-policies/fast-org-log-sinks.yaml similarity index 90% rename from fast/stages/1-vpcsc/data/ingress-policies/fast-org-log-sinks.yaml rename to fast/stages/1-vpcsc/datasets/classic/ingress-policies/fast-org-log-sinks.yaml index 1efc9cf13..42bb2d59a 100644 --- a/fast/stages/1-vpcsc/data/ingress-policies/fast-org-log-sinks.yaml +++ b/fast/stages/1-vpcsc/datasets/classic/ingress-policies/fast-org-log-sinks.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# yaml-language-server: $schema=../../schemas/ingress-policy.schema.json +# yaml-language-server: $schema=../../../schemas/ingress-policy.schema.json from: access_levels: diff --git a/fast/stages/1-vpcsc/data/perimeters/default.yaml b/fast/stages/1-vpcsc/datasets/classic/perimeters/default.yaml similarity index 91% rename from fast/stages/1-vpcsc/data/perimeters/default.yaml rename to fast/stages/1-vpcsc/datasets/classic/perimeters/default.yaml index 8e9d59cbd..877c32a75 100644 --- a/fast/stages/1-vpcsc/data/perimeters/default.yaml +++ b/fast/stages/1-vpcsc/datasets/classic/perimeters/default.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# yaml-language-server: $schema=../../schemas/perimeter.schema.json +# yaml-language-server: $schema=../../../schemas/perimeter.schema.json use_explicit_dry_run_spec: true spec: diff --git a/fast/stages/1-vpcsc/data/restricted-services.yaml b/fast/stages/1-vpcsc/datasets/classic/restricted-services.yaml similarity index 100% rename from fast/stages/1-vpcsc/data/restricted-services.yaml rename to fast/stages/1-vpcsc/datasets/classic/restricted-services.yaml diff --git a/fast/stages/1-vpcsc/datasets/hardened/access-levels/geo.yaml b/fast/stages/1-vpcsc/datasets/hardened/access-levels/geo.yaml new file mode 100644 index 000000000..55d2e40e7 --- /dev/null +++ b/fast/stages/1-vpcsc/datasets/hardened/access-levels/geo.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../schemas/access-level.schema.json + +# this is just an example that reflects the FAST core team members' locations +# and needs to be edited, or not referenced in the perimeter variable +conditions: + - regions: + - ES + - ID + - IT diff --git a/fast/stages/1-vpcsc/datasets/hardened/ingress-policies/fast-org-log-sinks.yaml b/fast/stages/1-vpcsc/datasets/hardened/ingress-policies/fast-org-log-sinks.yaml new file mode 100644 index 000000000..42bb2d59a --- /dev/null +++ b/fast/stages/1-vpcsc/datasets/hardened/ingress-policies/fast-org-log-sinks.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../schemas/ingress-policy.schema.json + +from: + access_levels: + - "*" + identities: + - $identity_sets:logging_identities +to: + operations: + - service_name: "*" + resources: + - $resource_sets:logging_project diff --git a/fast/stages/1-vpcsc/datasets/hardened/perimeters/default.yaml b/fast/stages/1-vpcsc/datasets/hardened/perimeters/default.yaml new file mode 100644 index 000000000..eb32bb40c --- /dev/null +++ b/fast/stages/1-vpcsc/datasets/hardened/perimeters/default.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../../schemas/perimeter.schema.json + +status: + access_levels: + - geo + resources: + - $resource_sets:discovered_projects + ingress_policies: + - fast-org-log-sinks + restricted_services: + - $service_sets:restricted_services diff --git a/fast/stages/1-vpcsc/datasets/hardened/restricted-services.yaml b/fast/stages/1-vpcsc/datasets/hardened/restricted-services.yaml new file mode 100644 index 000000000..edfb7790c --- /dev/null +++ b/fast/stages/1-vpcsc/datasets/hardened/restricted-services.yaml @@ -0,0 +1,87 @@ +# skip boilerplate check +- accessapproval.googleapis.com +- adsdatahub.googleapis.com +- aiplatform.googleapis.com +- apigee.googleapis.com +- apigeeconnect.googleapis.com +- artifactregistry.googleapis.com +- assuredworkloads.googleapis.com +- automl.googleapis.com +- bigquery.googleapis.com +- bigquerydatatransfer.googleapis.com +- bigtable.googleapis.com +- binaryauthorization.googleapis.com +- cloudasset.googleapis.com +- cloudbuild.googleapis.com +- cloudfunctions.googleapis.com +- cloudkms.googleapis.com +- cloudprofiler.googleapis.com +- cloudresourcemanager.googleapis.com +- cloudsearch.googleapis.com +- cloudtrace.googleapis.com +- composer.googleapis.com +- compute.googleapis.com +- connectgateway.googleapis.com +- contactcenterinsights.googleapis.com +- container.googleapis.com +- containeranalysis.googleapis.com +- containerregistry.googleapis.com +- containerthreatdetection.googleapis.com +- datacatalog.googleapis.com +- dataflow.googleapis.com +- datafusion.googleapis.com +- dataproc.googleapis.com +- datastream.googleapis.com +- dialogflow.googleapis.com +- dlp.googleapis.com +- dns.googleapis.com +- documentai.googleapis.com +- eventarc.googleapis.com +- file.googleapis.com +- gameservices.googleapis.com +- gkeconnect.googleapis.com +- gkehub.googleapis.com +- healthcare.googleapis.com +- iam.googleapis.com +- iaptunnel.googleapis.com +- language.googleapis.com +- lifesciences.googleapis.com +- logging.googleapis.com +- managedidentities.googleapis.com +- memcache.googleapis.com +- meshca.googleapis.com +- metastore.googleapis.com +- ml.googleapis.com +- monitoring.googleapis.com +- networkconnectivity.googleapis.com +- networkmanagement.googleapis.com +- networksecurity.googleapis.com +- networkservices.googleapis.com +- notebooks.googleapis.com +- opsconfigmonitoring.googleapis.com +- osconfig.googleapis.com +- oslogin.googleapis.com +- privateca.googleapis.com +- pubsub.googleapis.com +- pubsublite.googleapis.com +- recaptchaenterprise.googleapis.com +- recommender.googleapis.com +- redis.googleapis.com +- run.googleapis.com +- secretmanager.googleapis.com +- servicecontrol.googleapis.com +- servicedirectory.googleapis.com +- spanner.googleapis.com +- speakerid.googleapis.com +- speech.googleapis.com +- sqladmin.googleapis.com +- storage.googleapis.com +- storagetransfer.googleapis.com +- texttospeech.googleapis.com +- tpu.googleapis.com +- trafficdirector.googleapis.com +- transcoder.googleapis.com +- translate.googleapis.com +- videointelligence.googleapis.com +- vision.googleapis.com +- vpcaccess.googleapis.com diff --git a/fast/stages/1-vpcsc/variables.tf b/fast/stages/1-vpcsc/variables.tf index 48cc09e6e..9065f6ac8 100644 --- a/fast/stages/1-vpcsc/variables.tf +++ b/fast/stages/1-vpcsc/variables.tf @@ -128,11 +128,11 @@ variable "egress_policies" { variable "factories_config" { description = "Paths to folders that enable factory functionality." type = object({ - access_levels = optional(string, "data/access-levels") - egress_policies = optional(string, "data/egress-policies") - ingress_policies = optional(string, "data/ingress-policies") - perimeters = optional(string, "data/perimeters") - restricted_services = optional(string, "data/restricted-services.yaml") + access_levels = optional(string, "datasets/classic/access-levels") + egress_policies = optional(string, "datasets/classic/egress-policies") + ingress_policies = optional(string, "datasets/classic/ingress-policies") + perimeters = optional(string, "datasets/classic/perimeters") + restricted_services = optional(string, "datasets/classic/restricted-services.yaml") }) nullable = false default = {} diff --git a/fast/stages/3-data-platform-dev/data-domains.tf b/fast/stages/3-data-platform-dev/data-domains.tf index 8e434611e..f14031d97 100644 --- a/fast/stages/3-data-platform-dev/data-domains.tf +++ b/fast/stages/3-data-platform-dev/data-domains.tf @@ -69,8 +69,11 @@ module "dd-folders" { }) } iam_by_principals = { - for k, v in each.value.folder_config.iam_by_principals : - lookup(var.factories_config.context.iam_principals, k, k) => v + for principal, roles_list in { + for k, v in each.value.folder_config.iam_by_principals : + lookup(var.factories_config.context.iam_principals, k, k) => v... + } : + principal => flatten(roles_list) } } @@ -179,8 +182,11 @@ module "dd-projects-iam" { } ) iam_by_principals = { - for k, v in each.value.project_config.iam_by_principals : - lookup(var.factories_config.context.iam_principals, k, k) => v + for principal, roles_list in { + for k, v in each.value.project_config.iam_by_principals : + lookup(var.factories_config.context.iam_principals, k, k) => v... + } : + principal => flatten(roles_list) } shared_vpc_service_config = ( each.value.project_config.shared_vpc_service_config == null diff --git a/fast/stages/3-data-platform-dev/main.tf b/fast/stages/3-data-platform-dev/main.tf index 22ca9af20..53c472f29 100644 --- a/fast/stages/3-data-platform-dev/main.tf +++ b/fast/stages/3-data-platform-dev/main.tf @@ -67,8 +67,11 @@ module "central-project" { }) } iam_by_principals = { - for k, v in var.central_project_config.iam_by_principals : - lookup(var.factories_config.context.iam_principals, k, k) => v + for principal, roles_list in { + for k, v in var.central_project_config.iam_by_principals : + lookup(var.factories_config.context.iam_principals, k, k) => v... + } : + principal => flatten(roles_list) } labels = { environment = var.stage_config.environment diff --git a/fast/stages/CLEANUP.md b/fast/stages/CLEANUP.md index 79898fa8c..a8c989d89 100644 --- a/fast/stages/CLEANUP.md +++ b/fast/stages/CLEANUP.md @@ -67,6 +67,8 @@ A minor glitch can surface running `terraform destroy`, where the service projec Just like before, we manually remove several resources (GCS buckets and BQ datasets). Note that `terrafom destroy` will fail. This is expected; just continue with the rest of the steps. +Also, you can't create a custom constraint with the same name than a previously deleted custom constraint. To avoid issues during next future reprovisionning, *it is recommended to remove from Terraform state custom constraints*. + ```bash cd $FAST_PWD/0-org-setup/ export FAST_BU=$(gcloud config list --format 'value(core.account)') @@ -82,6 +84,12 @@ for x in $(terraform state list | grep google_bigquery_dataset); do terraform state rm "$x"; done +# remove custom constraint to avoid future issue during reprovisionnning. +# comment this part if permanent removed is needed +for x in $(terraform state list | grep google_org_policy_custom_constraint); do + terraform state rm "$x"; +done + ## remove the providers file and migrate state rm 0-org-setup-providers.tf diff --git a/modules/organization/scc-sha-custom-modules.tf b/modules/organization/scc-sha-custom-modules.tf index e6c336e29..8eefe7739 100644 --- a/modules/organization/scc-sha-custom-modules.tf +++ b/modules/organization/scc-sha-custom-modules.tf @@ -65,4 +65,10 @@ resource "google_scc_management_organization_security_health_analytics_custom_mo severity = each.value.severity } enablement_state = each.value.enablement_state + + depends_on = [ + google_organization_iam_binding.authoritative, + google_organization_iam_binding.bindings, + google_organization_iam_member.bindings, + ] } \ No newline at end of file diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md index 139b42528..dcd837120 100644 --- a/modules/project-factory/README.md +++ b/modules/project-factory/README.md @@ -748,11 +748,11 @@ compute.disableSerialPortAccess: | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [factories_config](variables.tf#L169) | Path to folder with YAML resource description data files. | object({…}) | ✓ | | -| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} | -| [data_defaults](variables.tf#L36) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} | -| [data_merges](variables.tf#L106) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | -| [data_overrides](variables.tf#L125) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | +| [factories_config](variables.tf#L170) | Path to folder with YAML resource description data files. | object({…}) | ✓ | | +| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} | +| [data_defaults](variables.tf#L37) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} | +| [data_merges](variables.tf#L107) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | +| [data_overrides](variables.tf#L126) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | | [folders](variables-folders.tf#L17) | Folders data merged with factory data. | map(object({…})) | | {} | | [notification_channels](variables-billing.tf#L17) | Notification channels used by budget alerts. | map(object({…})) | | {} | | [projects](variables-projects.tf#L17) | Projects data merged with factory data. | map(object({…})) | | {} | diff --git a/modules/project-factory/projects.tf b/modules/project-factory/projects.tf index 759d36712..819a2afc7 100644 --- a/modules/project-factory/projects.tf +++ b/modules/project-factory/projects.tf @@ -49,6 +49,10 @@ locals { project_ids = { for k, v in module.projects : k => v.project_id } + ctx_log_buckets = merge(local.ctx.log_buckets, local.log_buckets) + log_buckets = { + for key, log_bucket in module.log-buckets : key => log_bucket.id + } projects_input = merge(var.projects, local._projects_output) } @@ -123,6 +127,7 @@ module "projects-iam" { folder_ids = local.ctx.folder_ids kms_keys = local.ctx.kms_keys iam_principals = local.ctx_iam_principals + log_buckets = local.ctx_log_buckets }) factories_config = { # we do anything that can refer to IAM and custom roles in this call diff --git a/modules/project-factory/variables.tf b/modules/project-factory/variables.tf index ce0cdd8a0..d32bf85ed 100644 --- a/modules/project-factory/variables.tf +++ b/modules/project-factory/variables.tf @@ -23,6 +23,7 @@ variable "context" { iam_principals = optional(map(string), {}) kms_keys = optional(map(string), {}) locations = optional(map(string), {}) + log_buckets = optional(map(string), {}) notification_channels = optional(map(string), {}) project_ids = optional(map(string), {}) tag_values = optional(map(string), {}) diff --git a/modules/project/README.md b/modules/project/README.md index 21e280f43..e3bb4d186 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1952,7 +1952,7 @@ alerts: | [billing_account](variables.tf#L23) | Billing account id. | string | | null | | [compute_metadata](variables.tf#L29) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string) | | {} | | [contacts](variables.tf#L36) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | -| [context](variables.tf#L43) | Context-specific interpolations. | object({…}) | | {} | +| [context](variables.tf#L43) | Context-specific interpolations. | object({…}) | | {} | | [custom_roles](variables.tf#L62) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | | [default_network_tier](variables.tf#L69) | Default compute network tier for the project. | string | | null | | [default_service_account](variables.tf#L75) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | diff --git a/modules/project/logging-metrics.tf b/modules/project/logging-metrics.tf index 03673a580..59dc7088e 100644 --- a/modules/project/logging-metrics.tf +++ b/modules/project/logging-metrics.tf @@ -71,7 +71,7 @@ resource "google_logging_metric" "metrics" { disabled = each.value.disabled bucket_name = try( # first try to check the context - var.context.logging_bucket_names[each.value.bucket_name], + var.context.log_buckets[each.value.bucket_name], # if nothing else, use the provided channel as is each.value.bucket_name ) diff --git a/modules/project/variables.tf b/modules/project/variables.tf index 5a0c33653..6b771c1c5 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -49,7 +49,7 @@ variable "context" { kms_keys = optional(map(string), {}) iam_principals = optional(map(string), {}) notification_channels = optional(map(string), {}) - logging_bucket_names = optional(map(string), {}) + log_buckets = optional(map(string), {}) project_ids = optional(map(string), {}) tag_keys = optional(map(string), {}) tag_values = optional(map(string), {}) diff --git a/tools/duplicate-diff.py b/tools/duplicate-diff.py index ef1219774..c4b8af5de 100755 --- a/tools/duplicate-diff.py +++ b/tools/duplicate-diff.py @@ -17,8 +17,19 @@ import filecmp import sys +import os -duplicates = [ # +# List of folders and files that are expected to have same content +duplicates = [ + # File comparison + [ + "fast/stages/0-org-setup/datasets/classic/defaults.yaml", + "fast/stages/0-org-setup/datasets/hardened/defaults.yaml", + ], + [ + "fast/stages/0-org-setup/datasets/classic/projects/core/billing-0.yaml", + "fast/stages/0-org-setup/datasets/hardened/projects/core/billing-0.yaml", + ], [ "fast/stages/2-networking-a-simple/data/dns-policy-rules.yaml", "fast/stages/2-networking-b-nva/data/dns-policy-rules.yaml", @@ -28,12 +39,76 @@ duplicates = [ # "fast/stages/2-networking-a-simple/data/cidrs.yaml", "fast/stages/2-networking-b-nva/data/cidrs.yaml", "fast/stages/2-networking-c-separate-envs/data/cidrs.yaml", - ] + ], + # Deep recursive folder comparison + [ + "fast/stages/0-org-setup/datasets/classic/organization/custom-roles", + "fast/stages/0-org-setup/datasets/hardened/organization/custom-roles", + ], + [ + "fast/stages/0-org-setup/datasets/classic/organization/tags", + "fast/stages/0-org-setup/datasets/hardened/organization/tags", + ], ] + +def check_dir_diff(dcmp): + """ + Recursively checks a filecmp.dircmp object for any differences. + Returns True if a difference is found, False otherwise. + """ + diff_found = False + + if dcmp.left_only: + print(f"[DIFF] Only in {dcmp.left}: {dcmp.left_only}") + diff_found = True + if dcmp.right_only: + print(f"[DIFF] Only in {dcmp.right}: {dcmp.right_only}") + diff_found = True + if dcmp.diff_files: + print(f"[DIFF] Mismatched files: {dcmp.diff_files}") + diff_found = True + + for sub_dcmp in dcmp.subdirs.values(): + if check_dir_diff(sub_dcmp): + diff_found = True + + return diff_found + + +has_diff = False for group in duplicates: first = group[0] + if not os.path.exists(first): + print(f"[ERROR] Path not found: {first}. Skipping group.") + has_diff = True + continue + + is_dir = os.path.isdir(first) for second in group[1:]: - if not filecmp.cmp(first, second): # true if files are the same - print(f'found diff between {first} and {second}') - sys.exit(1) + if not os.path.exists(second): + print(f"[DIFF] Path not found: {second}") + has_diff = True + continue + + if is_dir != os.path.isdir(second): + print(f"[DIFF] Type mismatch: {first} is {'DIR' if is_dir else 'FILE'}, " + f"but {second} is {'DIR' if os.path.isdir(second) else 'FILE'}.") + has_diff = True + continue + + if is_dir: + dcmp = filecmp.dircmp(first, second) + if check_dir_diff(dcmp): + print( + f"[DIFF] Found differences between directories {first} and {second}" + ) + has_diff = True + else: + if not filecmp.cmp(first, second, shallow=False): + print(f"[DIFF] Files are different: {first} and {second}") + has_diff = True + +if has_diff: + print("\nCheck finished: Found differences.") + sys.exit(1)