diff --git a/.kitchen.yml b/.kitchen.yml index 4b61fa30..36b5eeeb 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -84,3 +84,16 @@ suites: backend: local provisioner: name: terraform + + - name: billing-iam + driver: + name: terraform + command_timeout: 1800 + root_module_directory: test/fixtures/billing-iam + verifier: + name: terraform + systems: + - name: billing-iam + backend: local + provisioner: + name: terraform diff --git a/Makefile b/Makefile index 86e88824..0335fe60 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ docker_test_prepare: -e TF_VAR_org_id \ -e TF_VAR_folder_id \ -e TF_VAR_billing_account \ + -e TF_VAR_billing_iam_test_account \ -v $(CURDIR):/workspace \ $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ /usr/local/bin/execute_with_credentials.sh prepare_environment @@ -51,6 +52,7 @@ docker_test_cleanup: -e TF_VAR_org_id \ -e TF_VAR_folder_id \ -e TF_VAR_billing_account \ + -e TF_VAR_billing_iam_test_account \ -v $(CURDIR):/workspace \ $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ /usr/local/bin/execute_with_credentials.sh cleanup_environment diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index 0e4e0537..9f93942e 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -21,6 +21,7 @@ steps: - 'TF_VAR_org_id=$_ORG_ID' - 'TF_VAR_folder_id=$_FOLDER_ID' - 'TF_VAR_billing_account=$_BILLING_ACCOUNT' + - 'TF_VAR_billing_iam_test_account=$_BILLING_IAM_TEST_ACCOUNT' - id: create member-iam-local waitFor: @@ -43,6 +44,30 @@ steps: name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy member-iam-local'] +# ----- SUITE billing-iam-local + +- id: create billing-iam-local + waitFor: + - prepare + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do create billing-iam-local'] +- id: converge billing-iam-local + waitFor: + - create billing-iam-local + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do converge billing-iam-local'] +- id: verify billing-iam-local + waitFor: + - converge billing-iam-local + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do verify billing-iam-local'] +- id: destroy billing-iam-local + waitFor: + - verify billing-iam-local + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy billing-iam-local'] + + # ----- SUITE additive-local # verify additive-local with 2 roles diff --git a/examples/billing_account/README.md b/examples/billing_account/README.md index 474da886..ff1d2823 100644 --- a/examples/billing_account/README.md +++ b/examples/billing_account/README.md @@ -8,9 +8,15 @@ This example illustrates how to use the `billing_accounts_iam` submodule | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| | billing\_account\_id | Billing Account ID to apply IAM bindings | string | n/a | yes | -| group\_email | Email for group to receive roles (ex. group@example.com) | string | n/a | yes | -| sa\_email | Email for Service Account to receive roles (Ex. default-sa@example-project-id.iam.gserviceaccount.com) | string | n/a | yes | -| user\_email | Email for group to receive roles (Ex. user@example.com) | string | n/a | yes | +| project\_id | Project ID for the module | string | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| billing\_account\_ids | Billing Accounts which received bindings. | +| members | Members which were bound to the billing accounts. | +| service\_account\_addresses | Service Account Addresses which were bound to projects. | diff --git a/examples/billing_account/main.tf b/examples/billing_account/main.tf index f5c4f5ac..2d0b8c9a 100644 --- a/examples/billing_account/main.tf +++ b/examples/billing_account/main.tf @@ -25,6 +25,30 @@ provider "google-beta" { version = "~> 2.7" } +locals { + + bindings = { + "roles/billing.viewer" = [ + "serviceAccount:billing-iam-test-01@${var.project_id}.iam.gserviceaccount.com", + ] + + "roles/billing.admin" = [ + "serviceAccount:billing-iam-test-01@${var.project_id}.iam.gserviceaccount.com", + "serviceAccount:billing-iam-test-02@${var.project_id}.iam.gserviceaccount.com", + ] + } +} + +resource "google_service_account" "service_account_01" { + account_id = "billing-iam-test-01" + project = var.project_id +} + +resource "google_service_account" "service_account_02" { + account_id = "billing-iam-test-02" + project = var.project_id +} + /****************************************** Module billing_account_iam_binding calling *****************************************/ @@ -35,14 +59,5 @@ module "billing-account-iam" { mode = "additive" - bindings = { - "roles/billing.viewer" = [ - "user:${var.user_email}", - ] - - "roles/billing.user" = [ - "serviceAccount:${var.sa_email}", - "group:${var.group_email}", - ] - } + bindings = local.bindings } diff --git a/examples/billing_account/outputs.tf b/examples/billing_account/outputs.tf new file mode 100644 index 00000000..ba02156c --- /dev/null +++ b/examples/billing_account/outputs.tf @@ -0,0 +1,30 @@ +/** + * Copyright 2019 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. + */ + +output "service_account_addresses" { + value = [google_service_account.service_account_01.email, google_service_account.service_account_02.email] + description = "Service Account Addresses which were bound to projects." +} + +output "billing_account_ids" { + value = module.billing-account-iam.billing_account_ids + description = "Billing Accounts which received bindings." +} + +output "members" { + value = local.bindings + description = "Members which were bound to the billing accounts." +} diff --git a/examples/billing_account/variables.tf b/examples/billing_account/variables.tf index b1af0599..5add5a37 100644 --- a/examples/billing_account/variables.tf +++ b/examples/billing_account/variables.tf @@ -14,22 +14,12 @@ * limitations under the License. */ -variable "group_email" { - type = string - description = "Email for group to receive roles (ex. group@example.com)" -} - -variable "sa_email" { - type = string - description = "Email for Service Account to receive roles (Ex. default-sa@example-project-id.iam.gserviceaccount.com)" -} - -variable "user_email" { +variable "billing_account_id" { type = string - description = "Email for group to receive roles (Ex. user@example.com)" + description = "Billing Account ID to apply IAM bindings" } -variable "billing_account_id" { +variable "project_id" { type = string - description = "Billing Account ID to apply IAM bindings" + description = "Project ID for the module" } diff --git a/test/fixtures/billing-iam/main.tf b/test/fixtures/billing-iam/main.tf new file mode 100644 index 00000000..42d03dd4 --- /dev/null +++ b/test/fixtures/billing-iam/main.tf @@ -0,0 +1,31 @@ +/** + * Copyright 2019 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. + */ + +provider "google" { + version = "~> 2.7" +} + +provider "google-beta" { + version = "~> 2.7" +} + +#additive + +module "iam_binding_billing_accounts_additive" { + source = "../../../examples/billing_account" + billing_account_id = var.billing_iam_test_account + project_id = var.project_id +} diff --git a/test/fixtures/billing-iam/outputs.tf b/test/fixtures/billing-iam/outputs.tf new file mode 100644 index 00000000..e5195a31 --- /dev/null +++ b/test/fixtures/billing-iam/outputs.tf @@ -0,0 +1,34 @@ +/** + * Copyright 2019 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. + */ + +# Resources + +#Additive + +output "billing_iam_test_accounts" { + value = module.iam_binding_billing_accounts_additive.billing_account_ids + description = "Billing Accounts which received bindings." +} + +output "members" { + value = module.iam_binding_billing_accounts_additive.members + description = "Members which were bound to the billing accounts." +} + +output "project_id" { + value = var.project_id + description = "Project ID" +} diff --git a/test/fixtures/billing-iam/variables.tf b/test/fixtures/billing-iam/variables.tf new file mode 100644 index 00000000..7bc1ccf7 --- /dev/null +++ b/test/fixtures/billing-iam/variables.tf @@ -0,0 +1,25 @@ +/** + * Copyright 2019 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 "billing_iam_test_account" { + type = string + description = "Billing Account ID to use for testing IAM policies/bindings." +} + +variable "project_id" { + type = string + description = "Project ID" +} diff --git a/test/fixtures/helper/base/main.tf b/test/fixtures/helper/base/main.tf index c05c0102..7a415cb3 100644 --- a/test/fixtures/helper/base/main.tf +++ b/test/fixtures/helper/base/main.tf @@ -35,7 +35,7 @@ resource "google_folder" "test" { resource "random_id" "test" { count = local.n - byte_length = 2 + byte_length = 4 } resource "google_project" "test" { diff --git a/test/integration/billing-iam/controls/billing-iam.rb b/test/integration/billing-iam/controls/billing-iam.rb new file mode 100644 index 00000000..7da631ae --- /dev/null +++ b/test/integration/billing-iam/controls/billing-iam.rb @@ -0,0 +1,49 @@ +# Copyright 2019 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 +# +# https://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. + +# Billing Bindings + +billing_iam_test_accounts = attribute('billing_iam_test_accounts') +members = attribute('members') +project_id = attribute('project_id') + +control "GCP Billing IAM" do + title "GCP Billing Bindings" + billing_iam_test_accounts.each do |billing_iam_test_accounts| + describe command ("gcloud beta billing accounts get-iam-policy #{billing_iam_test_accounts} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:data) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + + describe "members" do + it "are bound" do + transformed_data={} + data['bindings'].each do |binding| + transformed_data.store(binding["role"],binding["members"]) + end + expect(transformed_data["roles/billing.viewer"]).to include("serviceAccount:billing-iam-test-01@#{project_id}.iam.gserviceaccount.com") + expect(transformed_data["roles/billing.admin"]).to include("serviceAccount:billing-iam-test-01@#{project_id}.iam.gserviceaccount.com") + expect(transformed_data["roles/billing.admin"]).to include("serviceAccount:billing-iam-test-02@#{project_id}.iam.gserviceaccount.com") + end + end + end + end +end diff --git a/test/integration/billing-iam/inspec.yml b/test/integration/billing-iam/inspec.yml new file mode 100644 index 00000000..2f9a0e5d --- /dev/null +++ b/test/integration/billing-iam/inspec.yml @@ -0,0 +1,28 @@ +# Copyright 2019 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. + +name: billing-iam +attributes: + - name: billing_iam_test_accounts + required: true + type: array + - name: roles + required: true + type: array + - name: members + required: true + type: hash + - name: project_id + required: true + type: string diff --git a/test/setup/iam.tf b/test/setup/iam.tf index 463735f0..6f93ca5b 100644 --- a/test/setup/iam.tf +++ b/test/setup/iam.tf @@ -40,6 +40,10 @@ locals { int_required_ba_roles = [ "roles/billing.user", ] + + int_required_ba_billing_iam_roles = [ + "roles/billing.admin", + ] } resource "google_service_account" "int_test" { @@ -72,7 +76,14 @@ resource "google_billing_account_iam_member" "int_test_ba" { member = "serviceAccount:${google_service_account.int_test.email}" } +resource "google_billing_account_iam_member" "int_test_ba_billing_iam" { + count = length(local.int_required_ba_billing_iam_roles) + + billing_account_id = var.billing_iam_test_account + role = local.int_required_ba_billing_iam_roles[count.index] + member = "serviceAccount:${google_service_account.int_test.email}" +} + resource "google_service_account_key" "int_test" { service_account_id = google_service_account.int_test.id } - diff --git a/test/setup/outputs.tf b/test/setup/outputs.tf index 04c0b89e..7b738174 100644 --- a/test/setup/outputs.tf +++ b/test/setup/outputs.tf @@ -45,7 +45,17 @@ output "member2" { description = "Members created for binding with roles." } +output "billing_sa_admin" { + value = google_service_account.int_test.email + description = "Admin Service Account bound to Test Billing Account." +} + output "random_hexes" { value = random_id.random_hexes[*].hex description = "List of pre-generated random id hexes. Required for 'for_each' to work when testing static scerarios." } + +output "billing_iam_test_account" { + value = var.billing_iam_test_account + description = "The billing iam test account id is for the billing-iam-module, only for testing, e.g. XXXXXX-YYYYYY-ZZZZZZ" +} diff --git a/test/setup/variables.tf b/test/setup/variables.tf index 6d80b898..f06665a4 100644 --- a/test/setup/variables.tf +++ b/test/setup/variables.tf @@ -24,3 +24,7 @@ variable "folder_id" { variable "billing_account" { description = "The billing account id associated with the project, e.g. XXXXXX-YYYYYY-ZZZZZZ" } + +variable "billing_iam_test_account" { + description = "The billing iam test account id is for the billing-iam-module, only for testing, e.g. XXXXXX-YYYYYY-ZZZZZZ" +}