diff --git a/CHANGELOG.md b/CHANGELOG.md index b4404d04..75618251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ and this project adheres to ## [Unreleased] +### Added + +- The `project_labels` and `storage_bucket_labels` variables. [#2] + +### Changed + +- The storage buckets are changed to enforce Bucket Policy Only access. [#3] +- The Terraform service account receives Security Admin by default. [#4] + ## [0.1.0] - 2019-11-21 ### Added @@ -17,4 +26,7 @@ and this project adheres to [Unreleased]: https://github.com/terraform-google-modules/terraform-google-bootstrap/compare/v0.1.0...HEAD [0.1.0]: https://github.com/terraform-google-modules/terraform-google-bootstrap/releases/tag/v0.1.0 +[#4]: https://github.com/terraform-google-modules/terraform-google-bootstrap/pull/4 +[#3]: https://github.com/terraform-google-modules/terraform-google-bootstrap/issues/3 +[#2]: https://github.com/terraform-google-modules/terraform-google-bootstrap/issues/2 [#1]: https://github.com/terraform-google-modules/terraform-google-bootstrap/pull/1 diff --git a/README.md b/README.md index 81886edc..f20d3372 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,11 @@ For the cloudbuild submodule, see the README [cloudbuild](./modules/cloudbuild). | org\_admins\_org\_iam\_permissions | List of permissions granted to the group supplied in group_org_admins variable across the GCP organization. | list(string) | `` | no | | org\_id | GCP Organization ID | string | n/a | yes | | org\_project\_creators | Additional list of members to have project creator role accross the organization. Prefix of group: user: or serviceAccount: is required. | list(string) | `` | no | +| project\_labels | Labels to apply to the project. | map(string) | `` | no | | project\_prefix | Name prefix to use for projects created. | string | `"cft"` | no | | sa\_enable\_impersonation | Allow org_admins group to impersonate service account & enable APIs required. | bool | `"false"` | no | | sa\_org\_iam\_permissions | List of permissions granted to Terraform service account across the GCP organization. | list(string) | `` | no | +| storage\_bucket\_labels | Labels to apply to the storage bucket. | map(string) | `` | no | ## Outputs diff --git a/examples/cloudbuild_enabled/main.tf b/examples/cloudbuild_enabled/main.tf index f75519dd..316072e4 100644 --- a/examples/cloudbuild_enabled/main.tf +++ b/examples/cloudbuild_enabled/main.tf @@ -16,7 +16,19 @@ provider "google" { - version = "~> 2.0" + version = "~> 2.12.0" +} + +provider "google-beta" { + version = "~> 2.12.0" +} + +provider "null" { + version = "~> 2.1" +} + +provider "random" { + version = "~> 2.2" } module "seed_bootstrap" { diff --git a/examples/simple/main.tf b/examples/simple/main.tf index e6c602d6..d839ff07 100644 --- a/examples/simple/main.tf +++ b/examples/simple/main.tf @@ -14,9 +14,20 @@ * limitations under the License. */ - provider "google" { - version = "~> 2.0" + version = "~> 2.12.0" +} + +provider "google-beta" { + version = "~> 2.12.0" +} + +provider "null" { + version = "~> 2.1" +} + +provider "random" { + version = "~> 2.2" } module "seed_bootstrap" { diff --git a/main.tf b/main.tf index 26361e61..f850fbb8 100644 --- a/main.tf +++ b/main.tf @@ -44,6 +44,7 @@ module "seed_project" { org_id = var.org_id billing_account = var.billing_account activate_apis = local.activate_apis + labels = var.project_labels } /****************************************** @@ -61,9 +62,14 @@ resource "google_service_account" "org_terraform" { ***********************************************/ resource "google_storage_bucket" "org_terraform_state" { - project = module.seed_project.project_id - name = format("%s-%s-%s", var.project_prefix, "tfstate", random_id.suffix.hex) - location = var.default_region + project = module.seed_project.project_id + name = format("%s-%s-%s", var.project_prefix, "tfstate", random_id.suffix.hex) + location = var.default_region + labels = var.storage_bucket_labels + bucket_policy_only = true + versioning { + enabled = true + } } /*********************************************** @@ -127,7 +133,7 @@ resource "google_billing_account_iam_member" "tf_billing_user" { resource "google_storage_bucket_iam_member" "org_terraform_state_iam" { bucket = google_storage_bucket.org_terraform_state.name - role = "roles/storage.objectAdmin" + role = "roles/storage.admin" member = "serviceAccount:${google_service_account.org_terraform.email}" } diff --git a/modules/cloudbuild/README.md b/modules/cloudbuild/README.md index c7d68dfd..cf9d37a9 100644 --- a/modules/cloudbuild/README.md +++ b/modules/cloudbuild/README.md @@ -13,7 +13,6 @@ module "bootstrap" { org_id = "" billing_account = "" group_org_admins = "gcp-organization-admins@example.com" - group_billing_admins = "gcp-billing-admins@example.com" default_region = "australia-southeast1" sa_enable_impersonation = true terraform_sa_email = "" @@ -59,8 +58,10 @@ Functional examples and sample Cloud Build definitions are included in the [exam | folder\_id | The ID of a folder to host this project | string | `""` | no | | group\_org\_admins | Google Group for GCP Organization Administrators | string | n/a | yes | | org\_id | GCP Organization ID | string | n/a | yes | +| project\_labels | Labels to apply to the project. | map(string) | `` | no | | project\_prefix | Name prefix to use for projects created. | string | `"cft"` | no | | sa\_enable\_impersonation | Allow org_admins group to impersonate service account & enable APIs required. | bool | `"false"` | no | +| storage\_bucket\_labels | Labels to apply to the storage bucket. | map(string) | `` | no | | terraform\_sa\_email | Email for terraform service account. | string | n/a | yes | | terraform\_sa\_name | Fully-qualified name of the terraform service account. | string | n/a | yes | | terraform\_state\_bucket | Default state bucket, used in Cloud Build substitutions. | string | n/a | yes | diff --git a/modules/cloudbuild/main.tf b/modules/cloudbuild/main.tf index f509dbaf..555bf8d7 100644 --- a/modules/cloudbuild/main.tf +++ b/modules/cloudbuild/main.tf @@ -44,6 +44,7 @@ module "cloudbuild_project" { org_id = var.org_id billing_account = var.billing_account activate_apis = local.activate_apis + labels = var.project_labels } resource "google_project_service" "cloudbuild_apis" { @@ -74,9 +75,14 @@ resource "google_project_iam_member" "org_admins_cloudbuild_viewer" { *******************************************/ resource "google_storage_bucket" "cloudbuild_artifacts" { - project = module.cloudbuild_project.project_id - name = format("%s-%s-%s", var.project_prefix, "cloudbuild-artifacts", random_id.suffix.hex) - location = var.default_region + project = module.cloudbuild_project.project_id + name = format("%s-%s-%s", var.project_prefix, "cloudbuild-artifacts", random_id.suffix.hex) + location = var.default_region + labels = var.storage_bucket_labels + bucket_policy_only = true + versioning { + enabled = true + } } /****************************************** @@ -237,7 +243,7 @@ resource "null_resource" "cloudbuild_terraform_builder" { resource "google_storage_bucket_iam_member" "cloudbuild_artifacts_iam" { bucket = google_storage_bucket.cloudbuild_artifacts.name - role = "roles/storage.objectAdmin" + role = "roles/storage.admin" member = "serviceAccount:${module.cloudbuild_project.project_number}@cloudbuild.gserviceaccount.com" depends_on = [ google_project_service.cloudbuild_apis, @@ -271,7 +277,7 @@ resource "google_storage_bucket_iam_member" "cloudbuild_state_iam" { count = local.impersonation_enabled_count bucket = var.terraform_state_bucket - role = "roles/storage.objectAdmin" + role = "roles/storage.admin" member = "serviceAccount:${module.cloudbuild_project.project_number}@cloudbuild.gserviceaccount.com" depends_on = [ google_project_service.cloudbuild_apis, diff --git a/modules/cloudbuild/variables.tf b/modules/cloudbuild/variables.tf index 46c8c2a1..d0c8978f 100644 --- a/modules/cloudbuild/variables.tf +++ b/modules/cloudbuild/variables.tf @@ -59,6 +59,12 @@ variable "terraform_state_bucket" { Optional variables *******************************************/ +variable "project_labels" { + description = "Labels to apply to the project." + type = map(string) + default = {} +} + variable "project_prefix" { description = "Name prefix to use for projects created." type = string @@ -79,6 +85,7 @@ variable "activate_apis" { "iam.googleapis.com", "admin.googleapis.com", "appengine.googleapis.com", + "storage-api.googleapis.com" ] } @@ -88,6 +95,12 @@ variable "sa_enable_impersonation" { default = false } +variable "storage_bucket_labels" { + description = "Labels to apply to the storage bucket." + type = map(string) + default = {} +} + variable "cloud_source_repos" { description = "List of Cloud Source Repo's to create with CloudBuild triggers." type = list(string) diff --git a/modules/cloudbuild/versions.tf b/modules/cloudbuild/versions.tf index 27ba8fc1..c5316c8a 100644 --- a/modules/cloudbuild/versions.tf +++ b/modules/cloudbuild/versions.tf @@ -16,4 +16,9 @@ terraform { required_version = "~> 0.12.6" + + required_providers { + google = "~> 2.1" + google-beta = "~> 2.1" + } } diff --git a/test/integration/cloudbuild_enabled/controls/gcp.rb b/test/integration/cloudbuild_enabled/controls/gcp.rb index a3036b1e..5d27d528 100644 --- a/test/integration/cloudbuild_enabled/controls/gcp.rb +++ b/test/integration/cloudbuild_enabled/controls/gcp.rb @@ -86,7 +86,7 @@ end google_projects.where(project_id: attribute("cloudbuild_project_id")).project_numbers.each do |project_number| - describe google_storage_bucket_iam_binding(bucket: attribute("gcs_bucket_tfstate"), role: 'roles/storage.objectAdmin') do + describe google_storage_bucket_iam_binding(bucket: attribute("gcs_bucket_tfstate"), role: 'roles/storage.admin') do it { should exist } its('members') {should include 'serviceAccount:' + attribute("terraform_sa_email")} its('members') {should include 'serviceAccount:' + project_number.to_s + '@cloudbuild.gserviceaccount.com'} diff --git a/test/integration/simple/controls/gcp.rb b/test/integration/simple/controls/gcp.rb index a476a09a..451ad75b 100644 --- a/test/integration/simple/controls/gcp.rb +++ b/test/integration/simple/controls/gcp.rb @@ -35,7 +35,7 @@ it { should exist } end - describe google_storage_bucket_iam_binding(bucket: attribute("gcs_bucket_tfstate"), role: 'roles/storage.objectAdmin') do + describe google_storage_bucket_iam_binding(bucket: attribute("gcs_bucket_tfstate"), role: 'roles/storage.admin') do its('members') {should include 'serviceAccount:' + attribute("terraform_sa_email")} end diff --git a/variables.tf b/variables.tf index bea477a7..26372da1 100644 --- a/variables.tf +++ b/variables.tf @@ -48,6 +48,12 @@ variable "default_region" { Optional variables *******************************************/ +variable "project_labels" { + description = "Labels to apply to the project." + type = map(string) + default = {} +} + variable "project_prefix" { description = "Name prefix to use for projects created." default = "cft" @@ -68,6 +74,7 @@ variable "activate_apis" { "iam.googleapis.com", "admin.googleapis.com", "appengine.googleapis.com", + "storage-api.googleapis.com" ] } @@ -78,6 +85,7 @@ variable "sa_org_iam_permissions" { "roles/billing.user", "roles/compute.networkAdmin", "roles/compute.xpnAdmin", + "roles/iam.securityAdmin", "roles/iam.serviceAccountAdmin", "roles/logging.configWriter", "roles/orgpolicy.policyAdmin", @@ -93,6 +101,12 @@ variable "sa_enable_impersonation" { default = false } +variable "storage_bucket_labels" { + description = "Labels to apply to the storage bucket." + type = map(string) + default = {} +} + variable "org_admins_org_iam_permissions" { description = "List of permissions granted to the group supplied in group_org_admins variable across the GCP organization." type = list(string) diff --git a/versions.tf b/versions.tf index 27ba8fc1..c5316c8a 100644 --- a/versions.tf +++ b/versions.tf @@ -16,4 +16,9 @@ terraform { required_version = "~> 0.12.6" + + required_providers { + google = "~> 2.1" + google-beta = "~> 2.1" + } }