blob: d5ce49502ac0c5db4cdbd90819730d97ca62f27e [file] [log] [blame]
# Copyright 2021 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Terraform configuration for GCP components from this repo.
terraform {
required_version = ">= 1.0.9, < 2.0.0"
# Store terraform state in a GCS bucket, so all team members share it.
backend "gcs" {
bucket = "go-ecosystem"
}
required_providers {
google = {
version = "~> 4.55.0"
source = "hashicorp/google"
}
}
}
locals {
region = "us-central1"
}
provider "google" {
region = local.region
}
# Inputs for values that should not appear in the repo.
# Terraform will prompt for these when you run it, or
# you can put them in a local file that is only readable
# by you, and pass them to terraform.
# See https://www.terraform.io/docs/language/values/variables.html#variable-definitions-tfvars-files.
variable "prod_project" {
description = "GCP project where resources live"
type = string
}
variable "dev_project" {
description = "GCP project where resources live"
type = string
}
variable "team_group" {
description = "GCP group for the entire team"
type = string
}
variable "deployers_group" {
description = "GCP group for deployers"
type = string
}
variable "pkgsite_db_project" {
description = "project containing pkgsite DB"
type = string
}
variable "pkgsite_db_name" {
description = "name of pkgsite DB"
type = string
}
variable "vulndb_bucket_project" {
description = "project ID for vuln DB bucket logs"
type = string
}
# Enabled APIs
resource "google_project_service" "apis" {
for_each = toset([
"bigquery",
"cloudbuild",
"clouderrorreporting",
"cloudscheduler",
"cloudtasks",
"cloudtrace",
"compute",
"containerregistry",
"firestore",
"iap",
"logging",
"monitoring",
"oslogin",
"pubsub",
"run",
"secretmanager",
"sql-component",
"sqladmin",
"storage-api",
"storage-component"
])
service = "${each.key}.googleapis.com"
disable_on_destroy = false
}
# Service accounts
resource "google_service_account" "worker" {
account_id = "worker"
display_name = "ecosystem metrics worker service account"
description = "Service account used by ecosystem metrics services."
}
resource "google_service_account_iam_policy" "worker" {
service_account_id = google_service_account.worker.name
policy_data = data.google_iam_policy.worker.policy_data
}
# Permissions on the worker service account.
# These grant other identities (like users and groups) permissions
# to do things to/with the service account.
# In IAM terms, the service account is acting as a resource here, not an identity.
# The permissions *for* the service account (those that let the service account
# do things, that treat the service account as an identity) are not represented
# in terraform because they are on the project resource, which is managed
# by an iam_policy file internal to Google.
data "google_iam_policy" "worker" {
binding {
# Let any ecosystem deployer act as this service account.
role = "roles/iam.serviceAccountUser"
members = [var.deployers_group]
}
}
resource "google_service_account" "impersonate" {
account_id = "impersonate"
display_name = "impersonate service account"
description = "Users can act as this service account."
}
resource "google_service_account_iam_policy" "impersonate" {
service_account_id = google_service_account.impersonate.name
policy_data = data.google_iam_policy.impersonate.policy_data
}
# Permissions on the impersonate service account.
data "google_iam_policy" "impersonate" {
binding {
# Let anyone in the ecosystem and golang group get an access token for this service account.
role = "roles/iam.serviceAccountTokenCreator"
members = [
var.team_group,
"group:golang-eng-policy@twosync.google.com"
]
}
binding {
# Let anyone in the ecosystem and golang group act as this service account.
role = "roles/iam.serviceAccountUser"
members = [
var.team_group,
"group:golang-eng-policy@twosync.google.com"
]
}
binding {
# Let anyone in the ecosystem and golang group view most of Cloud resources, including permissions.
role = "roles/viewer"
members = [
var.team_group,
"group:golang-eng-policy@twosync.google.com"
]
}
}
resource "google_logging_metric" "scheduler_errors" {
name = "cloud-scheduler-errors"
description = "Number of errors from Cloud Scheduler jobs"
filter = "resource.type=cloud_scheduler_job AND severity>=ERROR"
metric_descriptor {
metric_kind = "DELTA"
unit = "1"
value_type = "INT64"
}
}
resource "google_logging_metric" "build_errors" {
name = "cloud-build-errors"
description = "Errors from Cloud Build"
filter = "resource.type=build AND textPayload=ERROR"
metric_descriptor {
metric_kind = "DELTA"
unit = "1"
value_type = "INT64"
}
}
resource "google_monitoring_notification_channel" "email" {
display_name = "Go Ecosystem Team Alerts"
type = "email"
labels = {
email_address = "go-ecosystem-team+alerts@google.com"
}
}
resource "google_monitoring_alert_policy" "scheduler_job_failing" {
display_name = "Cloud Scheduler Job Failing"
conditions {
display_name = "Instance Count"
condition_threshold {
filter = <<-EOT
metric.type="logging.googleapis.com/user/cloud-scheduler-errors"
EOT
comparison = "COMPARISON_GT"
threshold_value = 1
aggregations {
alignment_period = "600s"
cross_series_reducer = "REDUCE_SUM"
per_series_aligner = "ALIGN_DELTA"
}
duration = "0s"
trigger { count = 1 }
}
}
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.email.name]
}
resource "google_monitoring_alert_policy" "build_job_failing" {
display_name = "Cloud Build Job Failing"
conditions {
display_name = "Instance Count"
condition_threshold {
filter = <<-EOT
metric.type="logging.googleapis.com/user/cloud-build-errors"
EOT
comparison = "COMPARISON_GT"
threshold_value = 1
aggregations {
alignment_period = "600s"
cross_series_reducer = "REDUCE_SUM"
per_series_aligner = "ALIGN_DELTA"
}
duration = "0s"
trigger { count = 1 }
}
}
combiner = "OR"
notification_channels = [google_monitoring_notification_channel.email.name]
}
# Cloud Build trigger to deploy the prod worker on every push to master.
resource "google_cloudbuild_trigger" "deploy_prod_worker" {
name = "Deploy-Prod-Ecosystem-Worker"
trigger_template {
branch_name = "master"
repo_name = "pkgsite-metrics"
}
filename = "deploy/worker.yaml"
substitutions = {
"_ENV" = "prod"
"_BQ_DATASET" = "prod"
}
}
# Secret for computing HMACs to obfuscate VulnDB request IPs.
resource "google_secret_manager_secret" "vulndb-hmac-key" {
secret_id = "vulndb-hmac-key"
replication {
automatic = true
}
}
# Deployment environments
module "prod" {
source = "./environment"
env = "prod"
project = var.prod_project
region = local.region
pkgsite_db_project = var.pkgsite_db_project
pkgsite_db_name = var.pkgsite_db_name
vulndb_bucket_project = var.vulndb_bucket_project
use_profiler = true
}
module "dev" {
source = "./environment"
env = "dev"
project = var.dev_project
region = local.region
pkgsite_db_project = var.pkgsite_db_project
pkgsite_db_name = var.pkgsite_db_name
vulndb_bucket_project = var.vulndb_bucket_project
use_profiler = false
}