Support additional attributes for buckets/datasets in project factory module (#3755)

* extend attributes for project factory secondary resources

* remove extra files

* complete

* tf fmt

* tfdoc

* schemas

* fix tests

* tfdoc
This commit is contained in:
Ludovico Magnocavallo
2026-02-20 12:57:59 +01:00
committed by GitHub
parent db8eecc999
commit 67b1543e90
21 changed files with 657 additions and 91 deletions

View File

@@ -55,8 +55,14 @@ module "bigquery-dataset" {
iam = {
"roles/bigquery.dataOwner" = ["user:user1@example.org"]
}
iam_bindings = {
reader_user = {
role = "roles/bigquery.dataViewer"
members = ["user:user2@example.org"]
}
}
}
# tftest modules=1 resources=2 inventory=iam.yaml
# tftest modules=1 resources=3 inventory=iam.yaml
```
## Authorized Views, Datasets, and Routines
@@ -353,27 +359,30 @@ module "bigquery-dataset" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [id](variables.tf#L112) | Dataset id. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L176) | Id of the project where datasets will be created. | <code>string</code> | ✓ | |
| [id](variables.tf#L111) | Dataset id. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L175) | Id of the project where datasets will be created. | <code>string</code> | ✓ | |
| [access](variables.tf#L17) | Map of access rules with role and identity type. Keys are arbitrary and must match those in the `access_identities` variable, types are `domain`, `group`, `special_group`, `user`, `view`. | <code title="map&#40;object&#40;&#123;&#10; role &#61; string&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [access_identities](variables.tf#L33) | Map of access identities used for basic access roles. View identities have the format 'project_id\|dataset_id\|table_id'. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [authorized_datasets](variables.tf#L39) | An array of datasets to be authorized on the dataset. | <code title="list&#40;object&#40;&#123;&#10; dataset_id &#61; string,&#10; project_id &#61; string,&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [authorized_routines](variables.tf#L48) | An array of routines to be authorized on the dataset. | <code title="list&#40;object&#40;&#123;&#10; project_id &#61; string,&#10; dataset_id &#61; string,&#10; routine_id &#61; string&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [authorized_views](variables.tf#L58) | An array of views to be authorized on the dataset. | <code title="list&#40;object&#40;&#123;&#10; dataset_id &#61; string,&#10; project_id &#61; string,&#10; table_id &#61; string &#35; this is the view id, but we keep table_id to stay consistent as the resource&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [context](variables.tf#L68) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; kms_keys &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; tag_values &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [dataset_access](variables.tf#L82) | Set access in the dataset resource instead of using separate resources. | <code>bool</code> | | <code>false</code> |
| [description](variables.tf#L88) | Optional description. | <code>string</code> | | <code>&#34;Terraform managed.&#34;</code> |
| [encryption_key](variables.tf#L94) | Self link of the KMS key that will be used to protect destination table. | <code>string</code> | | <code>null</code> |
| [friendly_name](variables.tf#L100) | Dataset friendly name. | <code>string</code> | | <code>null</code> |
| [iam](variables.tf#L106) | IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [labels](variables.tf#L117) | Dataset labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [location](variables.tf#L123) | Dataset location. | <code>string</code> | | <code>&#34;EU&#34;</code> |
| [materialized_views](variables.tf#L129) | Materialized views definitions. | <code title="map&#40;object&#40;&#123;&#10; query &#61; string&#10; allow_non_incremental_definition &#61; optional&#40;bool&#41;&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; enable_refresh &#61; optional&#40;bool&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; refresh_interval_ms &#61; optional&#40;bool&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; options &#61; optional&#40;object&#40;&#123;&#10; clustering &#61; optional&#40;list&#40;string&#41;&#41;&#10; expiration_time &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; partitioning &#61; optional&#40;object&#40;&#123;&#10; field &#61; optional&#40;string&#41;&#10; range &#61; optional&#40;object&#40;&#123;&#10; end &#61; number&#10; interval &#61; number&#10; start &#61; number&#10; &#125;&#41;&#41;&#10; time &#61; optional&#40;object&#40;&#123;&#10; type &#61; string&#10; expiration_ms &#61; optional&#40;number&#41;&#10; field &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [options](variables.tf#L162) | Dataset options. | <code title="object&#40;&#123;&#10; default_collation &#61; optional&#40;string&#41;&#10; default_table_expiration_ms &#61; optional&#40;number&#41;&#10; default_partition_expiration_ms &#61; optional&#40;number&#41;&#10; delete_contents_on_destroy &#61; optional&#40;bool, false&#41;&#10; is_case_insensitive &#61; optional&#40;bool&#41;&#10; max_time_travel_hours &#61; optional&#40;number, 168&#41;&#10; storage_billing_model &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [routines](variables.tf#L181) | Routine definitions. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; routine_type &#61; string&#10; language &#61; optional&#40;string&#41;&#10; definition_body &#61; string&#10; imported_libraries &#61; optional&#40;list&#40;string&#41;&#41;&#10; determinism_level &#61; optional&#40;string&#41;&#10; data_governance_type &#61; optional&#40;string&#41;&#10; return_type &#61; optional&#40;string&#41;&#10; return_table_type &#61; optional&#40;string&#41;&#10; arguments &#61; optional&#40;map&#40;object&#40;&#123;&#10; argument_kind &#61; optional&#40;string&#41;&#10; mode &#61; optional&#40;string&#41;&#10; data_type &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; spark_options &#61; optional&#40;object&#40;&#123;&#10; archive_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; connection &#61; string&#10; container_image &#61; optional&#40;string&#41;&#10; file_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; jar_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; main_file_uri &#61; optional&#40;string&#41;&#10; main_class &#61; optional&#40;string&#41;&#10; properties &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; py_file_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; runtime_version &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; remote_function_options &#61; optional&#40;object&#40;&#123;&#10; connection &#61; string&#10; endpoint &#61; optional&#40;string&#41;&#10; max_batching_rows &#61; optional&#40;string&#41;&#10; user_defined_context &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tables](variables.tf#L220) | Table definitions. Options and partitioning default to null. Partitioning can only use `range` or `time`, set the unused one to null. | <code title="map&#40;object&#40;&#123;&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; schema &#61; optional&#40;string&#41;&#10; external_data_configuration &#61; optional&#40;object&#40;&#123;&#10; autodetect &#61; bool&#10; source_uris &#61; list&#40;string&#41;&#10; avro_logical_types &#61; optional&#40;bool&#41;&#10; compression &#61; optional&#40;string&#41;&#10; connection_id &#61; optional&#40;string&#41;&#10; file_set_spec_type &#61; optional&#40;string&#41;&#10; ignore_unknown_values &#61; optional&#40;bool&#41;&#10; metadata_cache_mode &#61; optional&#40;string&#41;&#10; object_metadata &#61; optional&#40;string&#41;&#10; json_options_encoding &#61; optional&#40;string&#41;&#10; reference_file_schema_uri &#61; optional&#40;string&#41;&#10; schema &#61; optional&#40;string&#41;&#10; source_format &#61; optional&#40;string&#41;&#10; max_bad_records &#61; optional&#40;number&#41;&#10; csv_options &#61; optional&#40;object&#40;&#123;&#10; quote &#61; string&#10; allow_jagged_rows &#61; optional&#40;bool&#41;&#10; allow_quoted_newlines &#61; optional&#40;bool&#41;&#10; encoding &#61; optional&#40;string&#41;&#10; field_delimiter &#61; optional&#40;string&#41;&#10; skip_leading_rows &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; google_sheets_options &#61; optional&#40;object&#40;&#123;&#10; range &#61; optional&#40;string&#41;&#10; skip_leading_rows &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; hive_partitioning_options &#61; optional&#40;object&#40;&#123;&#10; mode &#61; optional&#40;string&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; source_uri_prefix &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; parquet_options &#61; optional&#40;object&#40;&#123;&#10; enum_as_string &#61; optional&#40;bool&#41;&#10; enable_list_inference &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10;&#10;&#10; &#125;&#41;&#41;&#10; options &#61; optional&#40;object&#40;&#123;&#10; clustering &#61; optional&#40;list&#40;string&#41;&#41;&#10; encryption_key &#61; optional&#40;string&#41;&#10; expiration_time &#61; optional&#40;number&#41;&#10; max_staleness &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; partitioning &#61; optional&#40;object&#40;&#123;&#10; field &#61; optional&#40;string&#41;&#10; range &#61; optional&#40;object&#40;&#123;&#10; end &#61; number&#10; interval &#61; number&#10; start &#61; number&#10; &#125;&#41;&#41;&#10; time &#61; optional&#40;object&#40;&#123;&#10; type &#61; string&#10; expiration_ms &#61; optional&#40;number&#41;&#10; field &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; table_constraints &#61; optional&#40;object&#40;&#123;&#10; primary_key_columns &#61; optional&#40;list&#40;string&#41;&#41;&#10; foreign_keys &#61; optional&#40;object&#40;&#123;&#10; referenced_table &#61; object&#40;&#123;&#10; project_id &#61; string&#10; dataset_id &#61; string&#10; table_id &#61; string&#10; &#125;&#41;&#10; column_references &#61; object&#40;&#123;&#10; referencing_column &#61; string&#10; referenced_column &#61; string&#10; &#125;&#41;&#10; name &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L305) | Tag bindings for this dataset, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [views](variables.tf#L312) | View definitions. | <code title="map&#40;object&#40;&#123;&#10; query &#61; string&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; use_legacy_sql &#61; optional&#40;bool&#41;&#10; schema &#61; optional&#40;list&#40;object&#40;&#123;&#10; name &#61; string&#10; type &#61; string&#10; description &#61; string&#10; mode &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [context](variables.tf#L68) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; condition_vars &#61; optional&#40;map&#40;map&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; kms_keys &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; tag_values &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [dataset_access](variables.tf#L83) | Set access in the dataset resource instead of using separate resources. | <code>bool</code> | | <code>false</code> |
| [description](variables.tf#L89) | Optional description. | <code>string</code> | | <code>&#34;Terraform managed.&#34;</code> |
| [encryption_key](variables.tf#L95) | Self link of the KMS key that will be used to protect destination table. | <code>string</code> | | <code>null</code> |
| [friendly_name](variables.tf#L101) | Dataset friendly name. | <code>string</code> | | <code>null</code> |
| [iam](variables-iam.tf#L17) | IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings](variables-iam.tf#L23) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings_additive](variables-iam.tf#L38) | Individual additive IAM bindings. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_by_principals](variables-iam.tf#L53) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [labels](variables.tf#L116) | Dataset labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [location](variables.tf#L122) | Dataset location. | <code>string</code> | | <code>&#34;EU&#34;</code> |
| [materialized_views](variables.tf#L128) | Materialized views definitions. | <code title="map&#40;object&#40;&#123;&#10; query &#61; string&#10; allow_non_incremental_definition &#61; optional&#40;bool&#41;&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; enable_refresh &#61; optional&#40;bool&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; refresh_interval_ms &#61; optional&#40;bool&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; options &#61; optional&#40;object&#40;&#123;&#10; clustering &#61; optional&#40;list&#40;string&#41;&#41;&#10; expiration_time &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; partitioning &#61; optional&#40;object&#40;&#123;&#10; field &#61; optional&#40;string&#41;&#10; range &#61; optional&#40;object&#40;&#123;&#10; end &#61; number&#10; interval &#61; number&#10; start &#61; number&#10; &#125;&#41;&#41;&#10; time &#61; optional&#40;object&#40;&#123;&#10; type &#61; string&#10; expiration_ms &#61; optional&#40;number&#41;&#10; field &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [options](variables.tf#L161) | Dataset options. | <code title="object&#40;&#123;&#10; default_collation &#61; optional&#40;string&#41;&#10; default_table_expiration_ms &#61; optional&#40;number&#41;&#10; default_partition_expiration_ms &#61; optional&#40;number&#41;&#10; delete_contents_on_destroy &#61; optional&#40;bool, false&#41;&#10; is_case_insensitive &#61; optional&#40;bool&#41;&#10; max_time_travel_hours &#61; optional&#40;number, 168&#41;&#10; storage_billing_model &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [routines](variables.tf#L180) | Routine definitions. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; routine_type &#61; string&#10; language &#61; optional&#40;string&#41;&#10; definition_body &#61; string&#10; imported_libraries &#61; optional&#40;list&#40;string&#41;&#41;&#10; determinism_level &#61; optional&#40;string&#41;&#10; data_governance_type &#61; optional&#40;string&#41;&#10; return_type &#61; optional&#40;string&#41;&#10; return_table_type &#61; optional&#40;string&#41;&#10; arguments &#61; optional&#40;map&#40;object&#40;&#123;&#10; argument_kind &#61; optional&#40;string&#41;&#10; mode &#61; optional&#40;string&#41;&#10; data_type &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; spark_options &#61; optional&#40;object&#40;&#123;&#10; archive_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; connection &#61; string&#10; container_image &#61; optional&#40;string&#41;&#10; file_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; jar_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; main_file_uri &#61; optional&#40;string&#41;&#10; main_class &#61; optional&#40;string&#41;&#10; properties &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; py_file_uris &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; runtime_version &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; remote_function_options &#61; optional&#40;object&#40;&#123;&#10; connection &#61; string&#10; endpoint &#61; optional&#40;string&#41;&#10; max_batching_rows &#61; optional&#40;string&#41;&#10; user_defined_context &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tables](variables.tf#L219) | Table definitions. Options and partitioning default to null. Partitioning can only use `range` or `time`, set the unused one to null. | <code title="map&#40;object&#40;&#123;&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; schema &#61; optional&#40;string&#41;&#10; external_data_configuration &#61; optional&#40;object&#40;&#123;&#10; autodetect &#61; bool&#10; source_uris &#61; list&#40;string&#41;&#10; avro_logical_types &#61; optional&#40;bool&#41;&#10; compression &#61; optional&#40;string&#41;&#10; connection_id &#61; optional&#40;string&#41;&#10; file_set_spec_type &#61; optional&#40;string&#41;&#10; ignore_unknown_values &#61; optional&#40;bool&#41;&#10; metadata_cache_mode &#61; optional&#40;string&#41;&#10; object_metadata &#61; optional&#40;string&#41;&#10; json_options_encoding &#61; optional&#40;string&#41;&#10; reference_file_schema_uri &#61; optional&#40;string&#41;&#10; schema &#61; optional&#40;string&#41;&#10; source_format &#61; optional&#40;string&#41;&#10; max_bad_records &#61; optional&#40;number&#41;&#10; csv_options &#61; optional&#40;object&#40;&#123;&#10; quote &#61; string&#10; allow_jagged_rows &#61; optional&#40;bool&#41;&#10; allow_quoted_newlines &#61; optional&#40;bool&#41;&#10; encoding &#61; optional&#40;string&#41;&#10; field_delimiter &#61; optional&#40;string&#41;&#10; skip_leading_rows &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; google_sheets_options &#61; optional&#40;object&#40;&#123;&#10; range &#61; optional&#40;string&#41;&#10; skip_leading_rows &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; hive_partitioning_options &#61; optional&#40;object&#40;&#123;&#10; mode &#61; optional&#40;string&#41;&#10; require_partition_filter &#61; optional&#40;bool&#41;&#10; source_uri_prefix &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; parquet_options &#61; optional&#40;object&#40;&#123;&#10; enum_as_string &#61; optional&#40;bool&#41;&#10; enable_list_inference &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10;&#10;&#10; &#125;&#41;&#41;&#10; options &#61; optional&#40;object&#40;&#123;&#10; clustering &#61; optional&#40;list&#40;string&#41;&#41;&#10; encryption_key &#61; optional&#40;string&#41;&#10; expiration_time &#61; optional&#40;number&#41;&#10; max_staleness &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; partitioning &#61; optional&#40;object&#40;&#123;&#10; field &#61; optional&#40;string&#41;&#10; range &#61; optional&#40;object&#40;&#123;&#10; end &#61; number&#10; interval &#61; number&#10; start &#61; number&#10; &#125;&#41;&#41;&#10; time &#61; optional&#40;object&#40;&#123;&#10; type &#61; string&#10; expiration_ms &#61; optional&#40;number&#41;&#10; field &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; table_constraints &#61; optional&#40;object&#40;&#123;&#10; primary_key_columns &#61; optional&#40;list&#40;string&#41;&#41;&#10; foreign_keys &#61; optional&#40;object&#40;&#123;&#10; referenced_table &#61; object&#40;&#123;&#10; project_id &#61; string&#10; dataset_id &#61; string&#10; table_id &#61; string&#10; &#125;&#41;&#10; column_references &#61; object&#40;&#123;&#10; referencing_column &#61; string&#10; referenced_column &#61; string&#10; &#125;&#41;&#10; name &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L304) | Tag bindings for this dataset, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [views](variables.tf#L311) | View definitions. | <code title="map&#40;object&#40;&#123;&#10; query &#61; string&#10; deletion_protection &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string, &#34;Terraform managed.&#34;&#41;&#10; friendly_name &#61; optional&#40;string&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; use_legacy_sql &#61; optional&#40;bool&#41;&#10; schema &#61; optional&#40;list&#40;object&#40;&#123;&#10; name &#61; string&#10; type &#61; string&#10; description &#61; string&#10; mode &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs

View File

@@ -0,0 +1,82 @@
/**
* Copyright 2024 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.
*/
# tfdoc:file:description IAM bindings.
locals {
_iam_principal_roles = distinct(flatten(values(var.iam_by_principals)))
_iam_principals = {
for r in local._iam_principal_roles : r => [
for k, v in var.iam_by_principals :
k if try(index(v, r), null) != null
]
}
iam = {
for role in distinct(concat(keys(var.iam), keys(local._iam_principals))) :
role => concat(
try(var.iam[role], []),
try(local._iam_principals[role], [])
)
}
}
resource "google_bigquery_dataset_iam_binding" "authoritative" {
for_each = local.iam
project = local.project_id
dataset_id = google_bigquery_dataset.default.dataset_id
role = lookup(local.ctx.custom_roles, each.key, each.key)
members = [
for v in each.value : lookup(local.ctx.iam_principals, v, v)
]
}
resource "google_bigquery_dataset_iam_binding" "bindings" {
for_each = var.iam_bindings
project = local.project_id
dataset_id = google_bigquery_dataset.default.dataset_id
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
members = [
for v in each.value.members : lookup(local.ctx.iam_principals, v, v)
]
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = templatestring(
each.value.condition.expression, var.context.condition_vars
)
title = each.value.condition.title
description = each.value.condition.description
}
}
}
resource "google_bigquery_dataset_iam_member" "bindings" {
for_each = var.iam_bindings_additive
project = local.project_id
dataset_id = google_bigquery_dataset.default.dataset_id
role = lookup(local.ctx.custom_roles, each.value.role, each.value.role)
member = lookup(local.ctx.iam_principals, each.value.member, each.value.member)
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = templatestring(
each.value.condition.expression, var.context.condition_vars
)
title = each.value.condition.title
description = each.value.condition.description
}
}
}

View File

@@ -231,15 +231,6 @@ resource "google_bigquery_dataset_access" "authorized_routines" {
}
}
resource "google_bigquery_dataset_iam_binding" "bindings" {
for_each = var.iam
project = local.project_id
dataset_id = google_bigquery_dataset.default.dataset_id
role = lookup(local.ctx.custom_roles, each.key, each.key)
members = [
for v in each.value : lookup(local.ctx.iam_principals, v, v)
]
}
resource "google_bigquery_table" "default" {
provider = google-beta

View File

@@ -0,0 +1,58 @@
/**
* Copyright 2024 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.
*/
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles."
type = map(list(string))
default = {}
}
variable "iam_bindings" {
description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary."
type = map(object({
members = list(string)
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
}))
nullable = false
default = {}
}
variable "iam_bindings_additive" {
description = "Individual additive IAM bindings. Keys are arbitrary."
type = map(object({
member = string
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
}))
nullable = false
default = {}
}
variable "iam_by_principals" {
description = "Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable."
type = map(list(string))
default = {}
nullable = false
}

View File

@@ -68,6 +68,7 @@ variable "authorized_views" {
variable "context" {
description = "Context-specific interpolations."
type = object({
condition_vars = optional(map(map(string)), {})
custom_roles = optional(map(string), {})
kms_keys = optional(map(string), {})
iam_principals = optional(map(string), {})
@@ -103,11 +104,9 @@ variable "friendly_name" {
default = null
}
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles."
type = map(list(string))
default = {}
}
variable "id" {
description = "Dataset id."

View File

@@ -442,7 +442,8 @@ module "project-factory" {
data_defaults = {
billing_account = var.billing_account_id
locations = {
storage = "EU"
bigquery = "EU"
storage = "EU"
}
}
# make sure the environment label and stackdriver service are always added
@@ -557,7 +558,6 @@ asset_feeds:
name: App 0
factories_config:
org_policies: data/factories/org-policies
pam_entitlements:
app-0-admins:
max_request_duration: 3600s
@@ -639,6 +639,8 @@ service_accounts:
iam_self_roles:
- roles/logging.logWriter
- roles/monitoring.metricWriter
tag_bindings:
context: $tag_values:context/project-factory
# this is just for illustrative/test purposes
iam:
roles/iam.serviceAccountUser:
@@ -672,6 +674,8 @@ billing_budgets:
buckets:
app-0-bucket-a:
location: europe-west8
tag_bindings:
context: $tag_values:context/gke
app-0-bucket-b:
location: europe-west8
logging_config:
@@ -695,6 +699,12 @@ services:
- container.googleapis.com
- pubsub.googleapis.com
- storage.googleapis.com
datasets:
test_0:
friendly_name: Test Dataset
iam:
roles/bigquery.dataViewer:
- $iam_principals:gcp-devops
pubsub_topics:
app-0-topic-a:
iam:
@@ -703,6 +713,14 @@ pubsub_topics:
app-0-topic-b:
subscriptions:
app-0-topic-b-sub: {}
kms:
keyrings:
my-keyring:
location: europe-west1
keys:
my-key: {}
tag_bindings:
context: $tag_values:context/project-factory
tags:
my-tag-key-1:
values:

View File

@@ -18,12 +18,26 @@ locals {
projects_bigquery_datasets = flatten([
for k, v in local.projects_input : [
for name, opts in lookup(v, "datasets", {}) : {
project_key = k
project_name = v.name
id = name
encryption_key = lookup(opts, "encryption_key", null)
friendly_name = lookup(opts, "friendly_name", null)
location = lookup(opts, "location", null)
project_key = k
project_name = v.name
id = name
encryption_key = lookup(opts, "encryption_key", null)
friendly_name = lookup(opts, "friendly_name", null)
location = lookup(opts, "location", null)
iam = lookup(opts, "iam", {})
iam_bindings = lookup(opts, "iam_bindings", {})
iam_bindings_additive = lookup(opts, "iam_bindings_additive", {})
iam_by_principals = lookup(opts, "iam_by_principals", {})
tag_bindings = lookup(opts, "tag_bindings", {})
options = {
default_collation = try(opts.options.default_collation, null)
default_table_expiration_ms = try(opts.options.default_table_expiration_ms, null)
default_partition_expiration_ms = try(opts.options.default_partition_expiration_ms, null)
delete_contents_on_destroy = try(opts.options.delete_contents_on_destroy, null)
is_case_insensitive = try(opts.options.is_case_insensitive, null)
max_time_travel_hours = try(opts.options.max_time_travel_hours, null)
storage_billing_model = try(opts.options.storage_billing_model, null)
}
}
]
])
@@ -46,6 +60,8 @@ module "bigquery-datasets" {
kms_keys = merge(local.ctx.kms_keys, local.kms_keys, local.kms_autokeys)
locations = local.ctx.locations
project_ids = local.ctx_project_ids
tag_keys = local.ctx_tag_keys
tag_values = local.ctx_tag_values
})
encryption_key = each.value.encryption_key
friendly_name = each.value.friendly_name
@@ -54,4 +70,10 @@ module "bigquery-datasets" {
lookup(each.value, "location", null),
local.data_defaults.defaults.locations.bigquery
)
iam = each.value.iam
iam_bindings = each.value.iam_bindings
iam_bindings_additive = each.value.iam_bindings_additive
iam_by_principals = each.value.iam_by_principals
tag_bindings = each.value.tag_bindings
options = each.value.options
}

View File

@@ -56,6 +56,7 @@ locals {
lifecycle_rules = lookup(opts, "lifecycle_rules", {})
logging_config = lookup(opts, "logging_config", null)
enable_object_retention = lookup(opts, "enable_object_retention", null)
tag_bindings = lookup(opts, "tag_bindings", {})
}
]
])
@@ -81,6 +82,8 @@ module "buckets" {
locations = local.ctx.locations
project_ids = local.ctx_project_ids
storage_buckets = local.ctx.storage_buckets
tag_keys = local.ctx_tag_keys
tag_values = local.ctx_tag_values
})
iam = each.value.iam
iam_bindings = each.value.iam_bindings
@@ -101,4 +104,5 @@ module "buckets" {
soft_delete_retention = each.value.soft_delete_retention
logging_config = each.value.logging_config
enable_object_retention = each.value.enable_object_retention
tag_bindings = each.value.tag_bindings
}

View File

@@ -25,6 +25,7 @@ locals {
iam = lookup(opts, "iam", {})
iam_bindings = lookup(opts, "iam_bindings", {})
iam_bindings_additive = lookup(opts, "iam_bindings_additive", {})
tag_bindings = lookup(opts, "tag_bindings", {})
keys = lookup(opts, "keys", {})
} if try(opts.location, null) != null
]
@@ -64,6 +65,7 @@ module "kms" {
iam = each.value.iam
iam_bindings = each.value.iam_bindings
iam_bindings_additive = each.value.iam_bindings_additive
tag_bindings = each.value.tag_bindings
keys = each.value.keys
context = merge(local.ctx, {
iam_principals = merge(
@@ -75,5 +77,7 @@ module "kms" {
)
locations = local.ctx.locations
project_ids = local.ctx_project_ids
tag_keys = local.ctx_tag_keys
tag_values = local.ctx_tag_values
})
}

View File

@@ -40,6 +40,7 @@ locals {
try(local.data_defaults.defaults.service_accounts.iam_self_roles, []),
))
iam_storage_roles = try(opts.iam_storage_roles, {})
tag_bindings = try(opts.tag_bindings, {})
opts = opts
}
]
@@ -85,6 +86,7 @@ module "service-accounts" {
display_name = each.value.display_name
context = merge(local.ctx, {
project_ids = local.ctx_project_ids
tag_values = local.ctx_tag_values
})
iam_project_roles = merge(
each.value.iam_project_roles,
@@ -92,6 +94,7 @@ module "service-accounts" {
"$project_ids:${each.value.project_key}" = each.value.iam_self_roles
}
)
tag_bindings = each.value.tag_bindings
}
module "service_accounts-iam" {

View File

@@ -244,6 +244,39 @@
},
"encryption_key": {
"type": "string"
},
"iam": {
"$ref": "#/$defs/iam"
},
"iam_bindings": {
"$ref": "#/$defs/iam_bindings"
},
"iam_bindings_additive": {
"$ref": "#/$defs/iam_bindings_additive"
},
"iam_by_principals": {
"$ref": "#/$defs/iam_by_principals"
},
"options": {
"type": "object",
"additionalProperties": false,
"properties": {
"default_table_expiration_ms": {
"type": "number"
},
"default_partition_expiration_ms": {
"type": "number"
},
"delete_contents_on_destroy": {
"type": "boolean"
},
"max_time_travel_hours": {
"type": "number"
}
}
},
"tag_bindings": {
"$ref": "#/$defs/tag_bindings"
}
}
}
@@ -348,6 +381,9 @@
"iam_bindings_additive": {
"$ref": "#/$defs/iam_bindings_additive"
},
"tag_bindings": {
"$ref": "#/$defs/tag_bindings"
},
"keys": {
"type": "object",
"additionalProperties": false,
@@ -651,6 +687,9 @@
},
"iam_sa_roles": {
"$ref": "#/$defs/iam_sa_roles"
},
"tag_bindings": {
"$ref": "#/$defs/tag_bindings"
}
}
}
@@ -756,15 +795,6 @@
}
}
},
"tag_bindings": {
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[a-z0-9_-]+$": {
"type": "string"
}
}
},
"tags": {
"type": "object",
"additionalProperties": {
@@ -813,6 +843,15 @@
}
}
},
"tag_bindings": {
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[a-z0-9_-]+$": {
"type": "string"
}
}
},
"universe": {
"type": "object",
"additionalProperties": false,
@@ -1192,6 +1231,9 @@
},
"enable_object_retention": {
"type": "boolean"
},
"tag_bindings": {
"$ref": "#/$defs/tag_bindings"
}
}
},
@@ -1804,6 +1846,15 @@
}
}
}
},
"tag_bindings": {
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[a-z0-9_-]+$": {
"type": "string"
}
}
}
}
}