This commit is contained in:
lcaggio 2023-02-06 21:33:04 +01:00
parent 1e4499c8ab
commit d68bb4b320
4 changed files with 43 additions and 148 deletions

View File

@ -66,6 +66,6 @@ This [blueprint](./vertex-mlops/) implements the infrastructure required to have
### Shielded Folder
<a href="./shielded-folder/" title="Shielded Folder"><img src="./shielded-folder/images/overview_diagram.png" align="left" width="280px"></a>
This [blueprint](./shielded-folder/) implements an opinionated Folder configuration to implement GCP best practices. Configurations implemented on the folder would be beneficial to host Workloads inheriting constraints from the folder they belong to.
This [blueprint](./shielded-folder/) implements an opinionated folder configuration according to GCP best practices. Configurations implemented on the folder would be beneficial to host workloads inheriting constraints from the folder they belong to.
<br clear="left">
<br clear="left">

View File

@ -1,8 +1,8 @@
# Shielded folder
This blueprint implements an opinionated folder configuration to implement GCP best practices. Configurations implemented on the folder would be beneficial to host Workloads inheriting constraints from the folder they belong to.
This blueprint implements an opinionated folder configuration according to GCP best practices. Configurations at the folder level would be beneficial to host workloads inheriting constraints from the folder they belong to.
In this blueprint, a folder will be created implementing the following features:
In this blueprint, a folder will be created setting following features:
- Organizational policies
- Hierarchical firewall rules
@ -43,7 +43,7 @@ This separation into projects allows adhering to the least-privilege principle b
User groups provide a stable frame of reference that allows decoupling the final set of permissions from the stage where entities and resources are created, and their IAM bindings are defined.
We use three groups to control access to resources:
We use groups to control access to resources:
- `data-engineers`: They handle and run workloads on the `workload` subfolder. They have editor access to all resources in the `workload` folder in order to troubleshoot possible issues within the workload. This team can also impersonate any service account in the workload folder.
- `data-security`: They handle security configurations for the shielded folder. They have owner access to the `audit-log` and `sec-core` projects.
@ -116,9 +116,9 @@ The shielded Folfer blueprint assumes [groups described](#user-groups) are creat
### Variable configuration PIPPO
There are three sets of variables you will need to fill in:
There are several sets of variables you will need to fill in:
```hcl
```tfvars
access_policy_config = {
access_policy_create = {
parent = "organizations/1234567890123"
@ -136,10 +136,9 @@ organization = {
id = "1122334455"
}
prefix = "prefix"
project_config_2 = {
billing_account_id = "123456-123456-123456"
project_config = {
billing_account_id = "123456-123456-123456"
}
# tftest modules=8 resources=35
```
### Deploying the blueprint
@ -159,17 +158,17 @@ terraform apply
| [access_policy_config](variables.tf#L17) | Provide 'access_policy_create' values if a folder scoped Access Policy creation is needed, uses existing 'policy_name' otherwise. Parent is in 'organizations/123456' format. Policy will be created scoped to the folder. | <code title="object&#40;&#123;&#10; policy_name &#61; optional&#40;string, null&#41;&#10; access_policy_create &#61; optional&#40;object&#40;&#123;&#10; parent &#61; string&#10; title &#61; string&#10; &#125;&#41;, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [folder_config](variables.tf#L49) | Provide 'folder_create' values if folder creation is needed, uses existing 'folder_id' otherwise. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object&#40;&#123;&#10; folder_id &#61; optional&#40;string, null&#41;&#10; folder_create &#61; optional&#40;object&#40;&#123;&#10; display_name &#61; string&#10; parent &#61; string&#10; &#125;&#41;, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [organization](variables.tf#L124) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [prefix](variables.tf#L132) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | |
| [project_config](variables.tf#L141) | Provide 'billing_account_id' value if project creation is needed, uses existing 'projects_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object&#40;&#123;&#10; billing_account_id &#61; optional&#40;string, null&#41;&#10; project_ids &#61; optional&#40;object&#40;&#123;&#10; sec-core &#61; string&#10; audit-logs &#61; string&#10; &#125;&#41;, &#123;&#10; sec-core &#61; &#34;sec-core&#34;&#10; audit-logs &#61; &#34;audit-logs&#34;&#10; &#125;&#10; &#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [prefix](variables.tf#L132) | Prefix used for resources that need unique names. | <code>string</code> | ✓ | |
| [project_config](variables.tf#L137) | Provide 'billing_account_id' value if project creation is needed, uses existing 'project_ids' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object&#40;&#123;&#10; billing_account_id &#61; optional&#40;string, null&#41;&#10; project_ids &#61; optional&#40;object&#40;&#123;&#10; sec-core &#61; string&#10; audit-logs &#61; string&#10; &#125;&#41;, &#123;&#10; sec-core &#61; &#34;sec-core&#34;&#10; audit-logs &#61; &#34;audit-logs&#34;&#10; &#125;&#10; &#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [data_dir](variables.tf#L29) | Relative path for the folder storing configuration data. | <code>string</code> | | <code>&#34;data&#34;</code> |
| [enable_features](variables.tf#L35) | Flag to enable features on the solution. | <code title="object&#40;&#123;&#10; encryption &#61; optional&#40;bool, false&#41;&#10; log_sink &#61; optional&#40;bool, true&#41;&#10; vpc_sc &#61; optional&#40;bool, true&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; encryption &#61; false&#10; log_sink &#61; true&#10; vpc_sc &#61; true&#10;&#125;">&#123;&#8230;&#125;</code> |
| [groups](variables.tf#L61) | User groups. | <code title="object&#40;&#123;&#10; workload-engineers &#61; optional&#40;string, &#34;gcp-data-engineers&#34;&#41;&#10; workload-security &#61; optional&#40;string, &#34;gcp-data-security&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [kms_keys](variables.tf#L71) | KMS keys to create, keyed by name. | <code title="map&#40;object&#40;&#123;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;list&#40;string&#41;, &#91;&#34;global&#34;, &#34;europe&#34;, &#34;europe-west1&#34;&#93;&#41;&#10; rotation_period &#61; optional&#40;string, &#34;7776000s&#34;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [log_locations](variables.tf#L82) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object&#40;&#123;&#10; bq &#61; optional&#40;string, &#34;europe&#34;&#41;&#10; storage &#61; optional&#40;string, &#34;europe&#34;&#41;&#10; logging &#61; optional&#40;string, &#34;global&#34;&#41;&#10; pubsub &#61; optional&#40;string, &#34;global&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; bq &#61; &#34;europe&#34;&#10; storage &#61; &#34;europe&#34;&#10; logging &#61; &#34;global&#34;&#10; pubsub &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [log_sinks](variables.tf#L99) | Org-level log sinks, in name => {type, filter} format. | <code title="map&#40;object&#40;&#123;&#10; filter &#61; string&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code title="&#123;&#10; audit-logs &#61; &#123;&#10; filter &#61; &#34;logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Factivity&#92;&#34; OR logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Fsystem_event&#92;&#34;&#34;&#10; type &#61; &#34;bigquery&#34;&#10; &#125;&#10; vpc-sc &#61; &#123;&#10; filter &#61; &#34;protoPayload.metadata.&#64;type&#61;&#92;&#34;type.googleapis.com&#47;google.cloud.audit.VpcServiceControlAuditMetadata&#92;&#34;&#34;&#10; type &#61; &#34;bigquery&#34;&#10; &#125;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [vpc_sc_access_levels](variables.tf#L157) | VPC SC access level definitions. | <code title="map&#40;object&#40;&#123;&#10; combining_function &#61; optional&#40;string&#41;&#10; conditions &#61; optional&#40;list&#40;object&#40;&#123;&#10; device_policy &#61; optional&#40;object&#40;&#123;&#10; allowed_device_management_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; allowed_encryption_statuses &#61; optional&#40;list&#40;string&#41;&#41;&#10; require_admin_approval &#61; bool&#10; require_corp_owned &#61; bool&#10; require_screen_lock &#61; optional&#40;bool&#41;&#10; os_constraints &#61; optional&#40;list&#40;object&#40;&#123;&#10; os_type &#61; string&#10; minimum_version &#61; optional&#40;string&#41;&#10; require_verified_chrome_os &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#41;&#10; ip_subnetworks &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; members &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; negate &#61; optional&#40;bool&#41;&#10; regions &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; required_access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_sc_egress_policies](variables.tf#L186) | VPC SC egress policy defnitions. | <code title="map&#40;object&#40;&#123;&#10; from &#61; object&#40;&#123;&#10; identity_type &#61; optional&#40;string, &#34;ANY_IDENTITY&#34;&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; resource_type_external &#61; optional&#40;bool, false&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_sc_ingress_policies](variables.tf#L206) | VPC SC ingress policy defnitions. | <code title="map&#40;object&#40;&#123;&#10; from &#61; object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; identity_type &#61; optional&#40;string&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_sc_access_levels](variables.tf#L153) | VPC SC access level definitions. | <code title="map&#40;object&#40;&#123;&#10; combining_function &#61; optional&#40;string&#41;&#10; conditions &#61; optional&#40;list&#40;object&#40;&#123;&#10; device_policy &#61; optional&#40;object&#40;&#123;&#10; allowed_device_management_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; allowed_encryption_statuses &#61; optional&#40;list&#40;string&#41;&#41;&#10; require_admin_approval &#61; bool&#10; require_corp_owned &#61; bool&#10; require_screen_lock &#61; optional&#40;bool&#41;&#10; os_constraints &#61; optional&#40;list&#40;object&#40;&#123;&#10; os_type &#61; string&#10; minimum_version &#61; optional&#40;string&#41;&#10; require_verified_chrome_os &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#41;&#10; ip_subnetworks &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; members &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; negate &#61; optional&#40;bool&#41;&#10; regions &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; required_access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_sc_egress_policies](variables.tf#L182) | VPC SC egress policy defnitions. | <code title="map&#40;object&#40;&#123;&#10; from &#61; object&#40;&#123;&#10; identity_type &#61; optional&#40;string, &#34;ANY_IDENTITY&#34;&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; resource_type_external &#61; optional&#40;bool, false&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_sc_ingress_policies](variables.tf#L202) | VPC SC ingress policy defnitions. | <code title="map&#40;object&#40;&#123;&#10; from &#61; object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; identity_type &#61; optional&#40;string&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs

View File

@ -35,12 +35,12 @@ variable "data_dir" {
variable "enable_features" {
description = "Flag to enable features on the solution."
type = object({
encryption = optional(bool, true)
encryption = optional(bool, false)
log_sink = optional(bool, true)
vpc_sc = optional(bool, true)
})
default = {
encryption = true
encryption = false
log_sink = true
vpc_sc = true
}
@ -130,16 +130,12 @@ variable "organization" {
}
variable "prefix" {
description = "Prefix used for resources that need unique names. Use 9 characters or less."
description = "Prefix used for resources that need unique names."
type = string
validation {
condition = try(length(var.prefix), 0) < 10
error_message = "Use a maximum of 9 characters for prefix."
}
}
variable "project_config" {
description = "Provide 'billing_account_id' value if project creation is needed, uses existing 'projects_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format."
description = "Provide 'billing_account_id' value if project creation is needed, uses existing 'project_ids' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format."
type = object({
billing_account_id = optional(string, null)
project_ids = optional(object({

View File

@ -12,121 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# values:
# module.folder-workload.google_folder.folder[0]:
# display_name: prefix-workload
# timeouts: null
# module.folder.google_bigquery_dataset_iam_member.bq-sinks-binding["audit-logs"]:
# condition: []
# role: roles/bigquery.dataEditor
# module.folder.google_bigquery_dataset_iam_member.bq-sinks-binding["vpc-sc"]:
# condition: []
# role: roles/bigquery.dataEditor
# module.folder.google_folder.folder[0]:
# display_name: ShieldedMVP
# parent: organizations/1054601055974
# timeouts: null
# module.folder.google_folder_iam_binding.authoritative["roles/editor"]:
# condition: []
# members:
# - group:gcp-data-engineers@example.com
# role: roles/editor
# module.folder.google_logging_folder_sink.sink["audit-logs"]:
# description: audit-logs (Terraform-managed).
# disabled: false
# exclusions: []
# filter: logName:"/logs/cloudaudit.googleapis.com%2Factivity" OR logName:"/logs/cloudaudit.googleapis.com%2Fsystem_event"
# include_children: true
# name: audit-logs
# module.folder.google_logging_folder_sink.sink["vpc-sc"]:
# description: vpc-sc (Terraform-managed).
# disabled: false
# exclusions: []
# filter: protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
# include_children: true
# name: vpc-sc
# module.log-export-dataset[0].google_bigquery_dataset.default:
# dataset_id: prefix_audit_export
# default_encryption_configuration:
# - kms_key_name: 'false'
# default_partition_expiration_ms: null
# default_table_expiration_ms: null
# delete_contents_on_destroy: false
# description: Terraform managed.
# friendly_name: Audit logs export.
# location: EU
# max_time_travel_hours: null
# project: prefix-audit-logs
# timeouts: null
# module.log-export-project[0].data.google_bigquery_default_service_account.bq_sa[0]:
# project: prefix-audit-logs
# module.log-export-project[0].data.google_storage_project_service_account.gcs_sa[0]:
# project: prefix-audit-logs
# user_project: null
# module.log-export-project[0].google_project.project[0]:
# auto_create_network: false
# billing_account: 123456-123456-123456
# labels: null
# name: prefix-audit-logs
# project_id: prefix-audit-logs
# skip_delete: false
# timeouts: null
# module.log-export-project[0].google_project_service.project_services["bigquery.googleapis.com"]:
# disable_dependent_services: false
# disable_on_destroy: false
# project: prefix-audit-logs
# service: bigquery.googleapis.com
# timeouts: null
# module.log-export-project[0].google_project_service.project_services["pubsub.googleapis.com"]:
# disable_dependent_services: false
# disable_on_destroy: false
# project: prefix-audit-logs
# service: pubsub.googleapis.com
# timeouts: null
# module.log-export-project[0].google_project_service.project_services["stackdriver.googleapis.com"]:
# disable_dependent_services: false
# disable_on_destroy: false
# project: prefix-audit-logs
# service: stackdriver.googleapis.com
# timeouts: null
# module.log-export-project[0].google_project_service.project_services["storage.googleapis.com"]:
# disable_dependent_services: false
# disable_on_destroy: false
# project: prefix-audit-logs
# service: storage.googleapis.com
# timeouts: null
# module.log-export-project[0].google_project_service_identity.jit_si["pubsub.googleapis.com"]:
# project: prefix-audit-logs
# service: pubsub.googleapis.com
# timeouts: null
# module.vpc-sc[0].google_access_context_manager_access_policy.default[0]:
# parent: organizations/1122334455
# timeouts: null
# title: shielded-folder
# module.vpc-sc[0].google_access_context_manager_service_perimeter.regular["shielded"]:
# description: null
# perimeter_type: PERIMETER_TYPE_REGULAR
# spec:
# - access_levels: []
# egress_policies: []
# ingress_policies:
# - ingress_from:
# - identity_type: null
# sources:
# - access_level: '*'
# resource: null
# ingress_to:
# - operations:
# - method_selectors: []
# service_name: '*'
# restricted_services: null
# vpc_accessible_services:
# - allowed_services: null
# enable_restriction: true
# status: []
# timeouts: null
# title: shielded
# use_explicit_dry_run_spec: true
values:
module.folder.google_compute_firewall_policy.policy["prefix-fw-policy"]:
short_name: prefix-fw-policy
module.folder.google_folder.folder[0]:
display_name: ShieldedMVP
parent: organizations/1234567890123
module.log-export-project[0].google_project.project[0]:
billing_account: 123456-123456-123456
project_id: prefix-audit-logs
module.vpc-sc[0].google_access_context_manager_access_policy.default[0]:
parent: organizations/1122334455
title: shielded-folder
module.vpc-sc[0].google_access_context_manager_service_perimeter.regular["shielded"]:
description: null
perimeter_type: PERIMETER_TYPE_REGULAR
title: shielded
counts:
google_access_context_manager_access_policy: 1
@ -134,18 +35,17 @@ counts:
google_bigquery_dataset: 1
google_bigquery_dataset_iam_member: 2
google_bigquery_default_service_account: 1
google_compute_firewall_policy: 1
google_compute_firewall_policy_rule: 4
google_folder: 2
google_folder_iam_binding: 2
google_kms_crypto_key: 3
google_kms_crypto_key_iam_member: 3
google_kms_key_ring: 2
google_logging_folder_sink: 2
google_project: 2
google_project_iam_binding: 2
google_project_service: 7
google_project_service_identity: 2
google_org_policy_policy: 12
google_project: 1
google_project_iam_binding: 1
google_project_service: 4
google_project_service_identity: 1
google_projects: 1
google_storage_project_service_account: 1
modules: 8
resources: 52
modules: 5
resources: 38