Code Monkey home page Code Monkey logo

terraform-google-project-factory's Introduction

Google Cloud Project Factory Terraform Module

FAQ | Troubleshooting Guide | Glossary.

This module allows you to create opinionated Google Cloud Platform projects. It creates projects and configures aspects like Shared VPC connectivity, IAM access, Service Accounts, and API enablement to follow best practices.

To include G Suite integration for creating groups and adding Service Accounts into groups, use the gsuite_enabled module.

Compatibility

This module is meant for use with Terraform 0.13+ and tested using Terraform 1.3+. If you find incompatibilities using Terraform >=0.13, please open an issue. If you haven't upgraded and need a Terraform 0.12.x-compatible version of this module, the last released version intended for Terraform 0.12.x is 9.2.0.

Upgrading

See the docs for detailed instructions on upgrading between major releases of the module.

Usage

There are multiple examples included in the examples folder but simple usage is as follows:

module "project-factory" {
  source  = "terraform-google-modules/project-factory/google"
  version = "~> 16.0"

  name                 = "pf-test-1"
  random_project_id    = true
  org_id               = "1234567890"
  usage_bucket_name    = "pf-test-1-usage-report-bucket"
  usage_bucket_prefix  = "pf/test/1/integration"
  billing_account      = "ABCDEF-ABCDEF-ABCDEF"
  svpc_host_project_id = "shared_vpc_host_name"

  shared_vpc_subnets = [
    "projects/base-project-196723/regions/us-east1/subnetworks/default",
    "projects/base-project-196723/regions/us-central1/subnetworks/default",
    "projects/base-project-196723/regions/us-central1/subnetworks/subnet-1",
  ]
}

Features

The Project Factory module will take the following actions:

  1. Create a new GCP project using the project_name.

  2. If a shared VPC is specified, attach the new project to the svpc_host_project_id.

    It will also give the following users network access on the specified subnets:

    • The project's new default service account (see step 4)
    • The Google API service account for the project
    • The project controlling group specified in group_name
  3. Delete the default compute service account.

  4. Create a new default service account for the project.

    1. Give it access to the shared VPC (to be able to launch instances).
  5. Attach the billing account (billing_account) to the project.

  6. Give the controlling group access to the project, with the group_role.

  7. Enable the required and specified APIs (activate_apis).

  8. Delete the default network.

  9. Enable usage report for GCE into central project bucket (target_usage_bucket), if provided.

  10. If specified, create the GCS bucket bucket_name and give the following accounts Storage Admin on it:

    1. The controlling group (group_name).
    2. The new default compute service account created for the project.
    3. The Google APIs service account for the project.

The roles granted are specifically:

  • New Default Service Account
    • compute.networkUser on host project or specified subnets
    • storage.admin on bucket_name GCS bucket
  • group_name is the controlling group
    • compute.networkUser on host project or specific subnets
    • Specified group_role on project
    • iam.serviceAccountUser on the default Service Account
    • storage.admin on bucket_name GCS bucket
  • Google APIs Service Account
    • compute.networkUser on host project or specified subnets
    • storage.admin on bucket_name GCS bucket

Shared VPC subnets and IAM permissions

A service project's access to shared VPC networks is controlled via the roles/compute.networkUser role and the location to where that role is assigned. If that role is assigned to the shared VPC host project, then the service project will have access to all shared VPC subnetworks. If that role is assigned to individual subnetworks, then the service project will have access to only the subnetworks on which that role was assigned. The logic for determining that location is as follows:

  1. If var.svpc_host_project_id and var.shared_vpc_subnets are not set then the compute.networkUser role is not assigned
  2. If var.svpc_host_project_id is set but no subnetworks are provided via var.shared_vpc_subnets then the compute.networkUser role is assigned at the host project and the service project will have access to all shared VPC subnetworks
  3. If var.svpc_host_project_id is set and var.shared_vpc_subnets contains an array of subnetworks then the compute.networkUser role is assigned to each subnetwork in the array

Inputs

Name Description Type Default Required
activate_api_identities The list of service identities (Google Managed service account for the API) to force-create for the project (e.g. in order to grant additional roles).
APIs in this list will automatically be appended to activate_apis.
Not including the API in this list will follow the default behaviour for identity creation (which is usually when the first resource using the API is created).
Any roles (e.g. service agent role) must be explicitly listed. See https://cloud.google.com/iam/docs/understanding-roles#service-agent-roles-roles for a list of related roles.
list(object({
api = string
roles = list(string)
}))
[] no
activate_apis The list of apis to activate within the project list(string)
[
"compute.googleapis.com"
]
no
auto_create_network Create the default network bool false no
billing_account The ID of the billing account to associate this project with string n/a yes
bucket_force_destroy Force the deletion of all objects within the GCS bucket when deleting the bucket (optional) bool false no
bucket_labels A map of key/value label pairs to assign to the bucket (optional) map(string) {} no
bucket_location The location for a GCS bucket to create (optional) string "US" no
bucket_name A name for a GCS bucket to create (in the bucket_project project), useful for Terraform state (optional) string "" no
bucket_pap Enable Public Access Prevention. Possible values are "enforced" or "inherited". string "inherited" no
bucket_project A project to create a GCS bucket (bucket_name) in, useful for Terraform state (optional) string "" no
bucket_ula Enable Uniform Bucket Level Access bool true no
bucket_versioning Enable versioning for a GCS bucket to create (optional) bool false no
budget_alert_pubsub_topic The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of projects/{project_id}/topics/{topic_id} string null no
budget_alert_spend_basis The type of basis used to determine if spend has passed the threshold string "CURRENT_SPEND" no
budget_alert_spent_percents A list of percentages of the budget to alert on when threshold is exceeded list(number)
[
0.5,
0.7,
1
]
no
budget_amount The amount to use for a budget alert number null no
budget_calendar_period Specifies the calendar period for the budget. Possible values are MONTH, QUARTER, YEAR, CALENDAR_PERIOD_UNSPECIFIED, CUSTOM. custom_period_start_date and custom_period_end_date must be set if CUSTOM string null no
budget_custom_period_end_date Specifies the end date (DD-MM-YYYY) for the calendar_period CUSTOM string null no
budget_custom_period_start_date Specifies the start date (DD-MM-YYYY) for the calendar_period CUSTOM string null no
budget_display_name The display name of the budget. If not set defaults to `Budget For <projects[0] All Projects>` string null
budget_labels A single label and value pair specifying that usage from only this set of labeled resources should be included in the budget. map(string) {} no
budget_monitoring_notification_channels A list of monitoring notification channels in the form [projects/{project_id}/notificationChannels/{channel_id}]. A maximum of 5 channels are allowed. list(string) [] no
cloud_armor_tier Managed protection tier to be set. Possible values are: CA_STANDARD, CA_ENTERPRISE_PAYGO string null no
consumer_quotas The quotas configuration you want to override for the project.
list(object({
service = string,
metric = string,
dimensions = map(string),
limit = string,
value = string,
}))
[] no
create_project_sa Whether the default service account for the project shall be created bool true no
default_network_tier Default Network Service Tier for resources created in this project. If unset, the value will not be modified. See https://cloud.google.com/network-tiers/docs/using-network-service-tiers and https://cloud.google.com/network-tiers. string "" no
default_service_account Project default service account setting: can be one of delete, deprivilege, disable, or keep. string "disable" no
disable_dependent_services Whether services that are enabled and which depend on this service should also be disabled when this service is destroyed. bool true no
disable_services_on_destroy Whether project services will be disabled when the resources are destroyed bool true no
domain The domain name (optional). string "" no
enable_shared_vpc_host_project If this project is a shared VPC host project. If true, you must not set svpc_host_project_id variable. Default is false. bool false no
essential_contacts A mapping of users or groups to be assigned as Essential Contacts to the project, specifying a notification category map(list(string)) {} no
folder_id The ID of a folder to host this project string "" no
grant_network_role Whether or not to grant networkUser role on the host project/subnets bool true no
grant_services_security_admin_role Whether or not to grant Kubernetes Engine Service Agent the Security Admin role on the host project so it can manage firewall rules bool false no
group_name A group to control the project by being assigned group_role (defaults to project editor) string "" no
group_role The role to give the controlling group (group_name) over the project (defaults to project editor) string "roles/editor" no
labels Map of labels for project map(string) {} no
language_tag Language code to be used for essential contacts notifications string "en-US" no
lien Add a lien on the project to prevent accidental deletion bool false no
name The name for the project string n/a yes
org_id The organization ID. string null no
project_id The ID to give the project. If not provided, the name will be used. string "" no
project_sa_name Default service account name for the project. string "project-service-account" no
random_project_id Adds a suffix of 4 random characters to the project_id. bool false no
random_project_id_length Sets the length of random_project_id to the provided length, and uses a random_string for a larger collusion domain. Recommended for use with CI. number null no
sa_role A role to give the default Service Account for the project (defaults to none) string "" no
shared_vpc_subnets List of subnets fully qualified subnet IDs (ie. projects/$project_id/regions/$region/subnetworks/$subnet_id) list(string) [] no
svpc_host_project_id The ID of the host project which hosts the shared VPC string "" no
tag_binding_values Tag values to bind the project to. list(string) [] no
usage_bucket_name Name of a GCS bucket to store GCE usage reports in (optional) string "" no
usage_bucket_prefix Prefix in the GCS bucket to store GCE usage reports in (optional) string "" no
vpc_service_control_attach_dry_run Whether the project will be attached to a VPC Service Control Perimeter in Dry Run Mode. vpc_service_control_attach_enabled should be false for this to be true bool false no
vpc_service_control_attach_enabled Whether the project will be attached to a VPC Service Control Perimeter in ENFORCED MODE. vpc_service_control_attach_dry_run should be false for this to be true bool false no
vpc_service_control_perimeter_name The name of a VPC Service Control Perimeter to add the created project to string null no
vpc_service_control_sleep_duration The duration to sleep in seconds before adding the project to a shared VPC after the project is added to the VPC Service Control Perimeter. VPC-SC is eventually consistent. string "5s" no

Outputs

Name Description
api_s_account API service account email
api_s_account_fmt API service account email formatted for terraform use
budget_name The name of the budget if created
domain The organization's domain
enabled_api_identities Enabled API identities in the project
enabled_apis Enabled APIs in the project
group_email The email of the G Suite group with group_name
project_bucket_self_link Project's bucket selfLink
project_bucket_url Project's bucket url
project_id ID of the project
project_name Name of the project
project_number Numeric identifier for the project
service_account_display_name The display name of the default service account
service_account_email The email of the default service account
service_account_id The id of the default service account
service_account_name The fully-qualified name of the default service account
service_account_unique_id The unique id of the default service account
tag_bindings Tag bindings
usage_report_export_bucket GCE usage reports bucket

Requirements

Software

Permissions

In order to execute this module you must have a Service Account with the following roles:

  • roles/resourcemanager.folderViewer on the folder that you want to create the project in
  • roles/resourcemanager.organizationViewer on the organization
  • roles/resourcemanager.projectCreator on the organization
  • roles/billing.user on the organization
  • roles/storage.admin on bucket_project
  • If you are using shared VPC:
    • roles/billing.user on the organization
    • roles/compute.xpnAdmin on the organization
    • roles/compute.networkAdmin on the organization
    • roles/browser on the Shared VPC host project
    • roles/resourcemanager.projectIamAdmin on the Shared VPC host project

Script Helper

A helper script is included to create the Seed Service Account in the Seed Project, grant the necessary roles to the Seed Service Account, and enable the necessary API's in the Seed Project. Run it as follows:

./helpers/setup-sa.sh -o <organization id> -p <project id> [-b <billing account id>] [-f <folder id>] [-n <service account name>]

In order to execute this script, you must have an account with the following list of permissions:

  • resourcemanager.organizations.list
  • resourcemanager.projects.list
  • billing.accounts.list
  • iam.serviceAccounts.create
  • iam.serviceAccountKeys.create
  • resourcemanager.organizations.setIamPolicy
  • resourcemanager.projects.setIamPolicy
  • serviceusage.services.enable on the project
  • servicemanagement.services.bind on following services:
    • cloudresourcemanager.googleapis.com
    • cloudbilling.googleapis.com
    • iam.googleapis.com
    • admin.googleapis.com
    • appengine.googleapis.com
  • billing.accounts.getIamPolicy on a billing account.
  • billing.accounts.setIamPolicy on a billing account.

Specifying credentials

The Project Factory module uses the Google Terraform provider to authenticate all GCP API calls. To configure credentials, you should configure the google and google-beta providers.

provider "google" {
  credentials = "${file(var.credentials_path)}"
}

provider "google-beta" {
  credentials = "${file(var.credentials_path)}"
}

APIs

In order to operate the Project Factory, you must activate the following APIs on the base project where the Service Account was created:

Optional APIs

  • Google App Engine Admin API - appengine.googleapis.com troubleshooting
    • Please note that if you are deploying an App Engine Flex application, you should not delete the default compute service account (as is default behavior). Please see the troubleshooting doc for more information.
  • Cloud Billing Budget API - billingbudgets.googleapis.com
    • Please note this API is only required if configuring budgets for projects.

Verifying setup

A preconditions checker script is included to verify that all preconditions are met before the Project Factory runs. The script will run automatically if the script dependencies (Python, "google-auth", and "google-api-python-client") are available at runtime. If the dependencies are not met, the precondition checking step will be skipped.

The precondition checker script can be directly invoked before running the project factory:

./helpers/preconditions/preconditions.py \
  --credentials_path "./credentials.json" \
  --billing_account 000000-000000-000000 \
  --org_id 000000000000 \
  --folder_id 000000000000 \
  --shared_vpc 'shared-vpc-host-ed64'

Caveats

Moving projects from org into a folder

There is currently a bug with moving a project which was originally created at the root of the organization into a folder. The bug and workaround is described here, but as a general best practice it is easier to create all projects within folders to start. Moving projects between different folders is supported.

Deleting default service accounts

Default SAs can be removed by setting default_service_account input variable to delete, but there can be certain scenarios where the default SAs are required. Hence some considerations to be aware of:

  1. Using App Engine SA.
  2. Cloud Scheduler dependency on AppEngine(default SA). Default SA is required to be able to setup Cloud scheduler, please refer to the document for more upto date information.

With a combination of project-factory's default behavior, disable, and setting constraints/iam.automaticIamGrantsForDefaultServiceAccounts org constraint will address removing the default editor IAM role on the SAs and limits the SA usage. However, when the default_service_account is set to delete please be aware of the default SA dependency for AppEngine/CloudScheduler services. Accounts deleted within 30days can be restored.

G Suite

The core Project Factory solely deals with GCP APIs and does not integrate G Suite functionality. If you would like certain group-management functionality which was previously included in the Project Factory, see the G Suite module.

Install

Terraform

Be sure you have the correct Terraform version (0.13.0+), you can choose the binary here:

terraform-google-project-factory's People

Contributors

aaron-lane avatar adrienthebo avatar akopachevskyy-globallogic avatar alexkonkin avatar apeabody avatar averbuks avatar bg-master avatar bharathkkb avatar cloud-foundation-bot avatar dependabot[bot] avatar glarizza avatar ingwarr avatar ivankorn avatar jberlinsky avatar jeffmccune avatar ludoo avatar morgante avatar mwallman avatar nstogner avatar paulpalamarchuk avatar release-please[bot] avatar renovate[bot] avatar rjerrems avatar rycieos avatar taylorludwig avatar thefirstofthe300 avatar thiagonache avatar trotttrotttrott avatar umairidris avatar xingao267 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

terraform-google-project-factory's Issues

Creating multiple projects from one module

Hello,
my intention is to create a script script.sh that uses one Terraform config main.tf with a single project factory module in order to create an arbitrary number of GCP projects.
The idea of the usage is:

./script.sh project-x
./script.sh project-y
./script.sh project-z

where projects x,y,z are GCP projects that i'd like to create and script.sh does roughly
terraform apply -auto-approve -var "credentials_path=credentials.json" -var "project_name=${1}"
and the main.tf is only composed of a single module which obtains a different project name from script.sh each time.

The problem is that if the first call to create project-x succeeds, a Terraform state file is created, and subsequent script call to create project-y would react to the existing Terraform state file by deleting project-x.
What I'd like to achieve is to somehow ensure that the sequence of the script.sh calls leads to creation and peaceful co-existence of all projects.

What would you recommend, please ?

IDEAS:

  • I am experimenting with script.sh doing the terraform apply calls in separate directories specific to the project name, thus getting Terraform state files only related to specific projects. E.g. ./script.sh project-y would create directory project-y and do the rest of the work inside of it. This seems to kinda work, but I am not sure whether I like this solution.

  • Another idea I have is to maintain a dynamic Terraform config file main.tf where ./script.sh project-ywould add a module for project project-y into main.tf, then do terraform apply and hopefully let Terraform maintain a single state file for all the projects without problems.

Fails with org_id interpolated to reference a resource or data source

Tested on v0.2.1 and master

Possibly related to #47; we find that passing an interpolated value to org_id that references a data source or resource fails with this error during refresh:

module.project.null_resource.args_missing: : invalid or unknown key: ERROR: Variable `group_name` was passed. Please provide either `org_id` or `domain` variables

Our use case: we store shared state, like the organization and folders, in a separate backend which we reference using terraform_remote_state. This bug makes it impossible to reference shared state in this way.

Is there a workaround we can pursue in the near term?

`helpers/setup-sa.sh` doesn't fail safely when variables are unset

When the service account helper script is invoked in some environments (such as the WSL), variables like $RANDOM may not be set. The script doesn't catch errors before setting up credentials and can fail in an unexpected way. We should be prefer to fail early rather than running bad commands.

Need to be authoritative on activate_apis

I need to be able to tell terraform-google-modules/project-factory/google to use terraform's google_project_services resource (instead of google_project_service).

I propose a new attribute apis_authority for use in modules/core_project_factory/main.tf:

