From 89a3f6e47b59c91f5ce3eac0f03cae9bf0f5b308 Mon Sep 17 00:00:00 2001 From: Patrick de Ruiter Date: Sat, 25 May 2024 05:32:38 +0200 Subject: [PATCH] Initial commit --- .gitignore | 34 +++++++ .terraform.lock.hcl | 44 +++++++++ README.md | 8 ++ backend.tf | 16 ++++ data.tf | 3 + files/limiter.toml | 6 ++ files/settings.yml | 33 +++++++ main.tf | 224 ++++++++++++++++++++++++++++++++++++++++++++ outputs.tf | 7 ++ provider.tf | 33 +++++++ variables.tf | 24 +++++ 11 files changed, 432 insertions(+) create mode 100644 .gitignore create mode 100644 .terraform.lock.hcl create mode 100644 README.md create mode 100644 backend.tf create mode 100644 data.tf create mode 100644 files/limiter.toml create mode 100644 files/settings.yml create mode 100644 main.tf create mode 100644 outputs.tf create mode 100644 provider.tf create mode 100644 variables.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6304eb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000..1c9f92c --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/abh80/docker" { + version = "1.0.1" + constraints = "1.0.1" + hashes = [ + "h1:cmotTmVc4w+Q5+pqjxx/HqHoDmhWcqIzCGPmPmyYUgs=", + "zh:111e17287b583f0ea4f9348e43d6451bec62178d99399c1273ce9c6b0e73b20e", + "zh:35e09001d2dbdd27519bd9d0987f8350fde9ffb78cfac83ae01a6c2e5e5120f6", + "zh:418c0930c8a2719184686ae27091dcaac0b05c554062dad87691772e257afd19", + "zh:5ea943d639daf72f5fe9a26a5ae9541527ea093f96ef261a130eecf14313ef0a", + "zh:7bd5bfca33ef7449313645b52f044ee970b0b929fed5b8d5bea3f0c971d85002", + "zh:7ea67b58146270acaea2f3d61ba72c5d4c28083208ac3a77f5be81f7910e0ceb", + "zh:830b24cc5328931c2796128647bbfcc44e7238461399f78b7f8e6376c431477b", + "zh:c51bd68a6c56f734baea5352d98c41815ac98916ad5c7760938af0c9d930414a", + "zh:d4b92841056fbcfdafc8d42d186a7e2e7bb3e1e8e2248012f92653b232ad8156", + "zh:e542b3e076da9d4d8325ff5bbd7bf2d58ef0b95ee9607b23fc4b2e26890313b2", + "zh:e803b0ef43d44b9a510b360663df9f2bc7bbc4f3a3b9e61ab5a98832367f5e29", + "zh:eaf409305294569b696c33d3778b73c41f8fe4dfbb812a6b87ddce9154d64af0", + "zh:f2555a9a387064a54b28123026f8d938e55266e944fbd4c3ca1e805b5b3009f7", + "zh:f747ca9d07c45711c94ac30dac2bc71cfe53d4c53b9a3b5a813bcf8b0fb3e7f2", + ] +} + +provider "registry.terraform.io/hashicorp/vault" { + version = "3.25.0" + constraints = "3.25.0" + hashes = [ + "h1:3GN5k6zxDAI5gfcKENb/jnJyFGWA/0JoumnD6eyVZjs=", + "zh:430308f5dbd322a2e5afafd2be810f44eb35e28afa0aa0ac30b270cd6f413da8", + "zh:6c36da504c4af84ea9fbaf1e6c2560f691dc3d2d7f0b382a937bfae78830fa17", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7bc39cb2a7d91631cb8be54b0b06de29fb47910923e54f779e74d8b218b1ab70", + "zh:7e4a5bebcfa19b9f1e3a6bbda5c6771b6dd28b3dfa19fdf3d4fced419cfa416f", + "zh:7ea473203b37d006a0d2b1cdc8bff55c96b3c5819dbb62862cdabff6f2f0e2f2", + "zh:9ad136feece62f0c545fefa4592b2cdaa896a39acb697fb129233dce880a69aa", + "zh:ad0c9980295c902804af23da0250830b912eb13089349bf5c7be0649fac2689c", + "zh:b305835cc13dcd9ec996d49d23163c6311f30786296f86ca5657b93aea4f3591", + "zh:d8fe6ab7da12efbb5b122ae9b6856375c5a3759add9df577a8fb448898ceffe3", + "zh:ef59ef2c06a55571e64fdd5888a074ed9556436738e9737e32bacab93ca133ff", + "zh:f59c2605d916e1806dc494241467dd430194f5e7bdbf331c5aca904873347ad8", + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..49bfb61 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Terraform Docker SearXNG Module + +This Terraform module deploys a SearXNG private search engine instance using Docker. + +## Usage + +```hcl +``` diff --git a/backend.tf b/backend.tf new file mode 100644 index 0000000..82c56cc --- /dev/null +++ b/backend.tf @@ -0,0 +1,16 @@ +terraform { + backend "s3" { + bucket = "terraformstate-vsphere" + endpoint = "https://wbyc-srv-minio01.bsdserver.lan:9000" + key = "home/docker/searxng/servers.tfstate" + + access_key = "terraform" + secret_key = "Drj3nD!!" + + region = "main" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + force_path_style = true + } +} diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..d24c475 --- /dev/null +++ b/data.tf @@ -0,0 +1,3 @@ +#data "vault_generic_secret" "searxng" { +# path = "secret/searxng" +#} diff --git a/files/limiter.toml b/files/limiter.toml new file mode 100644 index 0000000..c7bfbfb --- /dev/null +++ b/files/limiter.toml @@ -0,0 +1,6 @@ +# This configuration file updates the default configuration file +# See https://github.com/searxng/searxng/blob/master/searx/botdetection/limiter.toml + +[botdetection.ip_limit] +# activate link_token method in the ip_limit method +link_token = true diff --git a/files/settings.yml b/files/settings.yml new file mode 100644 index 0000000..b9ca0c0 --- /dev/null +++ b/files/settings.yml @@ -0,0 +1,33 @@ +# see https://docs.searxng.org/admin/settings/settings.html#settings-use-default-settings +use_default_settings: true +server: + # base_url is defined in the SEARXNG_BASE_URL environment variable, see .env and docker-compose.yml + secret_key: "9fd0439f0fc5c38dc3d6c433d5ec98b98234aa93c30f4136a117574da7bdea13" + limiter: true # can be disabled for a private instance + image_proxy: true +ui: + static_use_hash: true +redis: + url: redis://redis:6379/0 + +proxies: + http: socks5h://searxng-tor:9050 + https: socks5h://searxng-tor:9050 + +search: + engines: + duckduckgo_onion: + proxy: true + categories: general + base_url: "https://3g2upl4pq6kufc4m.onion" + name: DuckDuckGo (onion) + + torch_onion: + name: Torch (onion) + base_url: "https://xmh57jrzrnw6insl.onion" + search_url: "https://xmh57jrzrnw6insl.onioni/search?q={query}" + method: GET + parsing_engine: xpath + xpath: "//h3/a[@href]" + proxy: true + categories: general diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..7a39deb --- /dev/null +++ b/main.tf @@ -0,0 +1,224 @@ +# Description: This file contains the main Terraform configuration for the SonarQube Docker container configuration. + +# Define the local variables +locals { + app_name = "searxng" + app_version = "latest" + app_src_port = "8080" + app_dst_port = "8080" + db_type = "redis" + db_version = "alpine" + db_src_port = "6379" + db_dst_port = "6379" +} + +# Get the ID of the traefik_network +data "docker_network" "traefik_network" { + name = "traefik_network" +} + +# Create Docker volumes dynamically based on service_volumes variable +resource "docker_volume" "service_volume" { + for_each = toset(flatten([ + for svc, cfg in var.service_volumes : [ + for vol_name, _ in cfg.volumes : vol_name + ] + ])) + name = each.value +} + +# Create Docker images dynamically based on service_images variable +resource "docker_image" "database" { + name = "docker.io/library/${local.db_type}:${local.db_version}" +} + +# Create Docker images dynamically based on service_images variable +resource "docker_image" "application" { + name = "docker.io/${local.app_name}/${local.app_name}:${local.app_version}" +} + +# Create Docker images dynamically based on service_images variable +resource "docker_image" "tor" { + name = "docker.io/shinomineko/torproxy:latest" +} + +resource "docker_container" "tor" { + image = docker_image.tor.image_id + name = "${local.app_name}-tor" + hostname = "${local.app_name}-tor" + command = [ + "--Log", "notice stdout", + "--RunAsDaemon", "0", + "--SocksPort", "0.0.0.0:9050" + ] + + networks_advanced { + name = data.docker_network.traefik_network.name + } + + #ports { + # internal = 9050 + # external = 9050 + #} + + env = [ + "ALLOW_UNKNOWN=true", + "SOCKS_PORT=9050" + ] +} + +# Create Docker containers dynamically based on service_volumes variable +resource "docker_container" "db" { + image = docker_image.database.image_id + name = "${local.app_name}-${local.db_type}-db" + hostname = "${local.app_name}-db" + command = ["--save", "30", "1", "--loglevel", "warning"] + + networks_advanced { + name = data.docker_network.traefik_network.name + } + + dynamic "volumes" { + for_each = var.service_volumes["database"].volumes + iterator = volume + content { + volume_name = docker_volume.service_volume[volume.key].name + container_path = volume.value + } + } + + restart = "always" + capabilities { + drop = ["ALL"] + add = ["SETGID", "SETUID", "DAC_OVERRIDE"] + } + + #logging { + # driver = "json-file" + # options = { + # "max-size" = "1m" + # "max-file" = "1" + # } + #} +} + +# Create Docker containers dynamically based on service_volumes variable +resource "docker_container" "application" { + image = docker_image.application.image_id + name = local.app_name + hostname = local.app_name + networks_advanced { + name = data.docker_network.traefik_network.name + } + env = [ + "SEARXNG_BASE_URL=https://search.bsdserver.nl/", + ] + + dynamic "volumes" { + for_each = var.service_volumes["application"].volumes + iterator = volume + content { + volume_name = docker_volume.service_volume[volume.key].name + container_path = volume.value + } + } + + capabilities { + drop = ["ALL"] + add = ["CHOWN", "SETGID", "SETUID"] + } + + #logging { + # driver = "json-file" + # options = { + # "max-size" = "1m" + # "max-file" = "1" + # } + #} + + upload { + content = file("${path.module}/files/settings.yml") + file = "/etc/searxng/settings.yml" + } + + upload { + content = file("${path.module}/files/limiter.toml") + file = "/etc/searxng/limiter.toml" + } + + labels { + label = "traefik.enable" + value = "true" + } + + labels { + label = "traefik.http.routers.searxng.entrypoints" + value = "websecure" + } + + labels { + label = "traefik.http.routers.searxng.rule" + value = "Host(`search.bsdserver.nl`)" + } + + labels { + label = "traefik.http.services.searxng.loadBalancer.server.port" + value = 8080 + } + + labels { + label = "traefik.http.routers.searxng.tls" + value = "true" + } + + labels { + label = "traefik.http.routers.searxng.tls.certresolver" + value = "production" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.Strict-Transport-Security" + value = "max-age=31536000; includeSubDomains; preload" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.X-XSS-Protection" + value = "1; mode=block" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.X-Content-Type-Options" + value = "nosniff" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.Permissions-Policy" + value = "accelerometer=(),ambient-light-sensor=(),autoplay=(),camera=(),encrypted-media=(),focus-without-user-activation=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),speaker=(),sync-xhr=(),usb=(),vr=()" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.Referrer-Policy" + value = "no-referrer" + } + + labels { + label = "traefik.http.middlewares.searxng-headers.headers.customresponseheaders.X-Robots-Tag" + value = "noindex, noarchive, nofollow" + } + + labels { + label = "traefik.http.routers.searxng.middlewares" + value = "searxng-headers" + } + + ##labels { + ## label = "traefik.http.routers.searxng.middlewares" + ## value = "forward-auth" + ##} + + restart = "always" + + depends_on = [ + docker_container.db + ] +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..a78a55c --- /dev/null +++ b/outputs.tf @@ -0,0 +1,7 @@ +# Purpose: This file is used to output the values of the resources created in the main.tf file. + +# The output "searxng" block outputs the value of the password from the SearXNG secret in Vault. +#output "searxng" { +# value = data.vault_generic_secret.searxng.data ["admin_password"] +# sensitive = true +#} diff --git a/provider.tf b/provider.tf new file mode 100644 index 0000000..4927e00 --- /dev/null +++ b/provider.tf @@ -0,0 +1,33 @@ +# Description: This file is used to configure the Docker and Vault providers. +terraform { + required_providers { + docker = { + source = "abh80/docker" + version = "1.0.1" + } + + vault = { + source = "hashicorp/vault" + version = "3.25.0" + } + } +} + +# Configure the Docker provider +provider "docker" { + host = "tcp://192.168.2.170:2376" + + cert_path = pathexpand("~/.docker") +} + +# Configure the Vault provider +provider "vault" { + address = "https://wbyc-srv-docker01.bsdserver.lan:8200" + auth_login { + path = "auth/approle/login" + parameters = { + role_id = var.role_id + secret_id = var.secret_id + } + } +} \ No newline at end of file diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..645fcdc --- /dev/null +++ b/variables.tf @@ -0,0 +1,24 @@ +variable "service_volumes" { + description = "Mapping of service names to their volume names and mount points" + type = map(object({ + volumes = map(string) + })) +} + +variable "domain" { + description = "Domain name for the application" + type = string + default = "bsdserver.lan" +} + +variable "role_id" { + description = "Role ID for Vault AppRole authentication" + type = string + sensitive = true +} + +variable "secret_id" { + description = "Secret ID for Vault AppRole authentication" + type = string + sensitive = true +} \ No newline at end of file