* add support for URL filtering profiles to FAST NGFW add-on * fix YAML linting, add yamllint to pre-commit
298 lines
10 KiB
HCL
298 lines
10 KiB
HCL
/**
|
|
* 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 "certificate_authorities" {
|
|
description = "Certificate Authority Service pool and CAs. If host project ids is null identical pools and CAs are created in every host project."
|
|
type = map(object({
|
|
location = string
|
|
iam = optional(map(list(string)), {})
|
|
iam_bindings = optional(map(any), {})
|
|
iam_bindings_additive = optional(map(any), {})
|
|
iam_by_principals = optional(map(list(string)), {})
|
|
ca_configs = map(object({
|
|
deletion_protection = optional(string, true)
|
|
type = optional(string, "SELF_SIGNED")
|
|
is_ca = optional(bool, true)
|
|
lifetime = optional(string, null)
|
|
pem_ca_certificate = optional(string, null)
|
|
ignore_active_certificates_on_deletion = optional(bool, false)
|
|
skip_grace_period = optional(bool, true)
|
|
labels = optional(map(string), null)
|
|
gcs_bucket = optional(string, null)
|
|
key_spec = optional(object({
|
|
algorithm = optional(string, "RSA_PKCS1_2048_SHA256")
|
|
kms_key_id = optional(string, null)
|
|
}), {})
|
|
key_usage = optional(object({
|
|
cert_sign = optional(bool, true)
|
|
client_auth = optional(bool, false)
|
|
code_signing = optional(bool, false)
|
|
content_commitment = optional(bool, false)
|
|
crl_sign = optional(bool, true)
|
|
data_encipherment = optional(bool, false)
|
|
decipher_only = optional(bool, false)
|
|
digital_signature = optional(bool, false)
|
|
email_protection = optional(bool, false)
|
|
encipher_only = optional(bool, false)
|
|
key_agreement = optional(bool, false)
|
|
key_encipherment = optional(bool, true)
|
|
ocsp_signing = optional(bool, false)
|
|
server_auth = optional(bool, true)
|
|
time_stamping = optional(bool, false)
|
|
}), {})
|
|
subject = optional(
|
|
object({
|
|
common_name = string
|
|
organization = string
|
|
country_code = optional(string)
|
|
locality = optional(string)
|
|
organizational_unit = optional(string)
|
|
postal_code = optional(string)
|
|
province = optional(string)
|
|
street_address = optional(string)
|
|
}),
|
|
{
|
|
common_name = "test.example.com"
|
|
organization = "Test Example"
|
|
}
|
|
)
|
|
subject_alt_name = optional(object({
|
|
dns_names = optional(list(string), null)
|
|
email_addresses = optional(list(string), null)
|
|
ip_addresses = optional(list(string), null)
|
|
uris = optional(list(string), null)
|
|
}), null)
|
|
subordinate_config = optional(object({
|
|
root_ca_id = optional(string)
|
|
pem_issuer_certificates = optional(list(string))
|
|
}), null)
|
|
}))
|
|
ca_pool_config = optional(object({
|
|
create_pool = optional(object({
|
|
name = optional(string)
|
|
tier = optional(string, "DEVOPS")
|
|
}))
|
|
use_pool = optional(object({
|
|
id = string
|
|
}))
|
|
}))
|
|
}))
|
|
nullable = false
|
|
default = {}
|
|
}
|
|
|
|
variable "enable_services" {
|
|
description = "Configure project by enabling services required for this add-on."
|
|
type = bool
|
|
nullable = false
|
|
default = true
|
|
}
|
|
|
|
variable "names" {
|
|
description = "Configuration for names used for output files."
|
|
type = object({
|
|
output_files_prefix = optional(string, "2-networking-ngfw")
|
|
})
|
|
nullable = false
|
|
default = {}
|
|
}
|
|
|
|
variable "ngfw_config" {
|
|
description = "Configuration for NGFW Enterprise endpoints. Billing project defaults to the automation project. Network and TLS inspection policy ids support interpolation."
|
|
type = object({
|
|
endpoint_zones = list(string)
|
|
name = optional(string, "ngfw-0")
|
|
network_associations = optional(map(object({
|
|
vpc_id = string
|
|
disabled = optional(bool)
|
|
tls_inspection_policy = optional(string)
|
|
zones = optional(list(string))
|
|
})), {})
|
|
})
|
|
nullable = false
|
|
}
|
|
|
|
variable "outputs_location" {
|
|
description = "Path where providers and tfvars files for the following stages are written. Leave empty to disable."
|
|
type = string
|
|
default = null
|
|
}
|
|
|
|
variable "project_id" {
|
|
description = "Project where the network security resources will be created."
|
|
type = string
|
|
nullable = false
|
|
}
|
|
|
|
variable "security_profiles" {
|
|
description = "Security profile groups for Layer 7 inspection. Null environment list means all environments."
|
|
type = map(object({
|
|
description = optional(string)
|
|
threat_prevention_profile = optional(object({
|
|
severity_overrides = optional(map(object({
|
|
action = string
|
|
severity = string
|
|
})))
|
|
threat_overrides = optional(map(object({
|
|
action = string
|
|
threat_id = string
|
|
})))
|
|
}), {})
|
|
url_filtering_profile = optional(map(object({
|
|
action = string
|
|
priority = number
|
|
urls = optional(list(string), ["*"])
|
|
})), {})
|
|
}))
|
|
nullable = false
|
|
default = {
|
|
ngfw-default = {}
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for _, v in var.security_profiles : [
|
|
for _, sv in coalesce(v.threat_prevention_profile.severity_overrides, {}) : (
|
|
contains(["ALERT", "ALLOW", "DEFAULT_ACTION", "DENY"], sv.action) &&
|
|
contains(["CRITICAL", "HIGH", "INFORMATIONAL", "LOW", "MEDIUM"], sv.severity)
|
|
)
|
|
]
|
|
]))
|
|
error_message = "Incorrect severity override token."
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for k, v in var.security_profiles : [
|
|
for lk, lv in coalesce(v.threat_prevention_profile.severity_overrides, {}) : (
|
|
contains(["ALERT", "ALLOW", "DEFAULT_ACTION", "DENY"], lv.action)
|
|
)
|
|
]
|
|
]))
|
|
error_message = "Severity override action must be one of ALERT, ALLOW, DEFAULT_ACTION, DENY."
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for _, v in var.security_profiles : [
|
|
for _, sv in coalesce(v.threat_prevention_profile.threat_overrides, {}) : (
|
|
contains(["ALERT", "ALLOW", "DEFAULT_ACTION", "DENY"], sv.action)
|
|
)
|
|
]
|
|
]))
|
|
error_message = "Incorrect threat override token."
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for k, v in var.security_profiles : [
|
|
for lk, lv in coalesce(v.threat_prevention_profile.threat_overrides, {}) : (
|
|
contains(["ALERT", "ALLOW", "DEFAULT_ACTION", "DENY"], lv.action)
|
|
)
|
|
]
|
|
]))
|
|
error_message = "Threat override action must be one of ALERT, ALLOW, DEFAULT_ACTION, DENY."
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for k, v in var.security_profiles : [
|
|
for lk, lv in coalesce(v.url_filtering_profile, {}) : length(lv.urls) > 0
|
|
]
|
|
]))
|
|
error_message = "URL filtering rules must have at least one URL."
|
|
}
|
|
validation {
|
|
condition = alltrue(flatten([
|
|
for k, v in var.security_profiles : [
|
|
for lk, lv in coalesce(v.url_filtering_profile, {}) : contains(["ALLOW", "DENY"], lv.action)
|
|
]
|
|
]))
|
|
error_message = "URL filtering rule action must be ALLOW or DENY."
|
|
}
|
|
}
|
|
|
|
variable "tls_inspection_policies" {
|
|
description = "TLS inspection policies configuration. CA pools, trust configs and host project ids support interpolation."
|
|
type = map(object({
|
|
ca_pool_id = string
|
|
location = string
|
|
exclude_public_ca_set = optional(bool)
|
|
trust_config = optional(string)
|
|
tls = optional(object({
|
|
custom_features = optional(list(string))
|
|
feature_profile = optional(string)
|
|
min_version = optional(string)
|
|
}), {})
|
|
}))
|
|
nullable = false
|
|
default = {}
|
|
validation {
|
|
condition = alltrue([
|
|
for k, v in var.tls_inspection_policies : v.tls.min_version == null || contains(
|
|
["TLS_VERSION_UNSPECIFIED", "TLS_1_0", "TLS_1_1", "TLS_1_2", "TLS_1_3"],
|
|
coalesce(v.tls.min_version, "-")
|
|
)
|
|
])
|
|
error_message = "Invalid min TLS version."
|
|
}
|
|
validation {
|
|
condition = alltrue([
|
|
for k, v in var.tls_inspection_policies : v.tls.feature_profile == null || contains(
|
|
["PROFILE_UNSPECIFIED", "PROFILE_COMPATIBLE", "PROFILE_MODERN", "PROFILE_RESTRICTED", "PROFILE_CUSTOM"],
|
|
coalesce(v.tls.feature_profile, "-")
|
|
)
|
|
])
|
|
error_message = "Invalid TLS feature profile."
|
|
}
|
|
validation {
|
|
condition = alltrue([
|
|
for k, v in var.tls_inspection_policies :
|
|
v.tls.custom_features == null || v.tls.feature_profile == "PROFILE_CUSTOM"
|
|
])
|
|
error_message = "TLS custom features can only be used with custom profile."
|
|
}
|
|
}
|
|
|
|
variable "trust_configs" {
|
|
description = "Certificate Manager trust configurations for TLS inspection policies. Project ids and region can reference keys in the relevant FAST variables."
|
|
type = map(object({
|
|
location = string
|
|
description = optional(string)
|
|
allowlisted_certificates = optional(map(string))
|
|
trust_stores = optional(map(object({
|
|
intermediate_cas = optional(map(string))
|
|
trust_anchors = optional(map(string))
|
|
})))
|
|
}))
|
|
nullable = false
|
|
default = {
|
|
# dev-ngfw-default = {
|
|
# location = "primary"
|
|
# project_id = "dev-spoke-0"
|
|
# }
|
|
# prod-ngfw-default = {
|
|
# location = "primary"
|
|
# project_id = "prod-spoke-0"
|
|
# }
|
|
}
|
|
validation {
|
|
condition = alltrue([
|
|
for k, v in var.trust_configs : (
|
|
v.allowlisted_certificates != null ||
|
|
try(v.trust_stores.intermediate_cas, null) != null ||
|
|
try(v.trust_stores.trust_anchors, null) != null
|
|
)
|
|
])
|
|
error_message = "a trust configuration needs at least one set of allowlisted certificates, or a valid trust store."
|
|
}
|
|
}
|