resource "google_project_service" "project_services" {
  count = "${ apis_authority == "true" ? 0 : length(var.activate_apis)}"
  ...

resource "google_project_services" "project_services_authority" {
  count = "${ apis_authority == "true" ? 1 : 0}"
  ...

I can implement a workaround in our code by not passing activate_apis to the module but I see that the module is treating container.googleapis.com as a special case and I'm concerned about future special cases.

Typical usage:

module "my-project" {
  source = "terraform-google-modules/project-factory/google"
  apis_authority = true
  activate_apis = [ ... ]
  ...

Expand testing to cover G Suite functionality

The tests currently don't make it easy to test G Suite-related functionality in the module.

We should add fixtures to consistently exercise the create_group and API/SA group functionalities.

Allow import of GCP projects

GCP project names can not be reused, attempting to do so results in a 409 error. However, this module won't accept an imported project, e.g. terraform import module.X.google_project.main my-project, because id and project_id can not be supplied as inputs. The imported project results in

-/+ module.my-project.google_project.main (new resource required)
id: "my-project-name" => (forces new resource)
auto_create_network: "true" => "false"
billing_account: "XXXXX-XXXXX-XXXXX" => "XXXXX-XXXXX-XXXXX"
folder_id: "" =>
name: "my-project-name" => "my-project-name"
number: "808999117972" =>
org_id: "1234567890" => "1234567890"
policy_data: "" =>
policy_etag: "" =>
project_id: "my-project-name" => "${local.temp_project_id}" (forces new resource)
skip_delete: "" =>

Fails with shared VPC being specified using a reference

If I specify shared_vpc in a service project I receive following error during plan or apply. If I remove shared_vpc it works but creates a standalone project instead of a service project.

* module.service_project01.google_compute_subnetwork_iam_member.group_role_to_vpc_subnets:
google_compute_subnetwork_iam_member.group_role_to_vpc_subnets: value of 'count' cannot be computed
* module.service_project01.google_compute_shared_vpc_service_project.shared_vpc_attachment: google_compute_shared_vpc_service_project.shared_vpc_attachment: value of 'count' cannot be computed
* module.service_project01.google_project_iam_member.controlling_group_vpc_membership: google_project_iam_member.controlling_group_vpc_membership: value of 'count' cannot be computed
* module.service_project01.google_compute_subnetwork_iam_member.gke_shared_vpc_subnets: google_compute_subnetwork_iam_member.gke_shared_vpc_subnets: value of 'count' cannot be computed
* module.service_project01.google_compute_subnetwork_iam_member.service_account_role_to_vpc_subnets: google_compute_subnetwork_iam_member.service_account_role_to_vpc_subnets: value of 'count' cannot be computed
* module.service_project01.google_compute_subnetwork_iam_member.apis_service_account_role_to_vpc_subnets: google_compute_subnetwork_iam_member.apis_service_account_role_to_vpc_subnets: value of 'count' cannot be computed
* module.service_project01.google_project_iam_member.gke_host_agent: google_project_iam_member.gke_host_agent: value of 'count' cannot be computed

Example resources:


module "host_project01" {
  source            = "/modules/project-factory"
  random_project_id = "true"
  name              = "host-project-01"
  org_id            = "${var.organization_id}"
  billing_account   = "${var.billing_account}"
  activate_apis     = ["compute.googleapis.com"]
  credentials_path  = "${local.credentials_file_path}"
}

module "service_project01" {
  source            = "/modules/project-factory"
  random_project_id = "true"
  name              = "service-project01"
  org_id            = "${var.organization_id}"
  billing_account   = "${var.billing_account}"
  folder_id         = "${google_folder.prod.id}"
  shared_vpc        = "${module.host_project01.project_id}" # If I remove this it works but creates a standalone project.
  activate_apis     = ["compute.googleapis.com"]
  credentials_path  = "${local.credentials_file_path}"
  group_name        = "testgroup"
  group_role        = "roles/owner"
}

Allow updating project name without recreating project

Currently, any changes to the project name updates the project ID, requiring a full recreation of the project. This is causing us significant trouble as we roll out new governance and standards changes across the organization. In local testing, adding ignore_changes = ["project_id"] to the google_project's lifecycle fixes this.

I'm happy to submit a PR if this is an acceptable direction.

Organization viewer should not be needed

We should be able to create a project without having roles/organization.viewer.

Currently the org_id is used in 2 places:

  • google_project resource (not needed unless the project is straight under the org)
  • google_organization (this resource is used to get the org domain in order to construct the default service account email string. This can be optional by letting the user pass 'domain' input directly

Can't specify folder_id.

module "host-project" {
  source            = "terraform-google-modules/project-factory/google"
  random_project_id = true
  name              = "${local.host_project_name}"
  billing_account   = "${var.billing_account}"
  auto_create_network = false
  group_name = "${var.sysadmingroup}"
  labels = "${var.labels}"
  folder_id = "${var.folder_id}"
  # org_id = "${var.org_id}
}

When both org_id and folder_id are specified:

  • google_project.main: 'org_id' and 'folder_id' cannot be both set.

When org_id is not specified:
module "host-project": missing required argument "org_id"

How can I create a project in a folder?

disable_dependent_services

Error: module.host-project.module.project-factory.google_project_service.project_services: : invalid or unknown key: disable_dependent_services

cft.tfvars
organization_id = "12345678790"
billing_account = "AAAAA-BBBBB-CCCCC"
credentials_path = "demo_credentials_20190430131031.json"

terraform.tfvars
host_project_name = "shared-vpc-host-090519"
network_name = "shared-vpc-net-090509"

terraform -v
Terraform v0.11.13

  • provider.google v1.20.0
  • provider.google-beta v1.20.0
  • provider.null v2.1.2
  • provider.random v2.1.2

Outstanding issues with tests

After #34, a few issues remain.

  • deduplicate terraform.tfvars file between full and minimal fixtures (#34 (comment))
  • Test failures for gsuite group email
  • Test failures for gsuite membership on roles/iam.serviceAccountUser
  • Document optional test coverage: project-factory-shared-vpc
  • Test project-factory-sa-role by default
  • Document optional test coverage: project-factory-usage

Additionally, I noticed a number of unexpected skips and failures even with a full tfvars:

Profile: full
Version: (not specified)
Target:  local://

  โ†บ  project-factory-gsuite: Project Factory G Suite integration (2 failed) (1 skipped)
     โ†บ  includes the gsuite group in the given role
     โœ”  Command: `gcloud projects get-iam-policy pf-test-int-full-e736 --format=json` exit_status should eq 0
     โœ”  Command: `gcloud projects get-iam-policy pf-test-int-full-e736 --format=json` stderr should eq ""
     ร—  Command: `gcloud iam service-accounts get-iam-policy project-service-account@pf-test-int-full-e736.iam.gserviceaccount.com --format=json` includes the group email 
     expected: not nil
          got: nil
     ร—  Command: `gcloud iam service-accounts get-iam-policy project-service-account@pf-test-int-full-e736.iam.gserviceaccount.com --format=json` does not overwrite the membership of role roles/iam.serviceAccountUser
     expected: not nil
          got: nil
     โœ”  Command: `gcloud iam service-accounts get-iam-policy project-service-account@pf-test-int-full-e736.iam.gserviceaccount.com --format=json` exit_status should eq 0
     โœ”  Command: `gcloud iam service-accounts get-iam-policy project-service-account@pf-test-int-full-e736.iam.gserviceaccount.com --format=json` stderr should eq ""
  โœ”  project-factory-app-engine: Project Factory App Engine configuration
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:authDomain => "clearify.co"}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:featureSettings => {}}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:id => "pf-test-int-full-e736"}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:name => "apps/pf-test-int-full-e736"}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:locationId => "us-east4"}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` should include {:servingStatus => "SERVING"}
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` exit_status should equal 0
     โœ”  Command: `gcloud app describe --project pf-test-int-full-e736 --format=json` stderr should eq ""
  โ†บ  project-factory-shared-vpc: Project Factory shared VPC
     โ†บ  Skipped control due to only_if condition.
  โœ”  project-factory: Project Factory
     โœ”  Command: `gcloud projects describe pf-test-int-full-e736` exit_status should equal 0
     โœ”  Command: `gcloud projects describe pf-test-int-full-e736` stderr should eq ""
     โœ”  Command: `gcloud services list --project pf-test-int-full-e736` exit_status should equal 0
     โœ”  Command: `gcloud services list --project pf-test-int-full-e736` stderr should eq ""
     โœ”  Command: `gcloud services list --project pf-test-int-full-e736` stdout should match /compute\.googleapis\.com/
     โœ”  Command: `gcloud services list --project pf-test-int-full-e736` stdout should match /container\.googleapis\.com/
     โœ”  Command: `gcloud iam service-accounts list --project pf-test-int-full-e736 --format='json(email)'` includes the Google App Engine API service account user
     โœ”  Command: `gcloud iam service-accounts list --project pf-test-int-full-e736 --format='json(email)'` includes the service account generated by the project factory
     โœ”  Command: `gcloud iam service-accounts list --project pf-test-int-full-e736 --format='json(email)'` includes the service account created outside of the project factory
     โœ”  Command: `gcloud iam service-accounts list --project pf-test-int-full-e736 --format='json(email)'` exit_status should equal 0
     โœ”  Command: `gcloud iam service-accounts list --project pf-test-int-full-e736 --format='json(email)'` stderr should eq ""
  โ†บ  project-factory-sa-role: Project factory service account role
     โ†บ  Skipped control due to only_if condition.
  โ†บ  project-factory-usage: Project factory usage bucket
     โ†บ  Skipped control due to only_if condition.

