diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..a2228e60a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,56 @@ +name: Deploy service + +permissions: + contents: read + id-token: write + +on: + push: + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + terraform-plan: +# needs: [ docker-sync ] + runs-on: ubuntu-latest + steps: + - name: Acquire sources + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v1 + + - name: Google Auth + uses: google-github-actions/auth@v2 + with: + project_id: wetterdienst + workload_identity_provider: projects/867542820543/locations/global/workloadIdentityPools/github/providers/github + + - name: Terraform init + working-directory: ./terraform + run: terraform init + + - name: Terraform plan + working-directory: ./terraform + run: terraform plan + + terraform-apply: + needs: [ terraform-plan ] +# if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Acquire sources + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v1 + + - name: Terraform init + working-directory: ./terraform + run: terraform init + + - name: Terraform apply + working-directory: ./terraform + run: terraform apply -auto-approve \ No newline at end of file diff --git a/.github/workflows/docker-publish-standard.yml b/.github/workflows/docker-publish-standard.yml index 3d7f63819..6714d9408 100644 --- a/.github/workflows/docker-publish-standard.yml +++ b/.github/workflows/docker-publish-standard.yml @@ -151,3 +151,29 @@ jobs: set -x git describe --tags git status + + docker-sync: + needs: [ docker] + runs-on: ubuntu-latest + steps: + - name: Acquire sources + uses: actions/checkout@v4 + + - name: Setup Docker + uses: docker/setup-buildx-action@v1 + + - name: Docker login + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker pull + run: docker pull ghcr.io/${{ github.repository }}-standard:latest + + - name: Docker tag + run: docker tag ghcr.io/earthobservations/wetterdienst-standard:latest europe-north1-docker.pkg.dev/wetterdienst/docker-wetterdienst/wetterdienst-standard:latest + + - name: Docker push + run: docker push europe-north1-docker.pkg.dev/wetterdienst/docker-wetterdienst/wetterdienst-standard:latest diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml new file mode 100644 index 000000000..e9d18467b --- /dev/null +++ b/.github/workflows/terraform.yml @@ -0,0 +1,60 @@ +name: Terraform + +permissions: + contents: read + id-token: write + +on: + push: + + # Allow job to be triggered manually. + workflow_dispatch: + +# Cancel in-progress jobs when pushing to the same branch. +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + terraform: + runs-on: ubuntu-latest + steps: + - name: Acquire sources + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v1 + + - name: Google Auth + uses: google-github-actions/auth@v1 + env: + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + with: + workload_identity_provider: ${{ env.workload_identity_provider }} + service_account: cicd-dev@wetterdienst.iam.gserviceaccount.com + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Export Github PAT + run: echo "TF_VAR_gh_pat=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + + - name: Terraform init + working-directory: ./terraform + run: terraform init + + - name: Terraform plan + working-directory: ./terraform + env: + TV_VAR_gh_pat: ${{ env.TV_VAR_gh_pat }} + run: terraform plan + + - name: Terraform apply + working-directory: ./terraform + env: + TV_VAR_gh_pat: ${{ env.TV_VAR_gh_pat }} + run: terraform apply -auto-approve diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 000000000..8a1091c47 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,105 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/google" { + version = "5.7.0" + constraints = ">= 4.50.0, < 6.0.0" + hashes = [ + "h1:dGrS2F0C3frYTdaYvev6fZDWAGBE6O7Q4DhfO/0P7r8=", + "zh:0c0cf15cc034d5f92cc1cd5ee4615012553a674b69ee1802e46c4b87f1c339aa", + "zh:28e64a798320866c4dc84c323b66eef94ec98043dba016cf01d6adbe2dc85de4", + "zh:3b6e6443a9000354f93682d847737d6e9f702a77c53a492a39b200134b3e8dfd", + "zh:3ed6af130702d9da8fc14f94b3b2c9a93917cda31d50d934dd6de0ca48044572", + "zh:784a0feae2a48aa9a63fe6feb86ad29e8d35647fa29eb42303b799f09ee92060", + "zh:828e0198d99b7f9e53994470d6b51012566660a560da9c8266d1eaf2b140635c", + "zh:8dcb7537d95ec14e75ca71cfce62323682ce0fb453902dc9f890b7c524a915d3", + "zh:a7e760dc5707603091a0c3de0d47d6f8e51d8cce523b5c90587b05f113c5e09c", + "zh:b5c79a5e5b9bcaf0158f5f704d31cf90fb93826085151f06dfc3ef48276ed17a", + "zh:c44a2726dcfbf7d538aa0d5abd2473108f625d1d82485a340e62dfc04043288f", + "zh:f4da66ba04847138949a6a178b8836182f7960e9d069bfe76f1203d9af99cd22", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/google-beta" { + version = "5.7.0" + constraints = ">= 4.50.0, < 6.0.0" + hashes = [ + "h1:Rvo7YTb0Uu3oN+2FG0NZ1hBAg1Ra8630U6vkK8OQ2IA=", + "zh:1720258635c34406db44e3d08df9cc02e6897f804d6d558e1c73772324df7b30", + "zh:1a385e9b3d7cda4d76b242f78086f33600c566386fde97d625f3bd39e1dcb1ff", + "zh:26e01a0059c3d9954d0af22ccc05bb21a5b8af7f91a790311cf8ba13e10a5646", + "zh:2acdab4240714cc31407324773280eeeb8ec9ab420404a3f3b8c0f25d73a5e00", + "zh:4836143995c83c925b040c8bc7d3958fa6743c2179a098e783bf919e17db16ab", + "zh:4ca384ea0153ba101af3ca97276f59e76586f935c99b444bd360a4009756af2d", + "zh:54cc3398e8c336bd3f836954f87d3a7ae8fc4bced070baac66a244af656163d4", + "zh:a3e5d9eacc27047ea0c3c00753da3966516dfc982dee180a3a5f4a405689447e", + "zh:cc2052e93d0b52151a2374aa49e56de823ff11dce0570fa7c4bbbcf89467670f", + "zh:d8dc64ade395715dbb41753bda72b1bce6348cd2011f95b1cea1b2c675770c58", + "zh:da1fe36816881dac4acd7ab37291365c4b92584b8689c7c745c7a5b6800049c0", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.5.1" + constraints = ">= 2.1.0, ~> 3.0" + hashes = [ + "h1:IL9mSatmwov+e0+++YX2V6uel+dV6bn+fC/cnGDK3Ck=", + "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64", + "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d", + "zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831", + "zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3", + "zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b", + "zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2", + "zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865", + "zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03", + "zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602", + "zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014", + ] +} + +provider "registry.terraform.io/integrations/github" { + version = "5.42.0" + hashes = [ + "h1:rfyLEgbZCk3MMCBuGd4PNFM914vtLqGIYcsmVKr6tdg=", + "zh:0f97039c6b70295c4a82347bc8a0bcea700b3fb3df0e0be53585da025584bb7c", + "zh:12e78898580cc2a72b5f2a77e191b158f88e974b0500489b691f34842288745c", + "zh:23660933e4f00293c0d4d6cd6b4d72e382c0df46b70cecf22b5c4c090d3b61e3", + "zh:74119174b46d8d197dd209a246bf8b5db113c66467e02c831e68a8ceea312d3e", + "zh:829c4c0c202fc646eb0e1759eb9c8f0757df5295be2d3344b8fd6ca8ce9ef33b", + "zh:92043e667f520aee4e08a10a183ad5abe5487f3e9c8ad5a55ea1358b14b17b1a", + "zh:998909806b4ff42cf480fcd359ec1f12b868846f89284b991987f55de24876b7", + "zh:9f758447db3bf386516562abd6da1e54d22ddc207bda25961d2b5b049f32da0f", + "zh:a6259215612d4d6a281c671b2d5aa3a0a0b0a3ae92ed60b633998bb692e922d3", + "zh:ad7d78056beb44191911db9443bf5eec41a3d60e7b01def2a9e608d1c4288d27", + "zh:b697e7b0abef3000e1db482c897b82cd455621b488bb6c4cd3d270763d7b08ac", + "zh:db8e849eded8aebff780f89ab7e1339053d2f15c1c8f94103d70266a090527ad", + "zh:e5bdbb85fb148dd75877a7b94b595d4e8680e495c241db02c4b12b91e9d08953", + "zh:ee812c5fd77d3817fb688f720e5eb42d7ff04db67a125de48b05458c9f657483", + ] +} + +provider "registry.terraform.io/kreuzwerker/docker" { + version = "3.0.2" + constraints = "3.0.2" + hashes = [ + "h1:XjdpVL61KtTsuPE8swok3GY8A+Bu3TZs8T2DOEpyiXo=", + "zh:15b0a2b2b563d8d40f62f83057d91acb02cd0096f207488d8b4298a59203d64f", + "zh:23d919de139f7cd5ebfd2ff1b94e6d9913f0977fcfc2ca02e1573be53e269f95", + "zh:38081b3fe317c7e9555b2aaad325ad3fa516a886d2dfa8605ae6a809c1072138", + "zh:4a9c5065b178082f79ad8160243369c185214d874ff5048556d48d3edd03c4da", + "zh:5438ef6afe057945f28bce43d76c4401254073de01a774760169ac1058830ac2", + "zh:60b7fadc287166e5c9873dfe53a7976d98244979e0ab66428ea0dea1ebf33e06", + "zh:61c5ec1cb94e4c4a4fb1e4a24576d5f39a955f09afb17dab982de62b70a9bdd1", + "zh:a38fe9016ace5f911ab00c88e64b156ebbbbfb72a51a44da3c13d442cd214710", + "zh:c2c4d2b1fd9ebb291c57f524b3bf9d0994ff3e815c0cd9c9bcb87166dc687005", + "zh:d567bb8ce483ab2cf0602e07eae57027a1a53994aba470fa76095912a505533d", + "zh:e83bf05ab6a19dd8c43547ce9a8a511f8c331a124d11ac64687c764ab9d5a792", + "zh:e90c934b5cd65516fbcc454c89a150bfa726e7cf1fe749790c7480bbeb19d387", + "zh:f05f167d2eaf913045d8e7b88c13757e3cf595dd5cd333057fdafc7c4b7fed62", + "zh:fcc9c1cea5ce85e8bcb593862e699a881bd36dffd29e2e367f82d15368659c3d", + ] +} diff --git a/terraform/artifact_registry.tf b/terraform/artifact_registry.tf new file mode 100644 index 000000000..057d66d24 --- /dev/null +++ b/terraform/artifact_registry.tf @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository" "docker-wetterdienst" { + repository_id = "docker-wetterdienst" + location = var.region + format = "DOCKER" + description = "Standard image repository for the wetterdienst project." +} diff --git a/terraform/cloud_storage.tf b/terraform/cloud_storage.tf new file mode 100644 index 000000000..aa8df8b17 --- /dev/null +++ b/terraform/cloud_storage.tf @@ -0,0 +1,7 @@ +resource "google_storage_bucket" "wetterdienst-state" { + location = var.region + name = "wetterdienst-state" + versioning { + enabled = true + } +} \ No newline at end of file diff --git a/terraform/cloudrun.tf b/terraform/cloudrun.tf new file mode 100644 index 000000000..5ffe8c292 --- /dev/null +++ b/terraform/cloudrun.tf @@ -0,0 +1,36 @@ +resource "google_cloud_run_v2_service" "wetterdienst-restapi" { + name = "wetterdienst-restapi" + project = var.project + location = var.region + ingress = "INGRESS_TRAFFIC_ALL" + + template { + containers { + image = "${var.region}-docker.pkg.dev/${var.project}/${google_artifact_registry_repository.docker-wetterdienst.name}/wetterdienst-standard:latest" + command = ["wetterdienst", "restapi", "--listen=0.0.0.0:8080"] + resources { + limits = { + cpu = "1000m" + memory = "512Mi" + } + } + } + scaling { + min_instance_count = 1 + max_instance_count = 10 + } + } +} + +resource "google_cloud_run_domain_mapping" "wetterdienst-earth-observations-net" { + name = "wetterdienst.earth-observations.net" + location = var.region + + metadata { + namespace = var.project + } + + spec { + route_name = google_cloud_run_v2_service.wetterdienst-restapi.name + } +} \ No newline at end of file diff --git a/terraform/iam.tf b/terraform/iam.tf new file mode 100644 index 000000000..95e7a4788 --- /dev/null +++ b/terraform/iam.tf @@ -0,0 +1,5 @@ +resource "google_storage_bucket_iam_member" "state" { + bucket = google_storage_bucket.wetterdienst-state.name + role = "roles/storage.admin" + member = "serviceAccount:cicd-dev@wetterdienst.iam.gserviceaccount.com" +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 000000000..f2cc0548a --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,38 @@ +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "3.0.2" + } + google = { + source = "hashicorp/google" + } + google-beta = { + source = "hashicorp/google-beta" + } + github = { + source = "integrations/github" + } + } + + backend "gcs" { + bucket = "wetterdienst-state" + prefix = "terraform/state" + } +} + +provider "docker" { +# host = "unix:///var/run/docker.sock" + registry_auth { + address = "ghcr.io" + username = var.gh_username + password = var.gh_pat + } +} + +provider "github" {} + +provider "google" { + project = var.project + region = var.region +} diff --git a/terraform/network.tf b/terraform/network.tf new file mode 100644 index 000000000..45bde2779 --- /dev/null +++ b/terraform/network.tf @@ -0,0 +1,38 @@ +resource "google_compute_region_network_endpoint_group" "serverless_neg" { + name = "serverless-neg" + project = var.project + network_endpoint_type = "SERVERLESS" + region = var.region + cloud_run { + service = google_cloud_run_v2_service.wetterdienst-restapi.name + } +} + +module "lb-http" { + source = "GoogleCloudPlatform/lb-http/google//modules/serverless_negs" + name = "loadbalancer" + project = var.project + + https_redirect = true + + security_policy = google_compute_security_policy.default.name + + backends = { + default = { + description = null + groups = [ + { + group = google_compute_region_network_endpoint_group.serverless_neg.id + } + ] + enable_cdn = false + + iap_config = { + enable = false + } + log_config = { + enable = false + } + } + } +} \ No newline at end of file diff --git a/terraform/security_policy.tf b/terraform/security_policy.tf new file mode 100644 index 000000000..f60cea191 --- /dev/null +++ b/terraform/security_policy.tf @@ -0,0 +1,107 @@ + +# Source: https://github.com/ybellerose/GCP-Cloud-Armor/blob/main/Cloud%20Armor%20Deployment/cloud_armor_sec_policy/cloud_armor_sec_policy.tf +resource "google_compute_security_policy" "default" { + project = var.project + name = "${var.project}-waf-policy" + description = "Default rule, Top 10 OWASP, Throttling & Log4J custom rules" + # --------------------------------- + # Default rules + # --------------------------------- + dynamic "rule" { + for_each = var.default_rules + content { + action = rule.value.action + priority = rule.value.priority + description = rule.value.description + preview = rule.value.preview + match { + versioned_expr = rule.value.versioned_expr + config { + src_ip_ranges = rule.value.src_ip_ranges + } + } + } + } + + # --------------------------------- + # Throttling traffic rules + # --------------------------------- + dynamic "rule" { + for_each = var.throttle_rules + content { + action = rule.value.action + priority = rule.value.priority + description = rule.value.description + preview = rule.value.preview + match { + versioned_expr = rule.value.versioned_expr + config { + src_ip_ranges = rule.value.src_ip_ranges + } + } + rate_limit_options { + conform_action = rule.value.conform_action + exceed_action = rule.value.exceed_action + enforce_on_key = rule.value.enforce_on_key + rate_limit_threshold { + count = rule.value.rate_limit_threshold_count + interval_sec = rule.value.rate_limit_threshold_interval_sec + } + } + } + } + + # --------------------------------- + # Country limitation + # --------------------------------- + dynamic "rule" { + for_each = var.countries_rules + content { + action = rule.value.action + priority = rule.value.priority + description = rule.value.description + preview = rule.value.preview + match { + expr { + expression = rule.value.expression + } + } + } + } + + # --------------------------------- + # OWASP top 10 rules + # --------------------------------- + dynamic "rule" { + for_each = var.owasp_rules + content { + action = rule.value.action + priority = rule.value.priority + description = rule.value.description + preview = rule.value.preview + match { + expr { + expression = rule.value.expression + } + } + } + } + + # --------------------------------- + # Custom Log4j rule + # --------------------------------- + dynamic "rule" { + for_each = var.cves_and_vulnerabilities_rules + content { + action = rule.value.action + priority = rule.value.priority + description = rule.value.description + preview = rule.value.preview + match { + expr { + expression = rule.value.expression + } + } + } + } +} \ No newline at end of file diff --git a/terraform/service_accounts.tf b/terraform/service_accounts.tf new file mode 100644 index 000000000..8ca2143be --- /dev/null +++ b/terraform/service_accounts.tf @@ -0,0 +1,3 @@ +resource "google_service_account" "cloud-runner" { + account_id = "cloud-runner" +} \ No newline at end of file diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 000000000..733ee86e3 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,291 @@ +variable "region" { + default = "europe-north1" # finland +} + +variable "project" { + default = "wetterdienst" +} + +variable "gh_username" { + default = "gutzbenj" +} + +variable "gh_pat" { +} + +variable "default_rules" { + default = { + def_rule = { + action = "allow" + priority = "2147483647" + versioned_expr = "SRC_IPS_V1" + src_ip_ranges = ["*"] + description = "Default rule" + preview = false + } + } + type = map(object({ + action = string + priority = string + versioned_expr = string + src_ip_ranges = list(string) + description = string + preview = bool + }) + ) +} + +# --------------------------------- +# Throttling traffic rules +# --------------------------------- +variable "throttle_rules" { + default = { + def_rule = { + action = "throttle" + priority = "4000" + versioned_expr = "SRC_IPS_V1" + src_ip_ranges = ["*"] + description = "Throttling traffic rule" + conform_action = "allow" + exceed_action = "deny(429)" + enforce_on_key = "ALL" #https://cloud.google.com/armor/docs/rate-limiting-overview#identifying_clients_for_rate_limiting + rate_limit_threshold_count = "100" + rate_limit_threshold_interval_sec = "60" + preview = true + } + } + type = map(object({ + action = string + priority = string + versioned_expr = string + src_ip_ranges = list(string) + description = string + conform_action = string + exceed_action = string + enforce_on_key = string + rate_limit_threshold_count = number + rate_limit_threshold_interval_sec = number + preview = bool + }) + ) +} + +# --------------------------------- +# Countries limitation rules +# --------------------------------- +variable "countries_rules" { + default = { + def_rule = { + action = "deny(403)" + priority = "3000" + expression = "'[CN, RU]'.contains(origin.region_code)" + description = "Deny if region code is listed" + preview = true + } + } + type = map(object({ + action = string + priority = string + expression = string + description = string + preview = bool + }) + ) +} +# --------------------------------- +# OWASP top 10 rules +# --------------------------------- +variable "owasp_rules" { + default = { + #https://cloud.google.com/armor/docs/rule-tuning#sql_injection_sqli + rule_sqli = { + action = "deny(403)" + priority = "1000" + description = "SQL injection" + preview = true + + ### Detect Level severity (0 to 4): 0 mean no rules enabled and 4 is the most sensitive + expression = "evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 4})" + #Latest + #expression = "evaluatePreconfiguredWaf('sqli-v33-canary', {'sensitivity': 4})" + } + #https://cloud.google.com/armor/docs/rule-tuning#cross-site_scripting_xss + rule_xss = { + action = "deny(403)" + priority = "1001" + description = "Cross-site scripting" + preview = true + + ### Detect Level severity (0 to 2): 0 mean no rules enabled and 2 is the most sensitive + expression = "evaluatePreconfiguredWaf('xss-v33-stable', {'sensitivity': 2})" + #Latest + #expression = "evaluatePreconfiguredWaf('xss-v33-canary', {'sensitivity': 2})" + + } + #https://cloud.google.com/armor/docs/rule-tuning#local_file_inclusion_lfi + rule_lfi = { + action = "deny(403)" + priority = "1002" + description = "Local file inclusion" + preview = true + + ### Detect Level severity (0 to 1): 0 mean no rules enabled and 1 is the most sensitive + expression = "evaluatePreconfiguredWaf('lfi-v33-stable', {'sensitivity': 1})" + #Latest + #expression = "evaluatePreconfiguredWaf('lfi-v33-canary', {'sensitivity': 1})" + } + #https://cloud.google.com/armor/docs/rule-tuning#remote_code_execution_rce + rule_rce = { + action = "deny(403)" + priority = "1003" + description = "Remote code execution" + preview = true + + ### Detect Level severity (0 to 3): 0 mean no rules enabled and 3 is the most sensitive + expression = "evaluatePreconfiguredWaf('rce-v33-stable', {'sensitivity': 3})" + #Latest + #expression = "evaluatePreconfiguredWaf('rce-v33-canary', {'sensitivity': 3})" + } + #https://cloud.google.com/armor/docs/rule-tuning#remote_file_inclusion_rfi + rule_rfi = { + action = "deny(403)" + priority = "1004" + description = "Remote file inclusion" + preview = true + + ### Detect Level severity (0 to 2): 0 mean no rules enabled and 2 is the most sensitive + expression = "evaluatePreconfiguredWaf('rfi-v33-stable', {'sensitivity': 2})" + #Latest + #expression = "evaluatePreconfiguredWaf('rfi-v33-canary', {'sensitivity': 2})" + } + #https://cloud.google.com/armor/docs/rule-tuning#method_enforcement + rule_methodenforcement = { + action = "deny(403)" + priority = "1005" + description = "Method enforcement" + preview = true + + ### Detect Level severity (0 to 1): 0 mean no rules enabled and 1 is the most sensitive + expression = "evaluatePreconfiguredWaf('methodenforcement-v33-stable', {'sensitivity': 1})" + #Latest + #expression = "evaluatePreconfiguredWaf('methodenforcement-v33-canary', {'sensitivity': 1})" + } + #https://cloud.google.com/armor/docs/rule-tuning#scanner_detection + rule_scandetection = { + action = "deny(403)" + priority = "1006" + description = "Scanner detection" + preview = true + + ### Detect Level severity (0 to 2): 0 mean no rules enabled and 2 is the most sensitive + expression = "evaluatePreconfiguredWaf('scannerdetection-v33-stable', {'sensitivity': 2})" + #Latest + #expression = "evaluatePreconfiguredWaf('scannerdetection-v33-canary', {'sensitivity': 2})" + } + #https://cloud.google.com/armor/docs/rule-tuning#protocol_attack + rule_protocolattack = { + action = "deny(403)" + priority = "1007" + description = "Protocol Attack" + preview = true + + + ### Detect Level severity (0 to 3): 0 mean no rules enabled and 3 is the most sensitive + expression = "evaluatePreconfiguredWaf('protocolattack-v33-stable', {'sensitivity': 3})" + #Latest + #expression = "evaluatePreconfiguredWaf('protocolattack-v33-canary', {'sensitivity': 3})" + } + #https://cloud.google.com/armor/docs/rule-tuning#php + rule_php = { + action = "deny(403)" + priority = "1008" + description = "PHP" + preview = true + + ### Detect Level severity (0 to 3): 0 mean no rules enabled and 3 is the most sensitive + expression = "evaluatePreconfiguredWaf('php-v33-stable', {'sensitivity': 3})" + #Latest + #expression = "evaluatePreconfiguredWaf('php-v33-canary', {'sensitivity': 3})" + } + #https://cloud.google.com/armor/docs/rule-tuning#session_fixation + rule_sessionfixation = { + action = "deny(403)" + priority = "1009" + description = "Session Fixation" + preview = true + + ### Detect Level severity (0 to 1): 0 mean no rules enabled and 1 is the most sensitive + expression = "evaluatePreconfiguredWaf('sessionfixation-v33-stable', {'sensitivity': 1})" + #Latest + #expression = "evaluatePreconfiguredWaf('sessionfixation-v33-canary', {'sensitivity': 1})" + } + #https://cloud.google.com/armor/docs/waf-rules#java_attack + rule_java = { + action = "deny(403)" + priority = "1010" + description = "Java attack" + preview = true + + ### Detect Level severity (0 to 3): 0 mean no rules enabled and 3 is the most sensitive + expression = "evaluatePreconfiguredWaf('java-v33-stable', {'sensitivity': 3})" + #Latest + #expression = "evaluatePreconfiguredWaf('java-v33-canary', {'sensitivity': 3})" + } + #https://cloud.google.com/armor/docs/waf-rules#nodejs_attack + rule_nodejs = { + action = "deny(403)" + priority = "1011" + description = "NodeJS attack" + preview = true + + ### Detect Level severity (0 to 1): 0 mean no rules enabled and 1 is the most sensitive + expression = "evaluatePreconfiguredWaf('nodejs-v33-stable', {'sensitivity': 1})" + #Latest + #expression = "evaluatePreconfiguredWaf('nodejs-v33-canary', {'sensitivity': 1})" + } + } + type = map(object({ + action = string + priority = string + description = string + preview = bool + expression = string + }) + ) +} + +# --------------------------------- +# Custom rules +# --------------------------------- +variable "cves_and_vulnerabilities_rules" { + default = { + # https://cloud.google.com/armor/docs/rule-tuning#cves_and_other_vulnerabilities + rule_apache_log4j = { + action = "deny(403)" + priority = "2000" + description = "Apache Log4j CVE-2021-44228" + preview = true + + ### Detect Level severity (0 to 3): 0 mean no rules enabled and 3 is the most sensitive + expression = "evaluatePreconfiguredWaf('cve-canary', {'sensitivity': 3})" + } + # https://cloud.google.com/armor/docs/rule-tuning#cves_and_other_vulnerabilities + rule_json_sqli = { + action = "deny(403)" + priority = "2001" + description = "JSON-formatted content SQLi" + preview = true + + ### Detect Level severity (0 to 2): 0 mean no rules enabled and 2 is the most sensitive + expression = "evaluatePreconfiguredWaf('json-sqli-canary', {'sensitivity': 2})" + } + } + type = map(object({ + action = string + priority = string + description = string + preview = bool + expression = string + }) + ) +} \ No newline at end of file