Skip to content

Commit

Permalink
Implement FAST stage add-ons, refactor netsec as add-on (#2800)
Browse files Browse the repository at this point in the history
* security fixes

* change netsec to be a virtual stage in resman

* remove netsec bits from security stage, leave CAs in place

* netsec - security profile groups

* export regions to networking tfvars

* netsec - trust stores

* netsec refactor, untested

* netsec plan working

* netsec apply

* netsec apply errors

* netsec diagram

* update diagram

* move addon stages to addons folder

* remove top-level assets folder

* deprecate and remove fast plugins

* addon tests

* dynamic addon providers and cicd, untested

* stage 1 addons in stage 0, refactor stage 0 cicd

* addons and cicd refactor in stage 0 with tests

* refactor stage 0 cicd

* readd removed block

* small bootstrap cicd fixes

* refactor stage 1 cicd

* resman tests

* remove plugins from networking tests

* fix fast tests

* ngfw addon outputs

* try to fix unrelated tflint error in bootstrap

* remove common tfvars from bootstrap tests to fix linter errors

* tfdoc

* minimal readmes and links fixes

* tfdoc

* trim down test inventories

* fix plan test

* tfdoc

* allow configuring output files names

* fix tls inspection after adding count to project module

* comment fixes

* tfdoc
  • Loading branch information
ludoo authored Jan 9, 2025
1 parent d6d582e commit 27f1cc2
Show file tree
Hide file tree
Showing 138 changed files with 2,534 additions and 4,645 deletions.
13 changes: 3 additions & 10 deletions fast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ FAST uses YAML-based factories to deploy subnets and firewall rules and, as its

One of our objectives with FAST is to provide a lightweight reference design for the IaC repositories, and a built-in implementation for running our code in automated pipelines. Our CI/CD approach leverages [Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation), and provides sample workflow configurations for several major providers. Refer to the [CI/CD section in the bootstrap stage](./stages/0-bootstrap/README.md#cicd) for more details. We also provide separate [optional small stages](./extras/) to help you configure your CI/CD provider.

<!-- TODO: move CI/CD documentation to its own file -->

### Multitenant organizations

FAST has built-in support for multitenancy implemented in [an optional stage 1](./stages/1-tenant-factory/). Tenants can optionally be created with FAST compatibility, allowing them independent use of stages 1+ in their own context.
FAST has built-in support for multitenancy implemented in [an add-on stage](./addons/1-resman-tenants/). Tenants can optionally be created with FAST compatibility, allowing them independent use of stages 1+ in their own context.

The following diagram is a high-level overview of stages used with multitenancy.

Expand All @@ -64,12 +66,3 @@ Since we expect users to customize FAST to their specific needs, we strive to ma
We also recognize that FAST users don't need all of its features. Therefore, you don't need to use our project factory or our GKE implementation if you don't want to. Instead, remove those stages or pieces of code and keep what suits you.

Those familiar with Python will note that FAST follows many of the maxims in the [Zen of Python](https://www.python.org/dev/peps/pep-0020/#id2).

## Roadmap

Besides the features already described, FAST also includes:

- Stage to deploy environment-specific multitenant GKE clusters following Google's best practices
- Stage to deploy a fully featured data platform
- Reference implementation to use FAST in CI/CD pipelines
- Static policy enforcement (planned)

Large diffs are not rendered by default.

File renamed without changes
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/

locals {
default_environment = [
for k, v in var.environments : v if v.is_default == true
][0]
tenants = {
for k, v in var.tenant_configs : k => merge(v, {
billing_account = merge(v.billing_account, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ resource "local_file" "providers-simple" {
for k, v in local.tenants : k => local.tenant_data[k]
}
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/providers/tenant-${each.key}.tf"
filename = "${try(pathexpand(var.outputs_location), "")}/providers/${var.names.output_files_prefix}-${each.key}.tf"
content = templatefile(local._tpl_providers, {
backend_extra = null
bucket = each.value.gcs_bucket
Expand All @@ -35,21 +35,21 @@ resource "local_file" "tfvars-simple" {
for k, v in local.tenants : k => local.tenant_data[k]
}
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tfvars/tenant-${each.key}.auto.tfvars.json"
filename = "${try(pathexpand(var.outputs_location), "")}/tfvars/${var.names.output_files_prefix}-${each.key}.auto.tfvars.json"
content = jsonencode(each.value)
}

resource "local_file" "providers" {
for_each = var.outputs_location == null ? {} : local.tenant_providers
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tenants/${each.key}/providers/1-resman-providers.tf"
filename = "${try(pathexpand(var.outputs_location), "")}/${var.names.output_files_prefix}/${each.key}/providers/1-resman-providers.tf"
content = try(each.value, null)
}

resource "local_file" "providers-r" {
for_each = var.outputs_location == null ? {} : local.tenant_providers_r
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tenants/${each.key}/providers/1-resman-r-providers.tf"
filename = "${try(pathexpand(var.outputs_location), "")}/${var.names.output_files_prefix}/${each.key}/providers/1-resman-r-providers.tf"
content = try(each.value, null)
}

Expand All @@ -59,20 +59,20 @@ resource "local_file" "tfvars" {
for k, v in local.tenant_tfvars : k => v if var.outputs_location != null
}
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tenants/${each.key}/tfvars/0-bootstrap.auto.tfvars.json"
filename = "${try(pathexpand(var.outputs_location), "")}/${var.names.output_files_prefix}/${each.key}/tfvars/0-bootstrap.auto.tfvars.json"
content = jsonencode(each.value)
}

resource "local_file" "tfvars_globals" {
for_each = var.outputs_location == null ? {} : local.tenant_globals
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tenants/${each.key}/tfvars/0-globals.auto.tfvars.json"
filename = "${try(pathexpand(var.outputs_location), "")}/${var.names.output_files_prefix}/${each.key}/tfvars/0-globals.auto.tfvars.json"
content = jsonencode(each.value)
}

resource "local_file" "workflows" {
for_each = var.outputs_location == null ? {} : local.tenant_cicd_workflows
file_permission = "0644"
filename = "${try(pathexpand(var.outputs_location), "")}/tenants/${each.key}/workflows/1-resman-workflow.yaml"
filename = "${try(pathexpand(var.outputs_location), "")}/${var.names.output_files_prefix}/${each.key}/workflows/1-resman-workflow.yaml"
content = try(each.value, null)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ resource "google_storage_bucket_object" "providers-simple" {
for k, v in local.tenants : k => local.tenant_data[k]
}
bucket = var.automation.outputs_bucket
name = "providers/tenant-${each.key}.tf"
name = "providers/${var.names.output_files_prefix}-${each.key}.tf"
content = templatefile(local._tpl_providers, {
backend_extra = null
bucket = each.value.gcs_bucket
Expand All @@ -35,7 +35,7 @@ resource "google_storage_bucket_object" "tfvars-simple" {
for k, v in local.tenants : k => local.tenant_data[k]
}
bucket = var.automation.outputs_bucket
name = "tfvars/tenant-${each.key}.auto.tfvars.json"
name = "tfvars/${var.names.output_files_prefix}-${each.key}.auto.tfvars.json"
content = jsonencode(each.value)
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module "tenant-core-logbucket" {
for_each = local.tenants
parent_type = "project"
parent = var.logging.project_id
id = "tn-${each.key}-audit"
id = "${var.names.resource_short_name}-${each.key}-audit"
location = var.locations.logging
log_analytics = { enable = true }
}
Expand All @@ -36,7 +36,7 @@ module "tenant-core-folder" {
parent = local.root_node
name = "${each.value.descriptive_name} Core"
logging_sinks = {
"tn-${each.key}-audit" = {
"${var.names.resource_short_name}-${each.key}-audit" = {
destination = module.tenant-core-logbucket[each.key].id
filter = <<-FILTER
log_id("cloudaudit.googleapis.com/activity") OR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ locals {
}
fast_tenants = {
for k, v in local._fast_tenants : k => merge(v, {
stage_0_prefix = "${v.prefix}-prod"
stage_0_prefix = "${v.prefix}-${local.default_environment.short_name}"
principals = {
for gk, gv in v.groups : gk => (
can(regex("^[a-zA-Z]+:", gv))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ module "automation-tf-cicd-r-sa" {
source = "../../../modules/iam-service-account"
for_each = local.cicd_repositories
project_id = var.automation.project_id
name = "tenant-${each.key}-1r"
name = "${each.key}-1r"
display_name = "Terraform CI/CD ${each.key} service account (read-only)."
prefix = var.prefix
iam = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module "tenant-sa" {
source = "../../../modules/iam-service-account"
for_each = local.tenants
project_id = var.automation.project_id
name = "tn-${each.key}-0"
name = "${var.names.resource_short_name}-${each.key}-0"
display_name = "Terraform tenant ${each.key} service account."
prefix = var.prefix
iam = {
Expand All @@ -114,7 +114,7 @@ module "tenant-gcs" {
source = "../../../modules/gcs"
for_each = local.tenants
project_id = var.automation.project_id
name = "tn-${each.key}-0"
name = "${var.names.resource_short_name}-${each.key}-0"
prefix = var.prefix
location = each.value.locations.gcs
versioning = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ variable "custom_roles" {
default = null
}

variable "environments" {
# tfdoc:variable:source 0-globals
description = "Environment names."
type = map(object({
name = string
short_name = string
tag_name = string
is_default = optional(bool, false)
}))
nullable = false
validation {
condition = anytrue([
for k, v in var.environments : v.is_default == true
])
error_message = "At least one environment should be marked as default."
}
}

variable "groups" {
# tfdoc:variable:source 0-bootstrap
# https://cloud.google.com/docs/enterprise/setup-checklist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
* limitations under the License.
*/

# TODO: backport names variable from resman stage
variable "names" {
description = "Configuration for names used for resources and output files."
type = object({
output_files_prefix = optional(string, "2-resman-tenants")
resource_short_name = optional(string, "tn")
})
nullable = false
default = {}
}

variable "outputs_location" {
description = "Path where providers and tfvars files for the following stages are written. Leave empty to disable."
type = string
Expand Down
5 changes: 5 additions & 0 deletions fast/addons/2-networking-ngfw/.fast-stage.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FAST_STAGE_DESCRIPTION="NGFW Enterprise networking add-on"
FAST_STAGE_LEVEL=2
FAST_STAGE_NAME=networking-ngfw
FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman 2-networking"
FAST_STAGE_OPTIONAL="2-security"
Loading

0 comments on commit 27f1cc2

Please sign in to comment.