Precondition step fails if no org_id supplied

  File ".terraform/modules/c158d4e24da0dc3f5e10ff9e6d98ef82/scripts/preconditions/preconditions.py", line 425, in <module>
    retcode = main(sys.argv)
  File ".terraform/modules/c158d4e24da0dc3f5e10ff9e6d98ef82/scripts/preconditions/preconditions.py", line 406, in main
    results.append(validator.validate(credentials))
  File ".terraform/modules/c158d4e24da0dc3f5e10ff9e6d98ef82/scripts/preconditions/preconditions.py", line 125, in validate
    resource = "organizations/" + self.org_id
TypeError: can only concatenate str (not "NoneType") to str

Terraform state deadlock with a limited host project

Summary

The project-factory can use a service account with a misconfigured host project, which leads to a deadlocked Terraform configuration with confusing errors.

Description

The project factory requires that the host project associated with an instantiating service account has certain APIs enabled, but the project factory does not verify that these APIs are enabled before generating a new project. This can cause the project factory to partially generate a new project and then fail, and subsequent calls to terraform apply will fail with a number of related but unhelpful errors.

When terraform apply is run with the misconfigured environment, it will create a new project, attempt to associate a billing account with that project, and fail since cloudbilling.googleapis.com is disabled. Following runs of terraform apply will see that the google_project was created and then attempt to look up the default compute service account with the google_service_account data source. This will fail because the compute.googleapis.com API is not enabled, but this hides the more interesting errors - that the service project doesn't have a billing account enabled, and that the host project doesn't have the Cloud Billing API enabled and thus can't remedy the issue through Terraform.

Expected behavior

When the project-factory runs with a service account whose host project doesn't have the right APIs enabled, it terminates before generating resources.

Actual behavior

First invocation of terraform apply:

module.project-factory.google_project.project: Still creating... (10s elapsed)

Error: Error applying plan:

1 error(s) occurred:

* module.project-factory.google_project.project: 1 error(s) occurred:

* google_project.project: Error setting billing account "<BILLING ACCOUNT>" for project "projects/tftest-1-4901": googleapi: Error 403: Cloud Billing API has not been used in project <HOST NUMBER> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbilling.googleapis.com/overview?project=<HOST NUMBER> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

Note: that the error generated references the host project number on the first failed run.

Running terraform plan or terraform apply

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

random_id.random_project_id_suffix: Refreshing state... (ID: SQE)
data.google_organization.org: Refreshing state...
google_project.project: Refreshing state... (ID: tftest-1-4901)
data.null_data_source.data_given_group_email: Refreshing state...
data.null_data_source.data_final_group_email: Refreshing state...
data.null_data_source.data_group_email_format: Refreshing state...
data.google_compute_default_service_account.default: Refreshing state...

Error: Error refreshing state: 1 error(s) occurred:

* module.project-factory.data.google_compute_default_service_account.default: 1 error(s) occurred:

* module.project-factory.data.google_compute_default_service_account.default: data.google_compute_default_service_account.default: Error reading GCE service account not found: googleapi: Error 403: Project <SERVICE NUMBER> is not found and cannot be used for API calls. If it is recently created, enable Compute Engine API by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=<SERVICE NUMBER> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured

Note: in subsequent runs the error references the service project.

Steps to reproduce

note: these steps are approximate and should be checked to make sure that this reproduces correctly.

  1. Create a new host project, but don't enable any APIs.
  2. Create a service account within that project with helpers/setup-sa.sh.
  • This creates a service account with the correct rights to create projects, but without the APIs enabled that it needs to work
  1. Create a terraform configuration with the project factory.
  2. Run terraform apply; the command should fail.
  3. Verify that terraform can no longer generate a plan with terraform plan

Workarounds

If a terraform configuration is deadlocked in the describe manner, the correct APIs can be enabled retroactively and terraform will be able to run.

  1. Enable cloudbilling.googleapis.com on the host project through the Google Cloud console.
  2. Enable compute.googleapis.com on the service project through the Google Cloud console.
    • Using the console to enable this API will automatically prompt the user to add a billing account.
  3. (Maybe) enable serviceusage.googleapis.com on the host project?

API Page size too small

During preconditions check, if the seed project has a large number of APIs enabled, the python precondition check cannot page and preconditions fail. Suggest increasing the pageSize option as below.

        parent = "projects/" + self.project_id
        request = service.services().list(
            parent=parent,
            filter='state:ENABLED',
            pageSize='200'
        )

Error observed that led to the discovery.
': exit status 1. Output: [
{
"type": "Required APIs on service account project",
"name": "projects/project-abc123",
"satisfied": [
"cloudresourcemanager.googleapis.com",
"appengine.googleapis.com",
"cloudbilling.googleapis.com",
"admin.googleapis.com"
],
"unsatisfied": [
"iam.googleapis.com"
]
},

GCP subnet share conditions not working correctly

Based on the default 3 conditions

  1. No shared_vpc and no subnets => no grants
  2. shared_vpc and no subnets => grant to the project (all networks/subnets)
  3. shared_vpc and subnets => grant to the subnets (and not to the project)

If the subnet id get messed up ( fat finger) while attempting case 3, project factory ends up sharing the entire set of networks in the host project VPC to the service project. Which is a serious security issue. Ideally it should follow step 1 and should not grant any thing and error out.

Script not found error when deleting default service account

I'm trying to use this module to create a gcp project but it fails when it tries to delete the default service account. I'm using google cloud build as a ci tool.

Finished Step #3 Step #3: Step #3: Step #3: above and apply again to incrementally change your infrastructure. Step #3: any resources that successfully completed. Please address the error Step #3: Instead, your Terraform state file has been partially updated with Step #3: Terraform does not automatically rollback in the face of errors. Step #3: Step #3: Step #3: * module.project.module.project-factory.null_resource.delete_default_compute_service_account: Error running command '/workspace/environments/dev/.terraform/modules/112ba820419105134cc3b145beda68a6/scripts/delete-service-account.sh veamly-platform-dev [email protected] ': exit status 127. Output: /bin/sh: /workspace/environments/dev/.terraform/modules/112ba820419105134cc3b145beda68a6/scripts/delete-service-account.sh: not found Step #3: Step #3: 1 error(s) occurred:

Plugins installed in Docker image not detected by Terraform

Running make docker_create after make docker_build_terraform and make docker_build_kitchen_terraform results in the following error:

   Initializing provider plugins...
   - Checking for available provider plugins on https://releases.hashicorp.com...
   
   Provider "gsuite" not available for installation.
   
   A provider named "gsuite" could not be found in the official repository.

Debug output reveals the cause of the issue:

   2018/12/12 18:22:11 [DEBUG] checking for provider in "."
   2018/12/12 18:22:11 [DEBUG] checking for provider in "/cftk/bin"
   2018/12/12 18:22:11 [DEBUG] checking for provider in ".terraform/plugins/linux_amd64"
   2018/12/12 18:22:11 [DEBUG] found provider "terraform-provider-google_v1.19.1_x4"
   2018/12/12 18:22:11 [DEBUG] found provider "terraform-provider-null_v1.0.0_x4"
   2018/12/12 18:22:11 [DEBUG] found provider "terraform-provider-random_v2.0.0_x4"
   2018/12/12 18:22:11 [DEBUG] checking for provider in "/cftk/home/.terraform.d/plugins"
   2018/12/12 18:22:11 [WARN] found legacy provider "terraform-provider-google"
   2018/12/12 18:22:11 [WARN] found legacy provider "terraform-provider-gsuite"
   2018/12/12 18:22:11 [DEBUG] found valid plugin: "google", "0.0.0", "/cftk/home/.terraform.d/plugins/terraform-provider-google"
   2018/12/12 18:22:11 [DEBUG] found valid plugin: "gsuite", "0.0.0", "/cftk/home/.terraform.d/plugins/terraform-provider-gsuite"
   2018/12/12 18:22:11 [DEBUG] found valid plugin: "google", "1.19.1", "/cftk/workdir/test/fixtures/minimal/.terraform/plugins/linux_amd64/terraform-provider-google_v1.19.1_x4"                                                                                                                                        
   2018/12/12 18:22:11 [DEBUG] found valid plugin: "null", "1.0.0", "/cftk/workdir/test/fixtures/minimal/.terraform/plugins/linux_amd64/terraform-provider-null_v1.0.0_x4"                                                                                                                                              
   2018/12/12 18:22:11 [DEBUG] found valid plugin: "random", "2.0.0", "/cftk/workdir/test/fixtures/minimal/.terraform/plugins/linux_amd64/terraform-provider-random_v2.0.0_x4"

Because the plugin version is removed from the filename, Terraform considers the plugin to be v0.0.0 and thus not satisfactory for the ~> 0.1.9 requirement of the test fixture module.

Provide ability to delete default VPC gateway route on project creation

Similar to how we have functionality to delete the default GCE service account, can we add an option to delete default VPC gateway route on the project VPC?

The customer is asking for this feature as they wish to intercept all egress traffic with a security device. They will create their own route for this interception and routing of traffic from the security device to the gateway.

Thanks!

Document dependencies in installation

This module expects to be run on an OS that has been configured for a google cloud developer. If you follow the installation instructions on a fresh, minimal linux install you will encounter unsatisfied dependencies. I have had to add these to my build server:

  1. gcloud
  2. jq
    These ought to be mentioned as requirements

Deprecation warning for "app_engine"

Using v0.21 of this module and v1.19.1 of terraform-provider-google, we see the following warning:

