This stage sets up an area dedicated to hosting security resources and configurations which impact the whole organization, or are shared across the hierarchy to other projects and teams.
The design of this stage is fairly general, and out of the box it only provides a reference example for Cloud KMS.
Expanding it to include other security-related services like Secret Manager is fairly simple by adapting the provided implementation for Cloud KMS, and leveraging the broad permissions granted on the top-level Security folder to the automation service account used here.
The following diagram illustrates the high-level design of resources managed here:
Project-level security resources are grouped into two separate projects, one per environment. This setup matches requirements we frequently observe in real life and provides enough separation without needlessly complicating operations.
Cloud KMS is configured and designed mainly to encrypt GCP resources with a Customer-managed encryption key but it may be used to create cryptokeys used to encrypt application data too.
IAM for day to day operations is already assigned at the folder level to the security team by the previous stage, but more granularity can be added here at the project level, to grant control of separate services across environments to different actors.
A reference Cloud KMS implementation is part of this stage, to provide a simple way of managing centralized keys, that are then shared and consumed widely across the organization to enable customer-managed encryption. The implementation is also easy to clone and modify to support other services like Secret Manager.
The Cloud KMS configuration allows defining keys by name (typically matching the downstream service that uses them) in different locations. It then takes care internally of provisioning the relevant keyrings and creating keys in the appropriate location.
IAM roles on keys can be configured at the logical level for all locations where a logical key is created. Their management can also be delegated via delegated role grants exposed through a simple variable, to allow other identities to set IAM policies on keys. This is particularly useful in setups like project factories, making it possible to configure IAM bindings during project creation for team groups or service agent accounts (compute, storage, etc.).
With this stage you can leverage Certificate Authority Services (CAS) and create as many CAs you need for each environments. To create custom CAS, you can use the cas_configs
variable. The variable comes with some defaults, useful for demos: in each environment, specifying the CA location
should be enough for most of your test scenarios.
The stage lets you also create Certificate Manager trust configs. With trust configs you can trust whole CAs or specific server certificates, when you use them with other services, such as NGFW Enterprise. You can create additional trust configs for each environment with the trust_configs
variable. At a very minimum, each trust config needs a location
(the region) and either a trust_stores
block or an allowed_certificates
block.
We deploy NGFW Enterprise in the network-security stage. If you require TLS inspection, NGFW needs to interact with CAS and -optionally- Certificate Manager trust-configs. These components bind to firewall endpoint associations (created in the network-security stage) with zonal TLS inspection policies.
Using this module, you can define CAS configurations and trust-configs for NGFW Enterprise. You can create them using the cas_configs
and trust_configs
variables. Anyway, these will need to use specific keys (defined in ngfw_tls_configs.keys
), so that FAST knows which configurations to use for NGFW Enterprise.
You can then enable TLS inspection and customize its behavior for NGFW Enterprise, using the ngfw_tls_configs.tls_inspection
variable. FAST will create the TLS inspection policies for you in the regions where you defined your CAs for NGFW Enterprise.
When you create your CAs and trust-configs for NGFW Enterprise, make sure their region matches the zones where you will define your firewall endpoints.
You can read more about NGFW configurations in the Customizations section of this document.
This stage is meant to be executed after the resource management stage has run, as it leverages the automation service account and bucket created there, and additional resources configured in the bootstrap stage.
It's of course possible to run this stage in isolation, but that's outside the scope of this document, and you would need to refer to the code for the previous stages for the environmental requirements.
Before running this stage, you need to make sure you have the correct credentials and permissions, and localize variables by assigning values that match your configuration.
As all other FAST stages, the mechanism used to pass variable values and pre-built provider files from one stage to the next is also leveraged here.
The commands to link or copy the provider and terraform variable files can be easily derived from the stage-links.sh
script in the FAST root folder, passing it a single argument with the local output files folder (if configured) or the GCS output bucket in the automation project (derived from stage 0 outputs). The following examples demonstrate both cases, and the resulting commands that then need to be copy/pasted and run.
../../stage-links.sh ~/fast-config
# copy and paste the following commands for '2-security'
ln -s ~/fast-config/providers/2-security-providers.tf ./
ln -s ~/fast-config/tfvars/0-globals.auto.tfvars.json ./
ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./
ln -s ~/fast-config/tfvars/1-resman.auto.tfvars.json ./
../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
# copy and paste the following commands for '2-security'
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-security-providers.tf ./
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./
The preconfigured provider file uses impersonation to run with this stage's automation service account's credentials. The gcp-devops
and organization-admins
groups have the necessary IAM bindings in place to do that, so make sure the current user is a member of one of those groups.
Variables in this stage -- like most other FAST stages -- are broadly divided into three separate sets:
- variables which refer to global values for the whole organization (org id, billing account id, prefix, etc.), which are pre-populated via the
0-globals.auto.tfvars.json
file linked or copied above - variables which refer to resources managed by previous stages, which are prepopulated here via the
0-bootstrap.auto.tfvars.json
and1-resman.auto.tfvars.json
files linked or copied above - and finally variables that optionally control this stage's behaviour and customizations, and can to be set in a custom
terraform.tfvars
file
The latter set is explained in the Customization sections below, and the full list can be found in the Variables table at the bottom of this document.
Note that the outputs_location
variable is disabled by default, you need to explicitly set it in your terraform.tfvars
file if you want output files to be generated by this stage. This is a sample terraform.tfvars
that configures it, refer to the bootstrap stage documentation for more details:
outputs_location = "~/fast-config"
This configuration is possible but unsupported and only exists for development purposes, use at your own risk:
- temporarily switch
billing_account.id
tonull
in0-globals.auto.tfvars.json
- for each project resources in the project modules used in this stage (
dev-sec-project
,prod-sec-project
)- apply using
-target
, for exampleterraform apply -target 'module.prod-sec-project.google_project.project[0]'
- untaint the project resource after applying, for example
terraform untaint 'module.prod-sec-project.google_project.project[0]'
- apply using
- go through the process to associate the billing account with the two projects
- switch
billing_account.id
back to the real billing account id - resume applying normally
Once provider and variable values are in place and the correct user is configured, the stage can be run:
terraform init
terraform apply
Cloud KMS configuration is controlled by kms_keys
, which configures the actual keys to create, and also allows configuring their IAM bindings, labels, locations and rotation period. When configuring locations for a key, please consider the limitations each cloud product may have.
The additional kms_restricted_admins
variable allows granting roles/cloudkms.admin
to specified principals, restricted via delegated role grants so that it only allows granting the roles needed for encryption/decryption on keys. This allows safe delegation of key management to subsequent Terraform stages like the Project Factory, for example to grant usage access on relevant keys to the service agent accounts for compute, storage, etc.
To support these scenarios, key IAM bindings are configured by default to be additive, to enable other stages or Terraform configuration to safely co-manage bindings on the same keys. If this is not desired, follow the comments in the core-dev.tf
and core-prod.tf
files to switch to authoritative bindings on keys.
An example of how to configure keys:
# terraform.tfvars
kms_keys = {
compute = {
iam = {
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
"user:[email protected]"
]
}
labels = { service = "compute" }
locations = ["europe-west1", "europe-west3", "global"]
rotation_period = "7776000s"
}
storage = {
iam = null
labels = { service = "compute" }
locations = ["europe"]
rotation_period = null
}
}
The script will create one keyring for each specified location and keys on each keyring.
This is a minimal configuration that creates a CAs for each environment and enables TLS inspection policies for NGFW Enterprise.
cas_configs = {
dev = {
ngfw-dev-cas-0 = {
location = "europe-west1"
}
}
prod = {
ngfw-prod-cas-0 = {
location = "europe-west1"
}
}
}
tls_inspection = {
enabled = true
}
You can optionally create also trust-configs for NGFW Enterprise.
cas_configs = {
dev = {
ngfw-dev-cas-0 = {
location = "europe-west1"
}
}
prod = {
ngfw-prod-cas-0 = {
location = "europe-west1"
}
}
}
trust_configs = {
dev = {
ngfw-dev-tc-0 = {
allowlisted_certificates = {
my_ca = "~/my_keys/srv-dev.crt"
}
location = "europe-west1"
}
}
prod = {
ngfw-prod-tc-0 = {
allowlisted_certificates = {
my_ca = "~/my_keys/srv-prod.crt"
}
location = "europe-west1"
}
}
}
tls_inspection = {
enabled = true
}
You can customize the keys of your configurations, as long as they match the ones you specify in the ngfw_tls_configs.keys
variable.
cas_configs = {
dev = {
my-ca-0 = {
location = "europe-west1"
}
}
}
ngfw_tls_configs = {
keys = {
dev = {
cas = "my-ca-0"
}
}
}
tls_inspection = {
enabled = true
}
name | description | modules | resources |
---|---|---|---|
core-dev.tf | None | certificate-authority-service · kms · project |
google_certificate_manager_trust_config · google_network_security_tls_inspection_policy |
core-prod.tf | None | certificate-authority-service · kms · project |
google_certificate_manager_trust_config · google_network_security_tls_inspection_policy |
main.tf | Module-level locals and resources. | folder |
|
outputs.tf | Module outputs. | google_storage_bucket_object · local_file |
|
variables-fast.tf | None | ||
variables.tf | Module variables. |
name | description | type | required | default | producer |
---|---|---|---|---|---|
automation | Automation resources created by the bootstrap stage. | object({…}) |
✓ | 0-bootstrap |
|
billing_account | Billing account id. If billing account is not part of the same org set is_org_level to false. |
object({…}) |
✓ | 0-bootstrap |
|
folder_ids | Folder name => id mappings, the 'security' folder name must exist. | object({…}) |
✓ | 1-resman |
|
organization | Organization details. | object({…}) |
✓ | 0-bootstrap |
|
prefix | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string |
✓ | 0-bootstrap |
|
service_accounts | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) |
✓ | 1-resman |
|
cas_configs | The CAS CAs to add to each environment. | object({…}) |
{…} |
||
essential_contacts | Email used for essential contacts, unset if null. | string |
null |
||
kms_keys | KMS keys to create, keyed by name. | map(object({…})) |
{} |
||
ngfw_tls_configs | The CAS and trust configurations key names to be used for NGFW Enterprise. | object({…}) |
{…} |
||
outputs_location | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string |
null |
||
trust_configs | The trust configs grouped by environment. | object({…}) |
{…} |
name | description | sensitive | consumers |
---|---|---|---|
cas_configs | Certificate Authority Service configurations. | ||
kms_keys | KMS key ids. | ||
ngfw_tls_configs | The NGFW Enterprise configurations. | ||
tfvars | Terraform variable files for the following stages. | ✓ | |
trust_config_ids | Certificate Manager trust-config ids. |