Merge pull request #1412 from GoogleCloudPlatform/afda16/vpn-alerts
Add VPN monitoring alerts to 2-networking and VPN usage chart
This commit is contained in:
commit
4876161003
|
@ -380,6 +380,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
| [dns-prod.tf](./dns-prod.tf) | Production spoke DNS zones and peerings setup. | <code>dns</code> | |
|
||||
| [landing.tf](./landing.tf) | Landing VPC and related resources. | <code>net-cloudnat</code> · <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>project</code> | |
|
||||
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
|
||||
| [monitoring-vpn-onprem.tf](./monitoring-vpn-onprem.tf) | VPN monitoring alerts. | | <code>google_monitoring_alert_policy</code> |
|
||||
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
|
||||
| [peerings.tf](./peerings.tf) | None | <code>net-vpc-peering</code> | |
|
||||
|
@ -395,20 +396,21 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L76) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L86) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L102) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [custom_roles](variables.tf#L38) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L47) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L55) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L96) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L101) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L111) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L127) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L121) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [peering_configs](variables-peerings.tf#L19) | Peering configurations. | <code title="map(object({ export_local_custom_routes = bool export_peer_custom_routes = bool }))">map(object({…}))</code> | | <code title="{ dev = { export_local_custom_routes = true export_peer_custom_routes = true } prod = { export_local_custom_routes = true export_peer_custom_routes = true } }">{…}</code> | |
|
||||
| [psa_ranges](variables.tf#L113) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L134) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L146) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L160) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L159) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L171) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L185) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"displayName": "VPN Monitoring",
|
||||
"gridLayout": {
|
||||
"columns": "2",
|
||||
"widgets": [
|
||||
"mosaicLayout": {
|
||||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Number of connections",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -33,7 +35,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Tunnel established",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -63,7 +69,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "VPN Tunnel Bandwidth usage",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesQueryLanguage": "fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition val() > 187.5 \"MBy/s\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"targetAxis": "Y1",
|
||||
"value": 187500000
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -93,7 +136,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -123,7 +171,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -153,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -183,7 +242,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Incoming packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -213,7 +278,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Outgoing packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -242,6 +313,9 @@
|
|||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description VPN monitoring alerts.
|
||||
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_established" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_established != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Established"
|
||||
enabled = var.alert_config.vpn_tunnel_established.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_established.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_established.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Established"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| metric vpn.googleapis.com/tunnel_established",
|
||||
"| group_by 5m, [value_tunnel_established_max: max(value.tunnel_established)]",
|
||||
"| every 5m",
|
||||
"| condition val() < 1 '1'",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_established.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_established.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_established.auto_close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# https://cloud.google.com/network-connectivity/docs/vpn/how-to/viewing-logs-metrics#define-bandwidth-alerts
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_bandwidth" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_bandwidth != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
enabled = var.alert_config.vpn_tunnel_bandwidth.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_bandwidth.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_bandwidth.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| { metric vpn.googleapis.com/network/sent_bytes_count",
|
||||
"; metric vpn.googleapis.com/network/received_bytes_count }",
|
||||
"| align rate (1m)",
|
||||
"| group_by [metric.tunnel_name]",
|
||||
"| outer_join 0,0",
|
||||
"| value val(0) + val(1)",
|
||||
"| condition val() > ${var.alert_config.vpn_tunnel_bandwidth.threshold_mbys} \"MBy/s\"",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_bandwidth.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_bandwidth.auto_close
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,31 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "alert_config" {
|
||||
description = "Configuration for monitoring alerts."
|
||||
type = object({
|
||||
vpn_tunnel_established = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
vpn_tunnel_bandwidth = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
threshold_mbys = optional(string, "187.5")
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
vpn_tunnel_established = {}
|
||||
vpn_tunnel_bandwidth = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "automation" {
|
||||
# tfdoc:variable:source 0-bootstrap
|
||||
description = "Automation resources created by the bootstrap stage."
|
||||
|
|
|
@ -403,6 +403,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
| [dns-prod.tf](./dns-prod.tf) | Production spoke DNS zones and peerings setup. | <code>dns</code> | |
|
||||
| [landing.tf](./landing.tf) | Landing VPC and related resources. | <code>net-cloudnat</code> · <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>project</code> | |
|
||||
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
|
||||
| [monitoring-vpn.tf](./monitoring-vpn.tf) | VPN monitoring alerts. | | <code>google_monitoring_alert_policy</code> |
|
||||
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
|
||||
| [regions.tf](./regions.tf) | Compute short names for regions. | | |
|
||||
|
@ -420,20 +421,21 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L76) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L86) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L102) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [custom_roles](variables.tf#L38) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L47) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L55) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L96) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L113) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L134) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L146) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L101) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L111) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L127) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L121) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L159) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L171) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_configs](variables-vpn.tf#L17) | Hub to spokes VPN configurations. | <code title="object({ dev = object({ asn = number custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) landing = object({ asn = number custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) prod = object({ asn = number custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) })">object({…})</code> | | <code title="{ dev = { asn = 65501 } landing = { asn = 65500 } prod = { asn = 65502 } }">{…}</code> | |
|
||||
| [vpn_onprem_primary_config](variables.tf#L160) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_primary_config](variables.tf#L185) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"displayName": "VPN Monitoring",
|
||||
"gridLayout": {
|
||||
"columns": "2",
|
||||
"widgets": [
|
||||
"mosaicLayout": {
|
||||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Number of connections",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -33,7 +35,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Tunnel established",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -63,7 +69,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "VPN Tunnel Bandwidth usage",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesQueryLanguage": "fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition val() > 187.5 \"MBy/s\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"targetAxis": "Y1",
|
||||
"value": 187500000
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -93,7 +136,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -123,7 +171,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -153,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -183,7 +242,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Incoming packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -213,7 +278,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Outgoing packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -242,6 +313,9 @@
|
|||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description VPN monitoring alerts.
|
||||
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_established" {
|
||||
count = var.alert_config.vpn_tunnel_established != null ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Established"
|
||||
enabled = var.alert_config.vpn_tunnel_established.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_established.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_established.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Established"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| metric vpn.googleapis.com/tunnel_established",
|
||||
"| group_by 5m, [value_tunnel_established_max: max(value.tunnel_established)]",
|
||||
"| every 5m",
|
||||
"| condition val() < 1 '1'",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_established.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_established.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_established.auto_close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# https://cloud.google.com/network-connectivity/docs/vpn/how-to/viewing-logs-metrics#define-bandwidth-alerts
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_bandwidth" {
|
||||
count = var.alert_config.vpn_tunnel_bandwidth != null ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
enabled = var.alert_config.vpn_tunnel_bandwidth.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_bandwidth.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_bandwidth.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| { metric vpn.googleapis.com/network/sent_bytes_count",
|
||||
"; metric vpn.googleapis.com/network/received_bytes_count }",
|
||||
"| align rate (1m)",
|
||||
"| group_by [metric.tunnel_name]",
|
||||
"| outer_join 0,0",
|
||||
"| value val(0) + val(1)",
|
||||
"| condition val() > ${var.alert_config.vpn_tunnel_bandwidth.threshold_mbys} \"MBy/s\"",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_bandwidth.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_bandwidth.auto_close
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,31 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "alert_config" {
|
||||
description = "Configuration for monitoring alerts."
|
||||
type = object({
|
||||
vpn_tunnel_established = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
vpn_tunnel_bandwidth = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
threshold_mbys = optional(string, "187.5")
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
vpn_tunnel_established = {}
|
||||
vpn_tunnel_bandwidth = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "automation" {
|
||||
# tfdoc:variable:source 0-bootstrap
|
||||
description = "Automation resources created by the bootstrap stage."
|
||||
|
|
|
@ -462,6 +462,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
| [dns-prod.tf](./dns-prod.tf) | Production spoke DNS zones and peerings setup. | <code>dns</code> | |
|
||||
| [landing.tf](./landing.tf) | Landing VPC and related resources. | <code>net-cloudnat</code> · <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>project</code> | |
|
||||
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
|
||||
| [monitoring-vpn-onprem.tf](./monitoring-vpn-onprem.tf) | VPN monitoring alerts. | | <code>google_monitoring_alert_policy</code> |
|
||||
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
|
||||
| [nva.tf](./nva.tf) | None | <code>compute-mig</code> · <code>compute-vm</code> · <code>simple-nva</code> | |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
|
||||
|
@ -476,22 +477,23 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L76) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L109) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L125) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [custom_roles](variables.tf#L38) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L47) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L55) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L86) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.128.128.0/19" gcp_dev_secondary = "10.128.160.0/19" gcp_landing_trusted_primary = "10.128.64.0/19" gcp_landing_trusted_secondary = "10.128.96.0/19" gcp_landing_untrusted_primary = "10.128.0.0/19" gcp_landing_untrusted_secondary = "10.128.32.0/19" gcp_prod_primary = "10.128.192.0/19" gcp_prod_secondary = "10.128.224.0/19" }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L101) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L119) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L136) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L157) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L169) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L183) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L226) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L101) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L134) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L150) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L111) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.128.128.0/19" gcp_dev_secondary = "10.128.160.0/19" gcp_landing_trusted_primary = "10.128.64.0/19" gcp_landing_trusted_secondary = "10.128.96.0/19" gcp_landing_untrusted_primary = "10.128.0.0/19" gcp_landing_untrusted_secondary = "10.128.32.0/19" gcp_prod_primary = "10.128.192.0/19" gcp_prod_secondary = "10.128.224.0/19" }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L126) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L144) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L161) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L182) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L194) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L208) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L251) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"displayName": "VPN Monitoring",
|
||||
"gridLayout": {
|
||||
"columns": "2",
|
||||
"widgets": [
|
||||
"mosaicLayout": {
|
||||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Number of connections",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -33,7 +35,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Tunnel established",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -63,7 +69,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "VPN Tunnel Bandwidth usage",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesQueryLanguage": "fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition val() > 187.5 \"MBy/s\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"targetAxis": "Y1",
|
||||
"value": 187500000
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -93,7 +136,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -123,7 +171,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -153,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -183,7 +242,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Incoming packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -213,7 +278,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Outgoing packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -242,6 +313,9 @@
|
|||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description VPN monitoring alerts.
|
||||
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_established" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_established != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Established"
|
||||
enabled = var.alert_config.vpn_tunnel_established.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_established.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_established.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Established"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| metric vpn.googleapis.com/tunnel_established",
|
||||
"| group_by 5m, [value_tunnel_established_max: max(value.tunnel_established)]",
|
||||
"| every 5m",
|
||||
"| condition val() < 1 '1'",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_established.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_established.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_established.auto_close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# https://cloud.google.com/network-connectivity/docs/vpn/how-to/viewing-logs-metrics#define-bandwidth-alerts
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_bandwidth" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_bandwidth != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
enabled = var.alert_config.vpn_tunnel_bandwidth.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_bandwidth.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_bandwidth.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| { metric vpn.googleapis.com/network/sent_bytes_count",
|
||||
"; metric vpn.googleapis.com/network/received_bytes_count }",
|
||||
"| align rate (1m)",
|
||||
"| group_by [metric.tunnel_name]",
|
||||
"| outer_join 0,0",
|
||||
"| value val(0) + val(1)",
|
||||
"| condition val() > ${var.alert_config.vpn_tunnel_bandwidth.threshold_mbys} \"MBy/s\"",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_bandwidth.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_bandwidth.auto_close
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,31 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "alert_config" {
|
||||
description = "Configuration for monitoring alerts."
|
||||
type = object({
|
||||
vpn_tunnel_established = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
vpn_tunnel_bandwidth = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
threshold_mbys = optional(string, "187.5")
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
vpn_tunnel_established = {}
|
||||
vpn_tunnel_bandwidth = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "automation" {
|
||||
# tfdoc:variable:source 0-bootstrap
|
||||
description = "Automation resources created by the bootstrap stage."
|
||||
|
|
|
@ -325,6 +325,7 @@ Regions are defined via the `regions` variable which sets up a mapping between t
|
|||
| [dns-dev.tf](./dns-dev.tf) | Development spoke DNS zones and peerings setup. | <code>dns</code> · <code>dns-response-policy</code> | |
|
||||
| [dns-prod.tf](./dns-prod.tf) | Production spoke DNS zones and peerings setup. | <code>dns</code> · <code>dns-response-policy</code> | |
|
||||
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
|
||||
| [monitoring-vpn-onprem.tf](./monitoring-vpn-onprem.tf) | VPN monitoring alerts. | | <code>google_monitoring_alert_policy</code> |
|
||||
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
|
||||
| [regions.tf](./regions.tf) | Compute short names for regions. | | |
|
||||
|
@ -338,20 +339,21 @@ Regions are defined via the `regions` variable which sets up a mapping between t
|
|||
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L77) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L87) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L103) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [custom_roles](variables.tf#L38) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L47) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ prod = ["10.0.1.1"] dev = ["10.0.2.1"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L56) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L97) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L114) | IP ranges used for Private Service Access (e.g. CloudSQL). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L135) | Region definitions. | <code title="object({ primary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L145) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_dev_primary_config](variables.tf#L159) | VPN gateway configuration for onprem interconnection from dev in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_prod_primary_config](variables.tf#L202) | VPN gateway configuration for onprem interconnection from prod in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L102) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L112) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L128) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ prod = ["10.0.1.1"] dev = ["10.0.2.1"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L81) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L122) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L139) | IP ranges used for Private Service Access (e.g. CloudSQL). | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L160) | Region definitions. | <code title="object({ primary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L170) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_dev_primary_config](variables.tf#L184) | VPN gateway configuration for onprem interconnection from dev in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_prod_primary_config](variables.tf#L227) | VPN gateway configuration for onprem interconnection from prod in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"displayName": "VPN Monitoring",
|
||||
"gridLayout": {
|
||||
"columns": "2",
|
||||
"widgets": [
|
||||
"mosaicLayout": {
|
||||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Number of connections",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -33,7 +35,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Tunnel established",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -63,7 +69,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "VPN Tunnel Bandwidth usage",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesQueryLanguage": "fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition val() > 187.5 \"MBy/s\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"targetAxis": "Y1",
|
||||
"value": 187500000
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -93,7 +136,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -123,7 +171,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -153,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -183,7 +242,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Incoming packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -213,7 +278,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Outgoing packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -242,6 +313,9 @@
|
|||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description VPN monitoring alerts.
|
||||
|
||||
# VPN alerts
|
||||
|
||||
locals {
|
||||
alert_project_id = flatten([
|
||||
var.vpn_onprem_dev_primary_config == null ? [] : [module.dev-spoke-project.project_id],
|
||||
var.vpn_onprem_prod_primary_config == null ? [] : [module.prod-spoke-project.project_id]
|
||||
])
|
||||
}
|
||||
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_established" {
|
||||
for_each = var.alert_config.vpn_tunnel_established != null ? toset(local.alert_project_id) : []
|
||||
|
||||
project = each.key
|
||||
display_name = "VPN Tunnel Established"
|
||||
enabled = var.alert_config.vpn_tunnel_established.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_established.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_established.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Established"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| metric vpn.googleapis.com/tunnel_established",
|
||||
"| group_by 5m, [value_tunnel_established_max: max(value.tunnel_established)]",
|
||||
"| every 5m",
|
||||
"| condition val() < 1 '1'",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_established.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_established.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_established.auto_close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# https://cloud.google.com/network-connectivity/docs/vpn/how-to/viewing-logs-metrics#define-bandwidth-alerts
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_bandwidth" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth != null ? toset(local.alert_project_id) : []
|
||||
|
||||
project = each.key
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
enabled = var.alert_config.vpn_tunnel_bandwidth.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_bandwidth.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_bandwidth.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| { metric vpn.googleapis.com/network/sent_bytes_count",
|
||||
"; metric vpn.googleapis.com/network/received_bytes_count }",
|
||||
"| align rate (1m)",
|
||||
"| group_by [metric.tunnel_name]",
|
||||
"| outer_join 0,0",
|
||||
"| value val(0) + val(1)",
|
||||
"| condition val() > ${var.alert_config.vpn_tunnel_bandwidth.threshold_mbys} \"MBy/s\"",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_bandwidth.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_bandwidth.auto_close
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,31 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "alert_config" {
|
||||
description = "Configuration for monitoring alerts."
|
||||
type = object({
|
||||
vpn_tunnel_established = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
vpn_tunnel_bandwidth = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
threshold_mbys = optional(string, "187.5")
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
vpn_tunnel_established = {}
|
||||
vpn_tunnel_bandwidth = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "automation" {
|
||||
# tfdoc:variable:source 0-bootstrap
|
||||
description = "Automation resources created by the bootstrap stage."
|
||||
|
|
|
@ -486,6 +486,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
| [dns-prod.tf](./dns-prod.tf) | Production spoke DNS zones and peerings setup. | <code>dns</code> | |
|
||||
| [landing.tf](./landing.tf) | Landing VPC and related resources. | <code>net-cloudnat</code> · <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>project</code> | |
|
||||
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
|
||||
| [monitoring-vpn-onprem.tf](./monitoring-vpn-onprem.tf) | VPN monitoring alerts. | | <code>google_monitoring_alert_policy</code> |
|
||||
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
|
||||
| [ncc.tf](./ncc.tf) | None | <code>ncc-spoke-ra</code> | |
|
||||
| [nva.tf](./nva.tf) | None | <code>compute-vm</code> · <code>simple-nva</code> | <code>google_compute_address</code> |
|
||||
|
@ -501,24 +502,25 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L76) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L120) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L136) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [custom_roles](variables.tf#L38) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L47) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L55) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L86) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.128.128.0/19" gcp_dev_secondary = "10.128.160.0/19" gcp_landing_trusted_primary = "10.128.64.0/19" gcp_landing_trusted_secondary = "10.128.96.0/19" gcp_landing_untrusted_primary = "10.128.0.0/19" gcp_landing_untrusted_secondary = "10.128.32.0/19" gcp_prod_primary = "10.128.192.0/19" gcp_prod_secondary = "10.128.224.0/19" }">{…}</code> | |
|
||||
| [ncc_asn](variables.tf#L101) | The NCC Cloud Routers ASN configuration. | <code>map(number)</code> | | <code title="{ nva_primary = 64513 nva_secondary = 64514 trusted = 64515 untrusted = 64512 }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L112) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L130) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L147) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L168) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L180) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L194) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L237) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [zones](variables.tf#L280) | Zones in which NVAs are deployed. | <code>list(string)</code> | | <code>["b", "c"]</code> | |
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L101) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L145) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L161) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | Onprem DNS resolvers. | <code>map(list(string))</code> | | <code title="{ onprem = ["10.0.200.3"] }">{…}</code> | |
|
||||
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "factory") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L111) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.128.128.0/19" gcp_dev_secondary = "10.128.160.0/19" gcp_landing_trusted_primary = "10.128.64.0/19" gcp_landing_trusted_secondary = "10.128.96.0/19" gcp_landing_untrusted_primary = "10.128.0.0/19" gcp_landing_untrusted_secondary = "10.128.32.0/19" gcp_prod_primary = "10.128.192.0/19" gcp_prod_secondary = "10.128.224.0/19" }">{…}</code> | |
|
||||
| [ncc_asn](variables.tf#L126) | The NCC Cloud Routers ASN configuration. | <code>map(number)</code> | | <code title="{ nva_primary = 64513 nva_secondary = 64514 trusted = 64515 untrusted = 64512 }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L137) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L155) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L172) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) prod = object({ ranges = map(string) routes = object({ export = bool import = bool }) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L193) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L205) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L219) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L262) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [zones](variables.tf#L305) | Zones in which NVAs are deployed. | <code>list(string)</code> | | <code>["b", "c"]</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"displayName": "VPN Monitoring",
|
||||
"gridLayout": {
|
||||
"columns": "2",
|
||||
"widgets": [
|
||||
"mosaicLayout": {
|
||||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Number of connections",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -33,7 +35,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Tunnel established",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -63,7 +69,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "VPN Tunnel Bandwidth usage",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesQueryLanguage": "fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition val() > 187.5 \"MBy/s\""
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"targetAxis": "Y1",
|
||||
"value": 187500000
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 4,
|
||||
"xPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -93,7 +136,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent bytes",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -123,7 +171,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Received packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -153,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Cloud VPN Gateway - Sent packets",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -183,7 +242,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Incoming packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -213,7 +278,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "Outgoing packets dropped",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
|
@ -242,6 +313,9 @@
|
|||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
# tfdoc:file:description VPN monitoring alerts.
|
||||
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_established" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_established != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Established"
|
||||
enabled = var.alert_config.vpn_tunnel_established.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_established.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_established.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Established"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| metric vpn.googleapis.com/tunnel_established",
|
||||
"| group_by 5m, [value_tunnel_established_max: max(value.tunnel_established)]",
|
||||
"| every 5m",
|
||||
"| condition val() < 1 '1'",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_established.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_established.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_established.auto_close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# https://cloud.google.com/network-connectivity/docs/vpn/how-to/viewing-logs-metrics#define-bandwidth-alerts
|
||||
resource "google_monitoring_alert_policy" "vpn_tunnel_bandwidth" {
|
||||
count = (var.vpn_onprem_primary_config != null && var.alert_config.vpn_tunnel_bandwidth != null) ? 1 : 0
|
||||
|
||||
project = module.landing-project.project_id
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
enabled = var.alert_config.vpn_tunnel_bandwidth.enabled
|
||||
notification_channels = var.alert_config.vpn_tunnel_bandwidth.notification_channels
|
||||
user_labels = var.alert_config.vpn_tunnel_bandwidth.user_labels
|
||||
combiner = "OR"
|
||||
|
||||
conditions {
|
||||
display_name = "VPN Tunnel Bandwidth usage"
|
||||
|
||||
condition_monitoring_query_language {
|
||||
query = join("", [
|
||||
"fetch vpn_gateway",
|
||||
"| { metric vpn.googleapis.com/network/sent_bytes_count",
|
||||
"; metric vpn.googleapis.com/network/received_bytes_count }",
|
||||
"| align rate (1m)",
|
||||
"| group_by [metric.tunnel_name]",
|
||||
"| outer_join 0,0",
|
||||
"| value val(0) + val(1)",
|
||||
"| condition val() > ${var.alert_config.vpn_tunnel_bandwidth.threshold_mbys} \"MBy/s\"",
|
||||
])
|
||||
|
||||
duration = var.alert_config.vpn_tunnel_bandwidth.duration
|
||||
|
||||
trigger {
|
||||
count = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "alert_strategy" {
|
||||
for_each = var.alert_config.vpn_tunnel_bandwidth.auto_close != null ? [1] : []
|
||||
|
||||
content {
|
||||
auto_close = var.alert_config.vpn_tunnel_bandwidth.auto_close
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,31 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "alert_config" {
|
||||
description = "Configuration for monitoring alerts."
|
||||
type = object({
|
||||
vpn_tunnel_established = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
vpn_tunnel_bandwidth = optional(object({
|
||||
auto_close = optional(string, null)
|
||||
duration = optional(string, "120s")
|
||||
enabled = optional(bool, true)
|
||||
notification_channels = optional(list(string), [])
|
||||
threshold_mbys = optional(string, "187.5")
|
||||
user_labels = optional(map(string), {})
|
||||
}))
|
||||
})
|
||||
default = {
|
||||
vpn_tunnel_established = {}
|
||||
vpn_tunnel_bandwidth = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "automation" {
|
||||
# tfdoc:variable:source 0-bootstrap
|
||||
description = "Automation resources created by the bootstrap stage."
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
counts:
|
||||
modules: 27
|
||||
resources: 139
|
||||
resources: 141
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
counts:
|
||||
modules: 29
|
||||
resources: 176
|
||||
resources: 178
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
counts:
|
||||
modules: 41
|
||||
resources: 185
|
||||
resources: 187
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
counts:
|
||||
modules: 20
|
||||
resources: 156
|
||||
resources: 160
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
counts:
|
||||
modules: 35
|
||||
resources: 198
|
||||
resources: 200
|
||||
|
|
Loading…
Reference in New Issue