Warning: module.priv-env.module.vault-project.google_project.project: "app_engine": [DEPRECATED] Use the google_app_engine_application resource instead.

Remove `credentials_path` from module req

credentials_path variable is cumbersome to pass when automating things with CICD.

E.g with Jenkins we still need to:

  • upload the service account key file
  • store it in some place that's doesn't get destroyed (so no in the build workspace)
  • refer to the service account keyfile path in our terraform.tfvars, which might be seen by many users

In most cases we could use Application Default Credentials for this.
AFAIK, credentials_path is used only to delete the default service account on a new project.

This is just a tracking issue while we wait for a flag to be added to the API to disable the creation of the default service account.

Shared VPC granting is broken

In #72, we messed up the logic for granting networkUser permission.

There are meant to be 3 different conditions.

  1. No shared_vpc and no subnets => no grants
  2. shared_vpc and no subnets => grant to the project (all networks/subnets)
  3. shared_vpc and subnets => grant to the subnets (and not to the project)

Docker container does not use bundled gems when running Kitchen-Terraform

The Kitchen-Terraform Dockerfile
installs the gem bundle under /opt/kitchen, which is different from the WORKDIR.

Additionally, the Makefile does not use bundler to execute Kitchen.

Since Bundler is context sensitive, the combination of these two points means that the gems provided by the Gemfile are not necessarily used when executing the Kitchen-Terraform tasks in the Makefile.

I discovered this while attempting to test using an alternative source for the Kitchen-Terraform gem.

Remove gsuite requirement from project factory

Currently, the G Suite functionality causes a lot of pain and complexity in set up. We should make it a totally optional component (meaning you can use the project factory without ever installing the G Suite provider).

New architecture:

  • outer wrapper module references inner module
  • gsuite add on handles group creation and service account group management, passes through to inner module
  • inner module which holds all the non-gsuite components from current module

`googleapi: Error 400: Precondition check failed., failedPrecondition` on project creation (setting billing info).

