Skip to content

Commit

Permalink
feat: option to target bootstrap module at a folder (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
bharathkkb committed Jul 6, 2020
1 parent 0e06b29 commit fa923a5
Show file tree
Hide file tree
Showing 17 changed files with 493 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ 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) | `<list>` | 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) | `<list>` | no |
| parent\_folder | GCP parent folder ID in the form folders/{id} | string | `""` | no |
| project\_labels | Labels to apply to the project. | map(string) | `<map>` | 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 |
Expand Down
28 changes: 25 additions & 3 deletions build/int.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ steps:
- id: verify-simple
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 simple-default']
- id: destroy-simple
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 simple-default']
# Required to rerun to reinstate ci-integration account as project creator as not member of group_org_admins.
- id: prepare-rerun
- id: prepare-rerun-cloudbuild-enabled
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 && prepare_environment']
env:
Expand All @@ -48,9 +51,28 @@ steps:
- id: verify-cloudbuild-enabled
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 cloudbuild-enabled-default']
- id: destroy
- id: destroy-cloudbuild-enabled
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 cloudbuild-enabled-default']
# Required to rerun to reinstate ci-integration account as project creator as not member of group_org_admins.
- id: prepare-rerun-simple-folder
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 && prepare_environment']
env:
- 'TF_VAR_org_id=$_ORG_ID'
- 'TF_VAR_folder_id=$_FOLDER_ID'
- 'TF_VAR_billing_account=$_BILLING_ACCOUNT'
- 'TF_VAR_group_org_admins=test-gcp-org-admins@test.infra.cft.tips'
- 'TF_VAR_group_billing_admins=test-gcp-billing-admins@test.infra.cft.tips'
- id: converge-simple-folder
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 simple-folder-default']
- id: verify-simple-folder
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 simple-folder-default']
- id: destroy-simple-folder
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']
args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy simple-folder-default']
tags:
- 'ci'
- 'integration'
Expand Down
27 changes: 27 additions & 0 deletions examples/simple-folder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Overview

This example demonstrates the simplest usage of the GCP organization bootstrap module targeting a folder.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|:----:|:-----:|:-----:|
| billing\_account | The ID of the billing account to associate projects with. | string | n/a | yes |
| default\_region | Default region to create resources where applicable. | string | `"us-central1"` | no |
| group\_billing\_admins | Google Group for GCP Billing Administrators | string | n/a | yes |
| group\_org\_admins | Google Group for GCP Organization Administrators | string | n/a | yes |
| 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) | `<list>` | no |
| parent | GCP parent folder id of form folders/{id} | string | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| gcs\_bucket\_tfstate | Bucket used for storing terraform state for foundations pipelines in seed project. |
| seed\_project\_id | Project where service accounts and core APIs will be enabled. |
| terraform\_sa\_email | Email for privileged service account for Terraform. |
| terraform\_sa\_name | Fully qualified name for privileged service account for Terraform. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
46 changes: 46 additions & 0 deletions examples/simple-folder/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* 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 = "~> 3.5.0"
}

provider "google-beta" {
version = "~> 3.5.0"
}

provider "null" {
version = "~> 2.1"
}

provider "random" {
version = "~> 2.2"
}

/*************************************************
Bootstrap GCP Folder.
*************************************************/

module "seed_bootstrap" {
source = "../.."
org_id = var.org_id
parent_folder = var.parent
billing_account = var.billing_account
group_org_admins = var.group_org_admins
group_billing_admins = var.group_billing_admins
default_region = var.default_region
org_project_creators = var.org_project_creators
}
35 changes: 35 additions & 0 deletions examples/simple-folder/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* 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 "seed_project_id" {
description = "Project where service accounts and core APIs will be enabled."
value = module.seed_bootstrap.seed_project_id
}

output "terraform_sa_email" {
description = "Email for privileged service account for Terraform."
value = module.seed_bootstrap.terraform_sa_email
}

output "terraform_sa_name" {
description = "Fully qualified name for privileged service account for Terraform."
value = module.seed_bootstrap.terraform_sa_name
}

output "gcs_bucket_tfstate" {
description = "Bucket used for storing terraform state for foundations pipelines in seed project."
value = module.seed_bootstrap.gcs_bucket_tfstate
}
52 changes: 52 additions & 0 deletions examples/simple-folder/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* 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 "org_id" {
description = "GCP Organization ID"
type = string
}

variable "parent" {
description = "GCP parent folder id of form folders/{id}"
type = string
}

variable "billing_account" {
description = "The ID of the billing account to associate projects with."
type = string
}

variable "group_org_admins" {
description = "Google Group for GCP Organization Administrators"
type = string
}

variable "group_billing_admins" {
description = "Google Group for GCP Billing Administrators"
type = string
}

variable "default_region" {
description = "Default region to create resources where applicable."
type = string
default = "us-central1"
}

