diff --git a/packer/README.md b/packer/README.md index 32a4018..8acbae2 100644 --- a/packer/README.md +++ b/packer/README.md @@ -28,13 +28,11 @@ What you need: 2. Move the downloaded service account key file to `./gcp.key.json` - > Note: if you want to use a different file name or location, change `account_file` in [`./main.pkr.hcl`](./main.pkr.hcl) accordingly - 3. Create a `variables.auto.pkrvars.hcl` file: -```bash -project = "" -``` + ```bash + project_id = "" + ``` ### Build the image diff --git a/packer/main.pkr.hcl b/packer/main.pkr.hcl index 941383b..d1e5534 100644 --- a/packer/main.pkr.hcl +++ b/packer/main.pkr.hcl @@ -12,7 +12,7 @@ source "googlecompute" "ubuntu-2204" { source_image_family = "ubuntu-pro-2204-lts" ssh_username = "root" zone = "europe-west3-c" - account_file = var.credentials + account_file = var.gcp_key_file machine_type = "e2-small" } diff --git a/packer/variables.pkr.hcl b/packer/variables.pkr.hcl index 910df88..a56f285 100644 --- a/packer/variables.pkr.hcl +++ b/packer/variables.pkr.hcl @@ -3,10 +3,12 @@ // For those variables that you don't provide a default for, you must // set them from the command line, a var-file, or the environment. -variable "credentials" { +variable "gcp_key_file" { type = string description = "Path to your GCP service account key file (JSON)" + default = "gcp.key.json" } + variable "project_id" { type = string description = "Your GCP project ID" diff --git a/terraform/README.md b/terraform/README.md index 1275300..b0508cf 100755 --- a/terraform/README.md +++ b/terraform/README.md @@ -11,13 +11,12 @@ Install Terraform as follows: 2. Install [Terraform CLI](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/gcp-get-started) 3. Create and download a GCP _service account key_ (in JSON) following [Terraform - Set Up GCP](https://learn.hashicorp.com/tutorials/terraform/google-cloud-platform-build?in=terraform/gcp-get-started).\ - Terraform will use it to manage your GCP resources. Move the key file to current folder as `./gcp-key.json` + Terraform will use it to manage your GCP resources. Move the key file to current folder as `./gcp.key.json` 4. Create a `terraform/terraform.tfvars` file with the following content ```bash - project = "" - credentials_file = "gcp.key.json" + project_id = "" ``` 5. Create an SSH key to run commands on created VM @@ -137,3 +136,12 @@ google_compute_instance.gateway_vm: Still creating... [5m10s elapsed] Possible solution: Remove `./deployer_key`, `./deployer_key.pub`, and regenerate them following this README. + +### Trouble: unset credentials +Sometimes `terraform apply` may fail due to corrupted `./credentials.txt`. + +Regenerate the credential file via +```bash +./generate_credentials.sh +``` +Then, `terraform destroy` and `terraform apply` again. diff --git a/terraform/grafana/provisioning/dashboards/containerSSH.json b/terraform/files/grafana/provisioning/dashboards/containerSSH.json similarity index 100% rename from terraform/grafana/provisioning/dashboards/containerSSH.json rename to terraform/files/grafana/provisioning/dashboards/containerSSH.json diff --git a/terraform/grafana/provisioning/dashboards/dashboard.yml b/terraform/files/grafana/provisioning/dashboards/dashboard.yml similarity index 100% rename from terraform/grafana/provisioning/dashboards/dashboard.yml rename to terraform/files/grafana/provisioning/dashboards/dashboard.yml diff --git a/terraform/grafana/provisioning/datasources/datasource.yml b/terraform/files/grafana/provisioning/datasources/datasource.yml similarity index 100% rename from terraform/grafana/provisioning/datasources/datasource.yml rename to terraform/files/grafana/provisioning/datasources/datasource.yml diff --git a/terraform/firewall_rules.tf b/terraform/firewall_rules.tf new file mode 100644 index 0000000..2f1ae2c --- /dev/null +++ b/terraform/firewall_rules.tf @@ -0,0 +1,98 @@ +resource "google_compute_firewall" "containerssh_allow_all" { + name = "containerssh-allow-all" + network = google_compute_network.main.self_link + + allow { + protocol = "icmp" + } + allow { + protocol = "udp" + ports = ["0-65535"] + } + allow { + protocol = "tcp" + ports = ["0-65535"] + } + source_ranges = ["0.0.0.0/0"] +} + +resource "google_compute_firewall" "containerssh_allow_ssh" { + name = "containerssh-allow-ssh" + network = google_compute_network.main.self_link + + allow { + protocol = "icmp" + } + + allow { + protocol = "tcp" + ports = ["22"] + } + + source_ranges = ["0.0.0.0/0"] +} + +# open port 3000 for Grafana, 9000 and 9090 for MinIO on our logger-vm +resource "google_compute_firewall" "firewall_logger_view" { + name = "firewall-logger-view" + network = google_compute_network.main.self_link + allow { + protocol = "tcp" + ports = ["3000", "9000", "9090"] + } + target_tags = ["observer"] + source_ranges = ["0.0.0.0/0"] +} + +# open gateway-port 9100 and 9101, to our prometheus and metrics server +resource "google_compute_firewall" "firewall_gateway_nodeexport" { + name = "firewall-gateway-nodeexport" + network = google_compute_network.main.self_link + + allow { + protocol = "tcp" + ports = ["8088", "9100", "9101"] + } + + target_tags = ["gateway"] + source_tags = ["observer"] +} + +# allow inbound connection on TCP port 2376 from gateway +resource "google_compute_firewall" "firewall_sacrificial_exception" { + name = "firewall-sacrificial-exception" + network = google_compute_network.main.name + priority = 500 + source_tags = ["gateway"] + target_tags = ["sacrificial"] + allow { + protocol = "tcp" + ports = ["2376"] + } +} + +# open sacrificial-port 8088 for cadvisor and 9100 for node-exporter +resource "google_compute_firewall" "firewall_sacrificial_nodeexport" { + name = "firewall-sacrificial-nodeexport" + network = google_compute_network.main.self_link + + allow { + protocol = "tcp" + ports = ["8088", "9100"] + } + + target_tags = ["sacrificial"] + source_tags = ["observer"] +} + +# close all outgoing connection from sacrificial host +resource "google_compute_firewall" "firewall_sacrificial_no_egress" { + name = "firewall-sacrificial-no-egress" + network = google_compute_network.main.name + direction = "EGRESS" + destination_ranges = ["0.0.0.0/0"] + target_tags = ["sacrificial"] + deny { + protocol = "all" + } +} diff --git a/terraform/instances.tf b/terraform/instances.tf new file mode 100644 index 0000000..b77f58e --- /dev/null +++ b/terraform/instances.tf @@ -0,0 +1,118 @@ +resource "google_compute_instance" "gateway_vm" { + name = "gateway-vm" + machine_type = var.machine_type + tags = ["gateway"] + + boot_disk { + initialize_params { + image = "ubuntu-with-docker-image" + size = 20 + type = "pd-balanced" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.gateway_subnet.self_link + network_ip = "10.0.0.10" + access_config { + + } + } + + connection { + type = "ssh" + user = "deployer" + private_key = file("./deployer_key") + host = google_compute_instance.gateway_vm.network_interface.0.access_config.0.nat_ip + } + + provisioner "file" { + source = "./files/config.yaml" + destination = "./config.yaml" + } + + provisioner "remote-exec" { + scripts = [ + "./scripts/run_cadvisor.sh" + ] + } +} + +resource "google_compute_instance" "sacrificial_vm" { + name = "sacrificial-vm" + machine_type = var.machine_type + tags = ["sacrificial"] + boot_disk { + initialize_params { + image = "sacrificial-vm-image" + size = 20 + type = "pd-balanced" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.honeypot_subnet.name + network_ip = "10.0.1.10" + access_config { + + } + } +} + +resource "google_compute_instance" "logger_vm" { + name = "logger-vm" + machine_type = var.machine_type + tags = ["observer"] + + boot_disk { + initialize_params { + image = "ubuntu-with-docker-image" + size = 200 + type = "pd-balanced" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.gateway_subnet.name + network_ip = "10.0.0.11" + access_config { + + } + } + + connection { + type = "ssh" + user = "deployer" + private_key = file("./deployer_key") + host = google_compute_instance.logger_vm.network_interface.0.access_config.0.nat_ip + } + + provisioner "local-exec" { + command = "./generate_credentials.sh" + interpreter = ["/bin/bash"] + } + + provisioner "file" { + source = "./credentials.txt" # relative to terraform work_dir + destination = "./.env" # relative to remote $HOME + } + + provisioner "file" { + source = "./files/prometheus.yml" # relative to terraform work_dir + destination = "./prometheus.yml" # relative to remote $HOME + } + + provisioner "file" { + source = "./files/grafana" # relative to terraform work_dir + destination = "./" # relative to remote $HOME + } + + provisioner "remote-exec" { + scripts = [ + "./scripts/run_cadvisor.sh", + "./scripts/run_minio.sh", + "./scripts/run_prometheus.sh", + "./scripts/run_grafana.sh" + ] + } +} diff --git a/terraform/main.tf b/terraform/main.tf index 2ff946e..cb872d2 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,9 +1,18 @@ +terraform { + required_providers { + google = { + source = "google" + version = "4.20.0" + } + } +} + provider "google" { - project = var.project + project = var.project_id region = "europe-west3" zone = "europe-west3-c" - credentials = file(var.credentials) + credentials = file(var.gcp_key_file) } resource "google_compute_network" "main" { @@ -23,224 +32,6 @@ resource "google_compute_subnetwork" "honeypot_subnet" { network = google_compute_network.main.self_link } -resource "google_compute_firewall" "containerssh_allow_all" { - name = "containerssh-allow-all" - network = google_compute_network.main.self_link - - allow { - protocol = "icmp" - } - allow { - protocol = "udp" - ports = ["0-65535"] - } - allow { - protocol = "tcp" - ports = ["0-65535"] - } - source_ranges = ["0.0.0.0/0"] -} - -resource "google_compute_firewall" "containerssh_allow_ssh" { - name = "containerssh-allow-ssh" - network = google_compute_network.main.self_link - - allow { - protocol = "icmp" - } - - allow { - protocol = "tcp" - ports = ["22"] - } - - source_ranges = ["0.0.0.0/0"] -} - -# open port 3000 for Grafana, 9000 and 9090 for MinIO on our logger-vm -resource "google_compute_firewall" "firewall_logger_view" { - name = "firewall-logger-view" - network = google_compute_network.main.self_link - allow { - protocol = "tcp" - ports = ["3000", "9000", "9090"] - } - target_tags = ["observer"] - source_ranges = ["0.0.0.0/0"] -} - -# open gateway-port 9100 and 9101, to our prometheus and metrics server -resource "google_compute_firewall" "firewall_gateway_nodeexport" { - name = "firewall-gateway-nodeexport" - network = google_compute_network.main.self_link - - allow { - protocol = "tcp" - ports = ["8088", "9100", "9101"] - } - - target_tags = ["gateway"] - source_tags = ["observer"] -} - -# allow inbound connection on TCP port 2376 from gateway -resource "google_compute_firewall" "firewall_sacrificial_exception" { - name = "firewall-sacrificial-exception" - network = google_compute_network.main.name - priority = 500 - source_tags = ["gateway"] - target_tags = ["sacrificial"] - allow { - protocol = "tcp" - ports = ["2376"] - } -} - -# open sacrificial-port 8088 for cadvisor and 9100 for node-exporter -resource "google_compute_firewall" "firewall_sacrificial_nodeexport" { - name = "firewall-sacrificial-nodeexport" - network = google_compute_network.main.self_link - - allow { - protocol = "tcp" - ports = ["8088", "9100"] - } - - target_tags = ["sacrificial"] - source_tags = ["observer"] -} - -# close all outgoing connection from sacrificial host -resource "google_compute_firewall" "firewall_sacrificial_no_egress" { - name = "firewall-sacrificial-no-egress" - network = google_compute_network.main.name - direction = "EGRESS" - destination_ranges = ["0.0.0.0/0"] - target_tags = ["sacrificial"] - deny { - protocol = "all" - } -} - -resource "google_compute_instance" "gateway_vm" { - name = "gateway-vm" - machine_type = var.machine_type - tags = ["gateway"] - - boot_disk { - initialize_params { - image = "ubuntu-with-docker-image" - size = 20 - type = "pd-balanced" - } - } - - network_interface { - subnetwork = google_compute_subnetwork.gateway_subnet.self_link - network_ip = "10.0.0.10" - access_config { - - } - } - - connection { - type = "ssh" - user = "deployer" - private_key = file("./deployer_key") - host = google_compute_instance.gateway_vm.network_interface.0.access_config.0.nat_ip - } - - provisioner "file" { - source = "./files/config.yaml" - destination = "./config.yaml" - } - - provisioner "remote-exec" { - scripts = [ - "./scripts/run_cadvisor.sh" - ] - } -} - -resource "google_compute_instance" "sacrificial_vm" { - name = "sacrificial-vm" - machine_type = var.machine_type - tags = ["sacrificial"] - boot_disk { - initialize_params { - image = "sacrificial-vm-image" - size = 20 - type = "pd-balanced" - } - } - - network_interface { - subnetwork = google_compute_subnetwork.honeypot_subnet.name - network_ip = "10.0.1.10" - access_config { - - } - } -} - -resource "google_compute_instance" "logger_vm" { - name = "logger-vm" - machine_type = var.machine_type - tags = ["observer"] - - boot_disk { - initialize_params { - image = "ubuntu-with-docker-image" - size = 200 - type = "pd-balanced" - } - } - - network_interface { - subnetwork = google_compute_subnetwork.gateway_subnet.name - network_ip = "10.0.0.11" - access_config { - - } - } - - connection { - type = "ssh" - user = "deployer" - private_key = file("./deployer_key") - host = google_compute_instance.logger_vm.network_interface.0.access_config.0.nat_ip - } - - provisioner "local-exec" { - command = "./generate_credentials.sh" - interpreter = ["/bin/bash"] - } - - provisioner "file" { - source = "./credentials.txt" # relative to terraform work_dir - destination = "./.env" # relative to remote $HOME - } - - provisioner "file" { - source = "./files/prometheus.yml" # relative to terraform work_dir - destination = "./prometheus.yml" # relative to remote $HOME - } - - provisioner "file" { - source = "./grafana" # relative to terraform work_dir - destination = "./" # relative to remote $HOME - } - - provisioner "remote-exec" { - scripts = [ - "./scripts/run_cadvisor.sh", - "./scripts/run_minio.sh", - "./scripts/run_prometheus.sh", - "./scripts/run_grafana.sh" - ] - } -} - # Note: provisioner in this block only runs after all previous provisioners are finished resource "null_resource" "set_up_docker_tls_and_containerssh" { # 1. Create CA and client keys; Set up Docker TLS on Sacrificial VM diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..121bf22 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,16 @@ +output "vm_ip_addresses" { + description = "VM external IP address" + value = { + "gateway_vm_ip" = google_compute_instance.gateway_vm.network_interface.0.access_config.0.nat_ip + "sacrificial_vm_ip" = google_compute_instance.sacrificial_vm.network_interface.0.access_config.0.nat_ip + "logger_vm_ip" = google_compute_instance.logger_vm.network_interface.0.access_config.0.nat_ip + } +} + +output "grafana" { + value = "http://${google_compute_instance.logger_vm.network_interface.0.access_config.0.nat_ip}:3000/" +} + +output "minio_console" { + value = "http://${google_compute_instance.logger_vm.network_interface.0.access_config.0.nat_ip}:9090/" +} diff --git a/terraform/terraform.tf b/terraform/terraform.tf deleted file mode 100644 index eee1021..0000000 --- a/terraform/terraform.tf +++ /dev/null @@ -1,8 +0,0 @@ -terraform { - required_providers { - google = { - source = "google" - version = "4.20.0" - } - } -} diff --git a/terraform/variables.tf b/terraform/variables.tf index c080416..3e3e96d 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -1,11 +1,12 @@ -variable "project" { +variable "project_id" { type = string description = "Your GCP project ID" } -variable "credentials" { +variable "gcp_key_file" { type = string description = "Path to your GCP service account key file (JSON)" + default = "gcp.key.json" } variable "machine_type" {