When using project factory to create the projects (during today's training - was online), I couldn't get the project created...

My billing account definitely exists and is correct in the shape 'XXXXXX-XXXXXX-XXXXXX'.

The error I get:

Error: Error applying plan:

1 error(s) occurred:

* module.project-factory.google_project.project: 1 error(s) occurred:

* google_project.project: Error setting billing account "XXXXXX-XXXXXX-XXXXXX" for project "projects/blah-blah-blah-d50d": googleapi: Error 400: Precondition check failed., failedPrecondition

When I try to reproduce with TF_LOG=trace, I get this respose for the request to /v1/projects/alexg-proj-factory-d50d/billingInfo:

2018-09-17T17:19:25.091-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: ---[ RESPONSE ]--------------------------------------
2018-09-17T17:19:25.091-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: HTTP/2.0 400 Bad Request
2018-09-17T17:19:25.091-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Cache-Control: private
2018-09-17T17:19:25.091-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Content-Type: application/json; charset=UTF-8
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Date: Mon, 17 Sep 2018 20:19:25 GMT
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Server: ESF
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Vary: Origin
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Vary: X-Origin
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: Vary: Referer
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: X-Content-Type-Options: nosniff
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: X-Frame-Options: SAMEORIGIN
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: X-Xss-Protection: 1; mode=block
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: {
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:   "error": {
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:     "code": 400,
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:     "message": "Precondition check failed.",
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:     "errors": [
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:       {
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:         "message": "Precondition check failed.",
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:         "domain": "global",
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:         "reason": "failedPrecondition"
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:       }
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:     ],
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:     "status": "FAILED_PRECONDITION"
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:   }
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: }
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4:
2018-09-17T17:19:25.092-0300 [DEBUG] plugin.terraform-provider-google_v1.17.1_x4: -----------------------------------------------------```

This leaved the resources in a strange state and clearning up to restart basically involves manual drop of folders and "half-created" project. `terraform refresh` doesn't work because Compute Engine API is not enabled there (which cannot be done without linking a billing account, of course). But that's another problem - the issue is with 

appengine.googleapis.com not needed

In the main Readme file, it states that Google App Engine Admin API - appengine.googleapis.com is required. I was able to run the module successfully without it, and I don't know why it would be required in the first place.

Maybe just update the Readme file?

My input:

module "project-factory" {
source = "github.com/terraform-google-modules/terraform-google-project-factory"
random_project_id = "true"
name = "${var.team_project_name}"
folder_id = "${var.team_folder_id}"
org_id = "${var.organization_id}"
billing_account = "${var.billing_account}"
credentials_path = "${local.credentials_file_path}"
}

module initialization issue

Initializing modules...

  • module.project-factory
    Found version 0.2.1 of terraform-google-modules/project-factory/google on registry.terraform.io
    Getting source "terraform-google-modules/project-factory/google"

Initializing provider plugins...

Provider "gsuite" not available for installation.

A provider named "gsuite" could not be found in the official repository.

This may result from mistyping the provider name, or the given provider may
be a third-party provider that cannot be installed automatically.

In the latter case, the plugin must be installed manually by locating and
downloading a suitable distribution package and placing the plugin's executable
file in the following directory:
terraform.d/plugins/darwin_amd64

Terraform detects necessary plugins by inspecting the configuration and state.
To view the provider versions requested by each module, run
"terraform providers".

Document installation of preconditions.py requirements

The README does not mention that you need to install the prereqs for precondions.py to run. Maybe we should mention it?

modules/core_project_factory/scripts/preconditions/preconditions.py \
  --credentials_path "/Users/chlove/.config/gcloud/application_default_credentials.json" \
  --billing_account  my-account \
  --org_id my-id
Traceback (most recent call last):
  File "modules/core_project_factory/scripts/preconditions/preconditions.py", line 34, in <module>
    raise e
  File "modules/core_project_factory/scripts/preconditions/preconditions.py", line 25, in <module>
    import google.auth
ModuleNotFoundError: No module named 'google'

I know that I need to run pip3 with the requirements files, but not everyone will know that :)

Error updating secondary IP ranges in Google_compute_subnetwork

So i would like to replace an existing secondary ip range but this fails to work.

Terraform change

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ google_compute_subnetwork.network-with-private-secondary-ip-ranges
      secondary_ip_range.4.ip_cidr_range: "192.168.50.0/24" => "192.168.60.0/24"
      secondary_ip_range.4.range_name:    "secondary-range-50" => "secondary-range-60"


Plan: 0 to add, 1 to change, 0 to destroy.

------------------------------------------------------------------------

Error produced

googleapi: Error 400: Invalid value for field 'resource.secondaryIpRanges': ''. Cannot add and remove secondary IP ranges in the same request. Added ranges: [192.168.60.0/24]. 
Removed ranges: [192.168.50.0/24]., invalid

As this error is from the Google Api, can you please change the way terraform applies this change by deleting first and then adding the change.

Disable dependent services

Hi,
If you try to destroy a project with "complex" APIs activated, you have errors because the option disable_dependent_services is not set:

* google_project_service.project_services.16: Error disabling service: Error disabling service "replicapoolupdater.googleapis.com" for project "test-project-factory-22bd": googleapi: Error 400: The service replicapoolupdater.googleapis.com is depended on by the following active services: resourceviews.googleapis.com,deploymentmanager.googleapis.com,replicapool.googleapis.com; Please specify disable_dependent_services=true if you want to proceed with disabling all services., failedPrecondition
* module.test.module.project-factory.google_project_service.project_services[15] (destroy): 1 error(s) occurred:

* google_project_service.project_services.15: Error disabling service: Error disabling service "replicapool.googleapis.com" for project "test-project-factory-22bd": googleapi: Error 400: The service replicapool.googleapis.com is depended on by the following active services: resourceviews.googleapis.com,replicapoolupdater.googleapis.com,deploymentmanager.googleapis.com; Please specify disable_dependent_services=true if you want to proceed with disabling all services., failedPrecondition
* module.test.module.project-factory.google_project_service.project_services[2] (destroy): 1 error(s) occurred:

* google_project_service.project_services.2: Error disabling service: Error disabling service "containerregistry.googleapis.com" for project "test-project-factory-22bd": googleapi: Error 400: The service containerregistry.googleapis.com is depended on by the following active services: resourceviews.googleapis.com,replicapoolupdater.googleapis.com,container.googleapis.com,deploymentmanager.googleapis.com,replicapool.googleapis.com; Please specify disable_dependent_services=true if you want to proceed with disabling all services., failedPrecondition
* module.test.module.project-factory.google_project_service.project_services[7] (destroy): 1 error(s) occurred:

* google_project_service.project_services.7: Error disabling service: Error disabling service "monitoring.googleapis.com" for project "test-project-factory-22bd": googleapi: Error 400: The service monitoring.googleapis.com is depended on by the following active service: stackdriver.googleapis.com; Please specify disable_dependent_services=true if you want to proceed with disabling all services., failedPrecondition

Fails without shared VPC being specified

If you try to use the Project Factory without a Shared VPC, it fails with this error:

* module.project-demo-without-shared-vpc.google_project_iam_member.controlling_group_vpc_membership: google_project_iam_member.controlling_group_vpc_membership: value of 'count' cannot be computed

broken link in readme for test_preconditions.py

The link contained in the "Verifying Setup" section of the readme.md file is wrong. https://github.com/terraform-google-modules/terraform-google-project-factory#verifying-setup

A preconditions checker script is included to verify that all preconditions are met before the Project Factory runs. The script will run automatically if the script dependencies (Python, "google-auth", and "google-api-python-client") are available at runtime. If the dependencies are not met, the precondition checking step will be skipped.

The precondition checker script can be directly invoked before running the project factory:

./scripts/preconditions/preconditions.py
--credentials_path "./credentials.json"
--billing_account 000000-000000-000000
--org_id 000000000000
--folder_id 000000000000
--shared_vpc 'shared-vpc-host-ed64'

The link in the readme should point to the actual file location as such: https://github.com/terraform-google-modules/terraform-google-project-factory/blob/master/test/scripts/preconditions/test_preconditions.py

But instead it now shows: https://github.com/terraform-google-modules/terraform-google-project-factory/blob/master/scripts/preconditions/preconditions.py

I will create a pull request to fix the readme file.

Permissions required by setup-sa.sh not documented

I have a user that does not have the correct permissions to run the setup-sa.sh script. The documentation does not tell me what permissions I need in order to run this scripts. Here is my error:

 $ ./helpers/setup-sa.sh my-org my-project
Verifying organization...
Verifying project...
Skipping billing account verification... (parameter not passed)
Creating Seed Service Account...
Created service account [project-factory-6999].
Downloading key to credentials.json...
Applying permissions for org org-number and project chlove-baseproject...
ERROR: (gcloud.organizations.add-iam-policy-binding) User [[email protected]] does not have permission to access organization [org-number:getIamPolicy] (or it may not exist): The caller does not have permission

I removed org number and project id for security sake.

What permissions does the user need to run the setup-sa.sh script?

Incorrect state with API Activations

We were ironing out some permission issues so needed to re-run a TF pipeline a few times. It appears possible to create a project, fail to activate the right APIs, and then cause other parts of the pipeline to fail. (Note: the module name is our internal fork of project factory with no changes).

To reproduce, try to create a new project using a Service Account lacking this permission:

module.project-factory-project.module.sfdc_project.data.google_organization.org: data.google_organization.org: Error reading Organization Not Found : organizations/849937818733: googleapi: Error 403: The caller does not have permission, forbidden

If you fix that, then you will get this error:

Error: Error refreshing state: 1 error(s) occurred:
 * module.project-factory-project.module.sfdc_project.data.google_compute_default_service_account.default: 1 error(s) occurred:
 * module.project-factory-project.module.sfdc_project.data.google_compute_default_service_account.default: data.google_compute_default_service_account.default: Error reading GCE service account not found: googleapi: Error 403: Project 722914074885 is not found and cannot be used for API calls. If it is recently created, enable Compute Engine API by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=722914074885 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured

All subsequent plans will fail because this call happens early in the plan, preventing the rest.

Required test variables have empty defaults

Several of the tests have variables with blank defaults when they are actually required (and tests fail to run if they're not provided). For example: https://github.com/terraform-google-modules/terraform-google-project-factory/blob/master/test/fixtures/full/variables.tf#L55

In general, blank defaults are an anti-pattern which we should strongly avoid. It's against our standards. Please check through all variables again and confirm that everything with a default value can be left at the default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.