Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions fast/stages/0-init/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Fast Init

<!-- BEGIN TOC -->
<!-- END TOC -->

This stage establishes all the prerequisites required to execute 0-org-setup stage.

## Prerequisites

To successfully execute this stage, ensure the following are available:

* An organization
* A billing account
* A user belonging to a group that has the Organization Administrator role granted

In addition to that, edit the `datasets/[FACTORY-NAME]/default.yaml` file inside the `0-org-setup` stage, where `FACTORY-NAME` should be the factory of your choice (classic, hardened, etc), and populate the following:

* The billing account ID (`global.billing_account`)
* The organization ID (`global.organization.id`)
* The prefix to use for projects in your organization (`global.projects.defaults.prefix`)
* The group representing your organization admins (`context.iam_principals.gcp-organization-admins`)

To be able to run the `0-org-setup` stage we need a project to pre-exist in the organization. Some of the APIs enabled in the `0-org-setup` stage require a billing project. By default, this stage will create a project for you and enable those APIs in it. If however, you prefer that the APIs are enabled in an already existing in your organization, just create a `terraform.tfvars` and enter the project ID as follows:

```hcl
default_project_config = {
project_id = "YOUR_PROJECT_ID"
}
```

By the default this stage will use the config file in `0-org-setup/classic/default.yaml`. In case you would like to use a different one, just add this to your terraform.tfvars

```hcl
default_factory_config = "datasets/YOUR-PREFERRED-FACTORY/default.yaml"
```

## Deployment

Once you have set these values you can run the stage by executing the following in the 0-init folder:

```bash
terraform init
terraform apply
```

## Post-deployment

When terraform completes, take the `project_id` output and set your default project using gcloud CLI

```bash
gcloud config set project $(terraform output project_id)
```

Finally take the value of the `existing_org_policies` and add it to the terraform.tfvars of the `0-org-setup` stage

```bash
terraform output existing_org_policies > terraform.tfvars
```

Now you are ready to go to the `0-org-setup` stage!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the default vars/outputs tables.

82 changes: 82 additions & 0 deletions fast/stages/0-init/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright 2026 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.
*/

locals {
default_config = yamldecode(file("${path.module}/../0-org-setup/${var.defaults_factory_config}"))
organization_id = local.default_config.global.organization.id
parent = "organizations/${local.organization_id}"
billing_account_id = local.default_config.global.billing_account
prefix = local.default_config.projects.defaults.prefix
iam_principal = local.default_config.context.iam_principals.gcp-organization-admins
active_org_policies = [
for x in data.google_cloud_asset_search_all_resources.policies.results :
x.display_name
if x.parent_asset_type == "cloudresourcemanager.googleapis.com/Organization"
]
}

module "organization" {
source = "../../../modules/organization"
organization_id = local.parent
iam_by_principals_additive = {
(local.iam_principal) = [
"roles/cloudasset.viewer",
"roles/billing.admin",
"roles/logging.admin",
"roles/iam.organizationRoleAdmin",
"roles/orgpolicy.policyAdmin",
"roles/resourcemanager.folderAdmin",
"roles/resourcemanager.organizationAdmin",
"roles/resourcemanager.projectCreator",
"roles/resourcemanager.tagAdmin",
"roles/owner"
]
}
}

resource "random_string" "suffix" {
length = 5
special = false
upper = false
}

module "project" {
source = "../../../modules/project"
billing_account = var.default_project_config.create ? local.billing_account_id : null
name = coalesce(
var.default_project_config.id,
"${local.prefix}-init-${random_string.suffix.result}"
)
parent = var.default_project_config.create ? local.parent : null
prefix = local.prefix
Comment on lines +61 to +64

@juliocc juliocc Feb 5, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure prefix is handled correctly here. We're setting it explicitely in line 61 and again in line 64.

services = [
"bigquery.googleapis.com",
"cloudbilling.googleapis.com",
"cloudresourcemanager.googleapis.com",
"essentialcontacts.googleapis.com",
"iam.googleapis.com",
"logging.googleapis.com",
"orgpolicy.googleapis.com",
"serviceusage.googleapis.com"
]
}

data "google_cloud_asset_search_all_resources" "policies" {
scope = module.organization.id
asset_types = [
"orgpolicy.googleapis.com/Policy"
]
}
21 changes: 21 additions & 0 deletions fast/stages/0-init/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
output "existing_org_policies" {
description = "Variable containing existing organization policies to be added to the terraform.tfvars of the 0-org-setup stage."
value = <<-EOF
x = [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update variable name (I think it's org_policies_import)

%{for val in local.active_org_policies~}
"${val}",
%{endfor~}
]
EOF
}

output "project_id" {
description = "ID of the project to be used as billing project."
value = <<-EOF
x = [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update value

%{for val in local.active_org_policies~}
"${val}",
%{endfor~}
]
EOF
}
36 changes: 36 additions & 0 deletions fast/stages/0-init/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2026 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 "defaults_factory_config" {
description = "Defaults factory config."
type = string
nullable = false
default = "datasets/classic/defaults.yaml"
}

variable "default_project_config" {
description = "Flag indicating whether a temporary project needs be created."
type = object({
id = optional(string)
create = optional(bool, true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not used, at the moment.

})
default = {}
nullable = false
validation {
condition = var.default_project_config.create || var.default_project_config.id != null
error_message = "When 'create' is false a project id must be provided."
}
}
Loading