variable "org_project_creators" {
description = "Additional list of members to have project creator role accross the organization. Prefix of group: user: or serviceAccount: is required."
type = list(string)
default = []
}
10 changes: 10 additions & 0 deletions kitchen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ suites:
backend: gcp
controls:
- bootstrap
- name: simple-folder
driver:
root_module_directory: test/fixtures/simple-folder/
verifier:
color: false
systems:
- name: bootstrap-folder
backend: gcp
controls:
- bootstrap-folder
- name: cloudbuild_enabled
driver:
root_module_directory: test/fixtures/cloudbuild_enabled/
Expand Down
41 changes: 32 additions & 9 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,29 @@ locals {
impersonation_enabled_count = var.sa_enable_impersonation == true ? 1 : 0
activate_apis = var.sa_enable_impersonation == true ? local.impersonation_apis : var.activate_apis
org_project_creators = distinct(concat(var.org_project_creators, ["serviceAccount:${google_service_account.org_terraform.email}", "group:${var.group_org_admins}"]))
is_organization = var.parent_folder == "" ? true : false
parent_id = var.parent_folder == "" ? var.org_id : split("/", var.parent_folder)[1]
seed_org_depends_on = try(google_folder_iam_member.tmp_project_creator.0.etag, "") != "" ? var.org_id : google_organization_iam_member.tmp_project_creator.0.org_id
}

resource "random_id" "suffix" {
byte_length = 2
}

data "google_organization" "org" {
organization = var.org_id
}

/*************************************************
Make sure group_org_admins has projectCreator.
*************************************************/

resource "google_organization_iam_member" "tmp_project_creator" {
org_id = var.org_id
count = local.is_organization ? 1 : 0
org_id = local.parent_id
role = "roles/resourcemanager.projectCreator"
member = "group:${var.group_org_admins}"
}

resource "google_folder_iam_member" "tmp_project_creator" {
count = local.is_organization ? 0 : 1
folder = local.parent_id
role = "roles/resourcemanager.projectCreator"
member = "group:${var.group_org_admins}"
}
Expand All @@ -51,7 +58,7 @@ module "seed_project" {
random_project_id = true
disable_services_on_destroy = false
folder_id = var.folder_id
org_id = google_organization_iam_member.tmp_project_creator.org_id
org_id = local.seed_org_depends_on
billing_account = var.billing_account
activate_apis = local.activate_apis
labels = var.project_labels
Expand Down Expand Up @@ -98,7 +105,15 @@ resource "google_organization_iam_binding" "billing_creator" {
}

resource "google_organization_iam_binding" "project_creator" {
org_id = var.org_id
count = local.is_organization ? 1 : 0
org_id = local.parent_id
role = "roles/resourcemanager.projectCreator"
members = local.org_project_creators
}

resource "google_folder_iam_binding" "project_creator" {
count = local.is_organization ? 0 : 1
folder = local.parent_id
role = "roles/resourcemanager.projectCreator"
members = local.org_project_creators
}
Expand Down Expand Up @@ -163,9 +178,17 @@ resource "google_service_account_iam_member" "org_admin_sa_impersonate_permissio
}

resource "google_organization_iam_member" "org_admin_serviceusage_consumer" {
count = local.impersonation_enabled_count
count = var.sa_enable_impersonation && local.is_organization ? 1 : 0

org_id = var.org_id
org_id = local.parent_id
role = "roles/serviceusage.serviceUsageConsumer"
member = "group:${var.group_org_admins}"
}

resource "google_folder_iam_member" "org_admin_serviceusage_consumer" {
count = var.sa_enable_impersonation && ! local.is_organization ? 1 : 0

folder = local.parent_id
role = "roles/serviceusage.serviceUsageConsumer"
member = "group:${var.group_org_admins}"
}
Expand Down
26 changes: 26 additions & 0 deletions test/fixtures/simple-folder/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright 2018 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.
*/

module "simple" {
source = "../../../examples/simple-folder"

org_id = var.org_id
parent = var.parent_folder
billing_account = var.billing_account
group_org_admins = var.group_org_admins
group_billing_admins = var.group_billing_admins
default_region = var.default_region
}
45 changes: 45 additions & 0 deletions test/fixtures/simple-folder/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright 2018 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 "seed_project_id" {
description = "Project where service accounts and core APIs will be enabled."
value = module.simple.seed_project_id
}

output "terraform_sa_email" {
description = "Email for privileged service account for Terraform."
value = module.simple.terraform_sa_email
}

output "terraform_sa_name" {
description = "Fully qualified name for privileged service account for Terraform."
value = module.simple.terraform_sa_name
}

output "gcs_bucket_tfstate" {
description = "Bucket used for storing terraform state for foundations pipelines in seed project."
value = module.simple.gcs_bucket_tfstate
}

output "parent_folder" {
description = "Parent folder"
value = var.parent_folder
}

output "org_id" {
description = "Org id"
value = var.org_id
}

0 comments on commit fa923a5

Please sign in to comment.