Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Last active November 24, 2020 16:35
Show Gist options
  • Save mikesparr/42adb3b463d867f0dca4865362c213ac to your computer and use it in GitHub Desktop.
Save mikesparr/42adb3b463d867f0dca4865362c213ac to your computer and use it in GitHub Desktop.
Example Terraform GCP org with Memcache in service project
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = ">= 3.37"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 3.37"
}
}
}
provider "google" {
version = "3.37.0"
region = var.region
zone = var.zone
}
provider "google-beta" {
version = "3.37.0"
region = var.region
zone = var.zone
}
data "google_billing_account" "account" {
provider = google-beta
billing_account = var.billing_account_id
}
# folders
resource "google_folder" "demo_org" {
display_name = "demo-org"
parent = var.root_folder
}
resource "google_folder" "shared_services" {
display_name = "shared-services"
parent = google_folder.demo_org.name
}
resource "google_folder" "engineering" {
display_name = "engineering"
parent = google_folder.demo_org.name
}
resource "google_folder" "product_x" {
display_name = "product-x"
parent = google_folder.engineering.name
}
resource "google_folder" "non_production" {
display_name = "non-production"
parent = google_folder.product_x.name
}
resource "google_folder" "production" {
display_name = "production"
parent = google_folder.product_x.name
}
# audit config
resource "google_folder_iam_audit_config" "audit_root_folder" {
folder = google_folder.demo_org.folder_id
service = "allServices"
audit_log_config {
log_type = "ADMIN_READ"
}
audit_log_config {
log_type = "DATA_READ"
}
# audit_log_config {
# log_type = "DATA_WRITE"
# }
}
# policies
resource "google_folder_organization_policy" "default_network_policy" {
folder = google_folder.demo_org.id
constraint = "compute.skipDefaultNetworkCreation"
boolean_policy {
enforced = true
}
}
resource "google_folder_organization_policy" "service_acct_key_policy" {
folder = google_folder.demo_org.id
constraint = "iam.disableServiceAccountKeyCreation"
boolean_policy {
enforced = true
}
}
resource "google_folder_organization_policy" "shielded_vm_policy" {
folder = google_folder.demo_org.id
constraint = "compute.requireShieldedVm"
boolean_policy {
enforced = true
}
}
# finding GSuite ID: https://www.youtube.com/watch?v=AeadQfJT5kw
resource "google_folder_organization_policy" "allow_only_policy_member_domains" {
folder = google_folder.demo_org.id
constraint = "constraints/iam.allowedPolicyMemberDomains"
list_policy {
allow {
values = var.allowed_domain_ids
}
}
}
resource "google_folder_organization_policy" "restrict_vm_external_ip_policy" {
folder = google_folder.demo_org.id
constraint = "compute.vmExternalIpAccess"
list_policy {
deny {
all = true
}
}
}
resource "google_folder_organization_policy" "disable_appengine_code_download_policy" {
folder = google_folder.demo_org.id
constraint = "appengine.disableCodeDownload"
boolean_policy {
enforced = true
}
}
# shared projects
resource "random_id" "shared_random_id" {
byte_length = 4
}
# security
resource "google_project" "shared_security" {
name = "security"
project_id = "security2-${random_id.shared_random_id.hex}"
folder_id = google_folder.shared_services.name
billing_account = var.billing_account_id
labels = { "dept" : "infosec" }
}
# bucket for audit-logs, with log sink and dynamic sa role
resource "google_storage_bucket" "bucket_audit_logs" {
name = var.audit_logs_bucket_name
location = "US"
project = google_project.shared_security.project_id
labels = { "dept": "infosec", "role": "storage" }
}
resource "google_logging_folder_sink" "log_sink_audit" {
name = "demo-org-audit-logs"
folder = google_folder.demo_org.name
include_children = true
destination = "storage.googleapis.com/${google_storage_bucket.bucket_audit_logs.name}"
filter = "protoPayload.@type:\"type.googleapis.com/google.cloud.audit.AuditLog\""
}
resource "google_project_iam_binding" "audit_log_writer" {
project = google_project.shared_security.project_id
role = "roles/storage.objectCreator"
members = [
google_logging_folder_sink.log_sink_audit.writer_identity,
]
}
# monitoring
resource "google_project" "shared_monitoring" {
name = "monitoring"
project_id = "monitoring2-${random_id.shared_random_id.hex}"
folder_id = google_folder.shared_services.name
billing_account = var.billing_account_id
labels = { "dept" : "engineering" }
}
resource "google_project_service" "bq_service_monitoring" {
project = google_project.shared_monitoring.project_id
service = "monitoring.googleapis.com"
}
resource "google_monitoring_notification_channel" "notification_channel_security" {
provider = google-beta
project = google_project.shared_monitoring.project_id # var.monitoring_project_id
display_name = "Security Notification Channel"
type = "email"
labels = {
email_address = var.group_security_admins
}
}
resource "google_monitoring_notification_channel" "notification_channel_devops" {
provider = google-beta
project = google_project.shared_monitoring.project_id # var.monitoring_project_id
display_name = "Devops Notification Channel"
type = "email"
labels = {
email_address = var.group_devops
}
}
resource "google_monitoring_notification_channel" "notification_channel_billing" {
provider = google-beta
project = google_project.shared_monitoring.project_id # var.monitoring_project_id
display_name = "Billing Notification Channel"
type = "email"
labels = {
email_address = var.group_billing_admins
}
}
resource "google_monitoring_notification_channel" "notification_channel_developers" {
provider = google-beta
project = google_project.shared_monitoring.project_id # var.monitoring_project_id
display_name = "Developers Notification Channel"
type = "email"
labels = {
email_address = var.group_developers
}
}
# TODO: workspace for monitoring (not avail in Terraform it seems so manual)
# billing
resource "google_project" "shared_billing" {
name = "billing"
project_id = "billing2-${random_id.shared_random_id.hex}"
folder_id = google_folder.shared_services.name
billing_account = var.billing_account_id
labels = { "dept" : "finance" }
}
# enable billingbudgets.googleapis.com
resource "google_project_service" "bq_service_billing_budgets" {
project = google_project.shared_billing.project_id
service = "billingbudgets.googleapis.com"
}
# BigQuery dataset for billing export
# NOTE: must enable 'Logs Configuration Writer' for tf-sa on billing acct
resource "google_project_service" "bq_service_billing" {
project = google_project.shared_billing.project_id
service = "bigquery.googleapis.com"
}
resource "google_project_service" "bq_data_transfer_service_billing" {
project = google_project.shared_billing.project_id
service = "bigquerydatatransfer.googleapis.com"
}
resource "google_bigquery_dataset" "billing_dataset" {
project = google_project.shared_billing.project_id
dataset_id = "billing_export_${random_id.shared_random_id.hex}"
friendly_name = "Billing Export"
description = "Exported billing data"
location = "US"
delete_contents_on_destroy = true # destroying resource will fail otherwise
labels = { "dept" = "finance", "role" = "analytics" }
}
resource "google_logging_billing_account_sink" "billing_bq_export" {
name = "billing-export"
billing_account = var.billing_account_id
destination = "bigquery.googleapis.com/projects/${google_project.shared_billing.project_id}/datasets/${google_bigquery_dataset.billing_dataset.dataset_id}"
}
resource "google_project_iam_binding" "billing_export_writer" {
project = google_project.shared_billing.project_id
role = "roles/bigquery.dataOwner"
members = [
google_logging_billing_account_sink.billing_bq_export.writer_identity,
]
}
# host projects
# nonprod
resource "google_project" "shared_nw_nonprod" {
name = "shared-nw-nonprod"
project_id = "shared-nw-nonprod-${random_id.shared_random_id.hex}"
folder_id = google_folder.shared_services.name
billing_account = var.billing_account_id
labels = { "dept" : "network", "env" : "non-production" }
}
resource "google_project_service" "compute_shared_nw_nonprod" {
project = google_project.shared_nw_nonprod.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container_shared_nw_nonprod" {
project = google_project.shared_nw_nonprod.project_id
service = "container.googleapis.com"
}
resource "google_project_service" "servicenetworking_shared_nw_nonprod" {
project = google_project.shared_nw_nonprod.project_id
service = "servicenetworking.googleapis.com"
}
resource "google_compute_shared_vpc_host_project" "host_nonprod" {
project = google_project.shared_nw_nonprod.project_id
depends_on = [google_project_service.compute_shared_nw_nonprod]
}
resource "google_compute_network" "vpc_devops" {
name = "devops-10-19-0-0"
routing_mode = "REGIONAL"
auto_create_subnetworks = false
project = google_project.shared_nw_nonprod.project_id
depends_on = [google_project_service.compute_shared_nw_nonprod]
}
resource "google_compute_subnetwork" "subnet_devops_k8s" {
name = "k8s-nodes-devops"
ip_cidr_range = "10.19.0.0/22"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_devops.id
secondary_ip_range {
range_name = "k8s-pods-devops"
ip_cidr_range = "10.89.0.0/18"
}
secondary_ip_range {
range_name = "k8s-svcs-devops"
ip_cidr_range = "10.89.64.0/22"
}
}
resource "google_compute_subnetwork" "subnet_devops_bastion" {
name = "bastion-devops"
ip_cidr_range = "10.19.64.0/29"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_devops.id
}
resource "google_compute_subnetwork" "subnet_devops_vms" {
name = "vms-devops"
ip_cidr_range = "10.19.65.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_devops.id
}
resource "google_compute_subnetwork" "subnet_devops_dbs" {
name = "databases-devops"
ip_cidr_range = "10.19.70.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_devops.id
}
# TODO: firewall rule port 22 for bastion
resource "google_compute_network" "vpc_development" {
name = "dev-10-12-0-0"
routing_mode = "REGIONAL"
auto_create_subnetworks = false
project = google_project.shared_nw_nonprod.project_id
depends_on = [google_project_service.compute_shared_nw_nonprod]
}
resource "google_compute_subnetwork" "subnet_dev_k8s" {
name = "k8s-nodes-dev"
ip_cidr_range = "10.12.0.0/22"
region = var.region
project = google_project.shared_nw_nonprod.project_id
private_ip_google_access = true
network = google_compute_network.vpc_development.id
secondary_ip_range {
range_name = "k8s-pods-dev"
ip_cidr_range = "10.82.0.0/18"
}
secondary_ip_range {
range_name = "k8s-svcs-dev"
ip_cidr_range = "10.82.64.0/22"
}
}
resource "google_compute_global_address" "service_range" {
provider = google-beta
name = "devrange-${random_id.shared_random_id.hex}"
project = google_project.shared_nw_nonprod.project_id
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.vpc_development.id
}
resource "google_service_networking_connection" "private_service_connection" {
provider = google-beta
network = google_compute_network.vpc_development.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.service_range.name]
}
resource "google_compute_subnetwork" "subnet_dev_bastion" {
name = "bastion-dev"
ip_cidr_range = "10.12.64.0/29"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_development.id
}
resource "google_compute_subnetwork" "subnet_dev_vms" {
name = "vms-dev"
ip_cidr_range = "10.12.65.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_development.id
}
resource "google_compute_subnetwork" "subnet_dev_dbs" {
name = "databases-dev"
ip_cidr_range = "10.12.70.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_nonprod.project_id
network = google_compute_network.vpc_development.id
}
# TODO: firewall rule port 22 for bastion
# prod
resource "google_project" "shared_nw_prod" {
name = "shared-nw-prod"
project_id = "shared-nw-prod-${random_id.shared_random_id.hex}"
folder_id = google_folder.shared_services.name
billing_account = var.billing_account_id
labels = { "dept" : "network", "env" : "production" }
}
resource "google_project_service" "compute_shared_nw_prod" {
project = google_project.shared_nw_prod.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container_shared_nw_prod" {
project = google_project.shared_nw_prod.project_id
service = "container.googleapis.com"
}
resource "google_compute_shared_vpc_host_project" "host_prod" {
project = google_project.shared_nw_prod.project_id
depends_on = [google_project_service.compute_shared_nw_prod]
}
# network stage
resource "google_compute_network" "vpc_stage" {
name = "stage-10-11-0-0"
routing_mode = "REGIONAL"
auto_create_subnetworks = false
project = google_project.shared_nw_prod.project_id
depends_on = [google_project_service.compute_shared_nw_prod]
}
resource "google_compute_subnetwork" "subnet_stage_k8s" {
name = "k8s-nodes-stage"
ip_cidr_range = "10.11.0.0/22"
region = var.region
project = google_project.shared_nw_prod.project_id
private_ip_google_access = true
network = google_compute_network.vpc_stage.id
secondary_ip_range {
range_name = "k8s-pods-stage"
ip_cidr_range = "10.81.0.0/18"
}
secondary_ip_range {
range_name = "k8s-svcs-stage"
ip_cidr_range = "10.81.64.0/22"
}
}
resource "google_compute_subnetwork" "subnet_stage_bastion" {
name = "bastion-stage"
ip_cidr_range = "10.11.64.0/29"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_stage.id
}
resource "google_compute_subnetwork" "subnet_stage_vms" {
name = "vms-stage"
ip_cidr_range = "10.11.65.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_stage.id
}
resource "google_compute_subnetwork" "subnet_stage_dbs" {
name = "databases-stage"
ip_cidr_range = "10.11.70.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_stage.id
}
# network prod
resource "google_compute_network" "vpc_production" {
name = "production-10-10-0-0"
routing_mode = "REGIONAL"
auto_create_subnetworks = false
project = google_project.shared_nw_prod.project_id
depends_on = [google_project_service.compute_shared_nw_prod]
}
resource "google_compute_subnetwork" "subnet_prod_k8s" {
name = "k8s-nodes-prod"
ip_cidr_range = "10.10.0.0/22"
region = var.region
project = google_project.shared_nw_prod.project_id
private_ip_google_access = true
network = google_compute_network.vpc_production.id
secondary_ip_range {
range_name = "k8s-pods-prod"
ip_cidr_range = "10.80.0.0/18"
}
secondary_ip_range {
range_name = "k8s-svcs-prod"
ip_cidr_range = "10.80.64.0/22"
}
}
resource "google_compute_subnetwork" "subnet_prod_bastion" {
name = "bastion-prod"
ip_cidr_range = "10.12.64.0/29"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_production.id
}
resource "google_compute_subnetwork" "subnet_prod_vms" {
name = "vms-prod"
ip_cidr_range = "10.11.65.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_production.id
}
resource "google_compute_subnetwork" "subnet_prod_dbs" {
name = "databases-prod"
ip_cidr_range = "10.11.70.0/24"
region = var.region
private_ip_google_access = true
project = google_project.shared_nw_prod.project_id
network = google_compute_network.vpc_production.id
}
# service projects
# dev
resource "google_project" "development" {
name = "development"
project_id = "development-${random_id.shared_random_id.hex}"
folder_id = google_folder.non_production.name
billing_account = var.billing_account_id
labels = { "dept" : "engineering", "env" : "non-production", "product" : "x" }
}
resource "google_project_service" "compute_development" {
project = google_project.development.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container_development" {
project = google_project.development.project_id
service = "container.googleapis.com"
}
resource "google_project_service" "servicenetworking_development" {
project = google_project.development.project_id
service = "servicenetworking.googleapis.com"
}
resource "google_project_service" "memcache_development" {
project = google_project.development.project_id
service = "memcache.googleapis.com"
}
resource "google_compute_shared_vpc_service_project" "service_dev" {
host_project = google_compute_shared_vpc_host_project.host_nonprod.project
service_project = google_project.development.project_id
}
# add IAM role to link project to shared subnet
data "google_project" "project_development" {
project_id = google_project.development.project_id
}
resource "google_compute_subnetwork_iam_member" "member_development" {
project = google_project.shared_nw_nonprod.project_id
region = google_compute_subnetwork.subnet_dev_k8s.region
subnetwork = google_compute_subnetwork.subnet_dev_k8s.name
role = "roles/compute.networkUser"
member = format("serviceAccount:service-%s@container-engine-robot.iam.gserviceaccount.com", data.google_project.project_development.number)
}
# add memcache (Memorystore) example to development
resource "google_memcache_instance" "cache_dev" {
provider = google-beta
project = google_project.development.project_id
name = "cache-dev"
region = var.region
authorized_network = google_service_networking_connection.private_service_connection.network
node_config {
cpu_count = 1
memory_size_mb = 1024
}
node_count = 1
memcache_version = "MEMCACHE_1_5"
depends_on = [
google_service_networking_connection.private_service_connection,
google_project_service.memcache_development
]
}
# stage
resource "google_project" "stage" {
name = "stage"
project_id = "stage-${random_id.shared_random_id.hex}"
folder_id = google_folder.production.name
billing_account = var.billing_account_id
labels = { "dept" : "engineering", "env" : "non-production", "product" : "x" }
}
resource "google_project_service" "compute_stage" {
project = google_project.stage.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container_stage" {
project = google_project.stage.project_id
service = "container.googleapis.com"
}
resource "google_compute_shared_vpc_service_project" "service_stage" {
host_project = google_compute_shared_vpc_host_project.host_prod.project
service_project = google_project.stage.project_id
}
# add IAM role to link project to shared subnet
data "google_project" "project_stage" {
project_id = google_project.stage.project_id
}
resource "google_compute_subnetwork_iam_member" "member_stage" {
project = google_project.shared_nw_prod.project_id
region = google_compute_subnetwork.subnet_stage_k8s.region
subnetwork = google_compute_subnetwork.subnet_stage_k8s.name
role = "roles/compute.networkUser"
member = format("serviceAccount:service-%s@container-engine-robot.iam.gserviceaccount.com", data.google_project.project_stage.number)
}
# prod
resource "google_project" "production" {
name = "production"
project_id = "production-${random_id.shared_random_id.hex}"
folder_id = google_folder.production.name
billing_account = var.billing_account_id
labels = { "dept" : "engineering", "env" : "production", "product" : "x" }
}
resource "google_project_service" "compute_production" {
project = google_project.production.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container_production" {
project = google_project.production.project_id
service = "container.googleapis.com"
}
resource "google_compute_shared_vpc_service_project" "service_prod" {
host_project = google_compute_shared_vpc_host_project.host_prod.project
service_project = google_project.production.project_id
}
# add IAM role to link project to shared subnet
data "google_project" "project_production" {
project_id = google_project.production.project_id
}
resource "google_compute_subnetwork_iam_member" "member_production" {
project = google_project.shared_nw_prod.project_id
region = google_compute_subnetwork.subnet_prod_k8s.region
subnetwork = google_compute_subnetwork.subnet_prod_k8s.name
role = "roles/compute.networkUser"
member = format("serviceAccount:service-%s@container-engine-robot.iam.gserviceaccount.com", data.google_project.project_production.number)
}
# BUDGET
# budget notifications
resource "google_billing_budget" "budget_sandbox" {
provider = google-beta
billing_account = data.google_billing_account.account.id
display_name = "Sandbox Billing Budget"
budget_filter {
projects = [
"projects/mike-stage"
]
}
amount {
specified_amount {
currency_code = "USD"
units = "100"
}
}
threshold_rules {
threshold_percent = 0.75
}
all_updates_rule {
monitoring_notification_channels = [
google_monitoring_notification_channel.notification_channel_billing.id,
]
}
}
# LOG MONITORING / ALERTS (production)
resource "google_logging_metric" "log_metric_route" {
project = google_project.production.project_id
name = "route_monitoring/metric"
filter = "resource.type=\"gce_route\" AND jsonPayload.event_subtype=\"compute.routes.delete\" OR jsonPayload.event_subtype=\"compute.routes.insert\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Route Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_route" {
project = google_project.shared_monitoring.project_id
display_name = "Route Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/ROUTE_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/route_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_sql_instance" {
project = google_project.production.project_id
name = "sql_instance_monitoring/metric"
filter = "protoPayload.methodName=\"cloudsql.instances.update\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "SQL Instance Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_sql_instance" {
project = google_project.shared_monitoring.project_id
display_name = "SQL Instance Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/SQL_INSTANCE_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/sql_instance_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_network" {
project = google_project.shared_nw_prod.project_id
name = "network_monitoring/metric"
filter = "resource.type=gce_network AND jsonPayload.event_subtype=\"compute.networks.insert\" OR jsonPayload.event_subtype=\"compute.networks.patch\" OR jsonPayload.event_subtype=\"compute.networks.delete\" OR jsonPayload.event_subtype=\"compute.networks.removePeering\" OR jsonPayload.event_subtype=\"compute.networks.addPeering\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Network Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_network" {
project = google_project.shared_monitoring.project_id
display_name = "Network Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/NETWORK_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/network_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_firewall" {
project = google_project.shared_nw_prod.project_id
name = "firewall_monitoring/metric"
filter = "resource.type=\"gce_firewall_rule\" AND jsonPayload.event_subtype=\"compute.firewalls.patch\" OR jsonPayload.event_subtype=\"compute.firewalls.insert\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Firewall Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_firewall" {
project = google_project.shared_monitoring.project_id
display_name = "Firewall Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/FIREWALL_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/firewall_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_project_ownership" {
project = google_project.production.project_id
name = "project_ownership_monitoring/metric"
filter = "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\") AND (ProjectOwnership OR projectOwnerInvitee) OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"REMOVE\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\") OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"ADD\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\")"
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Project Ownership Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_project_ownership" {
project = google_project.shared_monitoring.project_id
display_name = "Project Ownership Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/PROJECT_OWNERSHIP_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/project_ownership_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_bucket_iam" {
project = google_project.production.project_id
name = "bucket_iam_monitoring/metric"
filter = "resource.type=gcs_bucket AND protoPayload.methodName=\"storage.setIamPermissions\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Bucket IAM Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_bucket_iam" {
project = google_project.shared_monitoring.project_id
display_name = "Bucket IAM Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/BUCKET_IAM_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/bucket_iam_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_audit_config" {
project = google_project.production.project_id
name = "audit_config_monitoring/metric"
filter = "protoPayload.methodName=\"SetIamPolicy\" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*"
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Audit Config Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_audit_config" {
project = google_project.shared_monitoring.project_id
display_name = "Audit Config Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/AUDIT_CONFIG_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/audit_config_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
resource "google_logging_metric" "log_metric_custom_role" {
project = google_project.production.project_id
name = "custom_role_monitoring/metric"
filter = "resource.type=\"iam_role\" AND protoPayload.methodName=\"google.iam.admin.v1.CreateRole\" OR protoPayload.methodName=\"google.iam.admin.v1.DeleteRole\" OR protoPayload.methodName=\"google.iam.admin.v1.UpdateRole\""
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
unit = "1"
display_name = "Custom Role Monitoring"
}
}
resource "google_monitoring_alert_policy" "alert_policy_custom_role" {
project = google_project.shared_monitoring.project_id
display_name = "Custom Role Monitoring"
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.notification_channel_security.name]
conditions {
display_name = "logging/user/CUSTOM_ROLE_MONITORING"
condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/custom_role_monitoring/metric\" AND resource.type=\"global\""
duration = "60s"
comparison = "COMPARISON_GT"
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
cross_series_reducer = "REDUCE_COUNT"
}
trigger {
count = 1
percent = 0
}
}
}
}
# IAM roles
# org
# resource "google_organization_iam_binding" "org_iam_org_admin" {
# org = var.org_id
# role = "roles/iam.organizationAdmin"
#
# members = [
# var.group_org_admins
# ]
# }
#
# resource "google_organization_iam_binding" "org_iam_billing_admin" {
# org = var.org_id
# role = "roles/billing.admin"
#
# members = [
# var.group_billing_admins
# ]
# }
#
# Billing Account User (tf-sa: org)
# resource "google_organization_iam_binding" "org_iam_billing_user" {
# org = var.org_id
# role = "roles/billing.user"
#
# members = [
# var.sa_terraform_admin
# ]
# }
#
# Organization Policy Admin (tf-sa: org)
# resource "google_organization_iam_binding" "org_iam_org_policy_admin" {
# org = var.org_id
# role = "roles/orgpolicy.policyAdmin"
#
# members = [
# var.sa_terraform_admin
# ]
# }
#
# Cloud Security Scanner Editor (security: org)
# resource "google_organization_iam_binding" "org_iam_security_scanner_editor" {
# org = var.org_id
# role = "roles/cloudsecurityscanner.editor"
#
# members = [
# var.group_security_admins
# ]
# }
# TODO: change (org) scoped bindings to google_organization_iam_binding (non-playground-org)
# Viewer (security, network, devops: org)
resource "google_folder_iam_binding" "folder_iam_viewer" {
folder = google_folder.demo_org.id
role = "roles/viewer"
members = [
var.group_security_admins,
var.group_network_admins,
var.group_devops
]
}
# Security Admin (security: org)
resource "google_folder_iam_binding" "folder_iam_security_admin" {
folder = google_folder.demo_org.id
role = "roles/iam.securityAdmin"
members = [
var.group_security_admins
]
}
# Compute Network Admin (network: org) roles/compute.networkAdmin
resource "google_folder_iam_binding" "folder_iam_compute_network_admin" {
folder = google_folder.demo_org.id
role = "roles/compute.networkAdmin"
members = [
var.group_network_admins
]
}
# Service Networking Admin (network: org) roles/servicenetworking.networksAdmin
resource "google_folder_iam_binding" "folder_iam_service_networking_admin" {
folder = google_folder.demo_org.id
role = "roles/servicenetworking.networksAdmin"
members = [
var.group_network_admins
]
}
# Compute Shared VPC Admin (network, tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_xpn_admin" {
folder = google_folder.demo_org.id
role = "roles/compute.xpnAdmin"
members = [
var.group_network_admins
]
}
# Logs Viewer (network: org)
resource "google_folder_iam_binding" "folder_iam_log_viewer" {
folder = google_folder.demo_org.id
role = "roles/compute.xpnAdmin"
members = [
var.group_network_admins
]
}
# Private Logs Viewer (security: org)
resource "google_folder_iam_binding" "folder_iam_private_log_viewer" {
folder = google_folder.demo_org.id
role = "roles/logging.viewer"
members = [
var.group_network_admins
]
}
# Compute Security Admin (security: org)
resource "google_folder_iam_binding" "folder_iam_compute_security_admin" {
folder = google_folder.demo_org.id
role = "roles/compute.securityAdmin"
members = [
var.group_network_admins
]
}
# Compute Organization Security Policy Admin (security: org)
resource "google_folder_iam_binding" "folder_iam_compute_org_security_policy_admin" {
folder = google_folder.demo_org.id
role = "roles/compute.orgSecurityPolicyAdmin"
members = [
var.group_network_admins
]
}
# Compute Instance Admin (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_compute_instance_admin" {
folder = google_folder.demo_org.id
role = "roles/compute.instanceAdmin"
members = [
var.sa_terraform_admin
]
}
# Create Service Accounts (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_sa_creator" {
folder = google_folder.demo_org.id
role = "roles/iam.serviceAccountCreator"
members = [
var.sa_terraform_admin
]
}
# Delete Service Accounts (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_sa_deleter" {
folder = google_folder.demo_org.id
role = "roles/iam.serviceAccountDeleter"
members = [
var.sa_terraform_admin
]
}
# Service Account User (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_sa_user" {
folder = google_folder.demo_org.id
role = "roles/iam.serviceAccountUser"
members = [
var.sa_terraform_admin
]
}
# Service Account Token Creator (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_sa_token_creator" {
folder = google_folder.demo_org.id
role = "roles/iam.serviceAccountTokenCreator"
members = [
var.sa_terraform_admin
]
}
# Logs Configuration Writer (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_log_config_writer" {
folder = google_folder.demo_org.id
role = "roles/logging.configWriter"
members = [
var.sa_terraform_admin
]
}
# Folder Creator (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_folder_creator" {
folder = google_folder.demo_org.id
role = "roles/resourcemanager.folderCreator"
members = [
var.sa_terraform_admin
]
}
# Folder Editor (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_folder_editor" {
folder = google_folder.demo_org.id
role = "roles/resourcemanager.folderEditor"
members = [
var.sa_terraform_admin
]
}
# projects
# Project Creator (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_project_creator" {
folder = google_folder.demo_org.id
role = "roles/resourcemanager.projectCreator"
members = [
var.sa_terraform_admin
]
}
# Project Deleter (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_product_deleter" {
folder = google_folder.demo_org.id
role = "roles/resourcemanager.projectDeleter"
members = [
var.sa_terraform_admin
]
}
# Access Context Manager Editor (tf-sa: org)
resource "google_folder_iam_binding" "folder_iam_access_context_editor" {
folder = google_folder.demo_org.id
role = "roles/accesscontextmanager.policyEditor"
members = [
var.sa_terraform_admin
]
}
# BigQuery Data Viewer (billing: billing project)
resource "google_project_iam_binding" "project_iam_bq_data_viewer" {
project = google_project.shared_billing.project_id
role = "roles/bigquery.dataViewer"
members = [
var.group_billing_admins
]
}
# Editor (security: security project)
resource "google_project_iam_binding" "project_iam_security_editor" {
project = google_project.shared_security.project_id
role = "roles/editor"
members = [
var.group_security_admins
]
}
# Monitoring Admin (devops: monitoring project)
resource "google_project_iam_binding" "project_iam_monitoring_admin" {
project = google_project.shared_monitoring.project_id
role = "roles/monitoring.admin"
members = [
var.group_devops
]
}
# Monitoring Viewer (dev: monitoring project)
resource "google_project_iam_binding" "project_iam_monitoring_viewer" {
project = google_project.shared_monitoring.project_id
role = "roles/monitoring.viewer"
members = [
var.group_developers
]
}
# Kubernetes Engine Developer (dev: development project)
resource "google_project_iam_binding" "project_iam_container_developer" {
project = google_project.development.project_id
role = "roles/container.developer"
members = [
var.group_developers
]
}
variable "org_id" {
default = "YOUR_ORG_ID"
}
variable "billing_account_id" {
default = "CHANGEME" # DoiT Playground
}
# wherever you set up your workspace for monitoring
variable "monitoring_project_id" {
default = "mike-stage"
}
# finding GSuite ID: https://www.youtube.com/watch?v=AeadQfJT5kw
variable "allowed_domain_ids" {
default = ["CHANGEME"]
}
variable "region" {
default = "us-west4"
}
variable "zone" {
default = "us-west4-a"
}
variable "root_folder" {
default = "folders/CHANGEME" # CHANGE: folder in playground
}
variable "audit_logs_bucket_name" {
default = "demo-org-audit-logs"
}
# IAM groups (set up in Cloud Identity or GSuite)
# CHANGE: using personal domain for testing / demo
variable "group_org_admins" {
default = "group:orgadmins@yourco.com"
}
variable "group_billing_admins" {
default = "group:billingadmins@yourco.com"
}
variable "group_security_admins" {
default = "group:securityadmins@yourco.com"
}
variable "group_network_admins" {
default = "group:networkadmins@yourco.com"
}
variable "group_devops" {
default = "group:devops@yourco.com"
}
variable "group_developers" {
default = "group:developers@yourco.com"
}
variable "sa_terraform_admin" {
default = "serviceAccount:terraform-sa-admin@devops.iam.gserviceaccount.com"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment