diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48c784d --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# ---> Terraform +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which are likely to contain sentitive 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. +# +*secret*.tfvars + +# 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 +*tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +tfplan_dl diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000..b16a819 --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,46 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hetznercloud/hcloud" { + version = "1.35.2" + constraints = "1.35.2" + hashes = [ + "h1:a/DH+2jHvgikSDajup5feRZRUwNw8OT9NBPKezjgM5g=", + "zh:1a7cb8f9cbd51b62bdbb4f36cdb070dd99059d86115c4777193e0f8536798d4d", + "zh:29c104aae7f7a4e1a4aea32febc9caa2d7d86589cd9d01d5b93dbe2cb0a73220", + "zh:29f082195d8f4e4cfb4050fae2ed62ed5616659c6dfaa7b5f1eb42d94d130864", + "zh:3cfe3876763659e27696adcb945e6da2dc2ec014ff8a2e8f0f3e610e3bfd9b73", + "zh:3d967f4b1aef78ffce389dd32cdea4b558ef826cec96ceb4bdafde4bb4a9b655", + "zh:3e160f581f7912c2053f86d6d8a3e3470fcf1fe8228b59ac216a7e40a1dd444c", + "zh:5138022c8b4c8a572e8097749241d929a96d3522e67ce25f86bb9fd51c4b343c", + "zh:5783febc4d8ac4b7fdb49607cab92ad13509d87ad4ca1999067ac3d20e815d12", + "zh:7f8ce9268d48beb5fa0103a8510d4fe644aaac6cd328fc4441dd37e8bdbfadab", + "zh:8ab6aea82657fd6f97d79b41e6cd129a33a47ce727a7d0b52205590fa3785ce1", + "zh:9e4bebe3bbee7875dc2e3ceca3cf0fec3254a8b481c7b96ba9a5d65647ea9092", + "zh:af2a912db9a6fce844ac8c0e695a5d92a5625f2df126129940051a6b1021443d", + "zh:bfe86d80e55f44a99dbbdca9d1caf0c837fe21d91e78674ee36263b7de71fd38", + "zh:d9538a361bd8979c4a87273a82fc5dec7110f3aa7ec69fffb8c70fe8937bc1f4", + ] +} + +provider "registry.terraform.io/ionos-developer/ionosdeveloper" { + version = "0.0.1" + constraints = ">= 0.0.1" + hashes = [ + "h1:EsbYrlAajO0JuWTtDmY5srsWm8TWOEtM+VfliBgSmag=", + "zh:04dc3d964dac33d1ff16e5893517c8b724cc0726bb93cb7bcd95eca25bb028fa", + "zh:090e552495d6766b26380a49c2bea4fdd898f0de641792b646bfc9e844ae5ab7", + "zh:0fe5eb23d65c42792d51ea55dce1f00ef1dd0ecba710827efd9218369dba6463", + "zh:1f71e1db13d3d6dfc09d6e95f8232ce23c78c72d126db23499f22c529496a744", + "zh:557325b7766cbc4ccbc0fee36469ecc0c96fb3bc7cf75036289161444906cb63", + "zh:7cbb553d04fa5cb53fd13e3684709712fde9ef5be0dca8e2eca8d27c8cda6bb1", + "zh:9fed4131682204eb4e1a4d05000192a904d3645305c52d05d8fac5e3f264a1f6", + "zh:b1cfb981617a3b276fbd95d60831e6f8a3207e806acb0dfa48f3d880694ecfe7", + "zh:b32a84063690cf3cf7c72b63051dc51d3da9697d355f100bb51ef4c766e14b04", + "zh:b3eea4f8cbd8a452f0688f0839009387ade879be768ea378dfc61937657cea00", + "zh:b865969d0ad218f96716c96128545afe11974717ec48a8dfb4b22f21c439c25e", + "zh:d1c06c76da4ad5f3589b0361fcb8cf563d651fe6e7261828d2d8e36a9b1bc727", + "zh:e60a2ad003970d038ac9bae82a7983315e186e22d51b78c52301a4fa7ccd3655", + "zh:f0544e6b18b2af7b0d2a567d33f304df9a9961a94f2692c7af91aef4f2b785df", + ] +} diff --git a/cloud.userdata b/cloud.userdata new file mode 100644 index 0000000..c7e74dd --- /dev/null +++ b/cloud.userdata @@ -0,0 +1,19 @@ +#cloud-config +users: + - name: oli + primary_group: oli + groups: sudo + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpczZfQ5MrfjSYz8MnDHG4sM2cQ8cIsj3ALDGtmW3zu + +package_update: true +package_upgrade: true + +runcmd: + - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config + - sed -i -e '/^PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config + - sed -i -e '/^X11Forwarding/s/^.*$/X11Forwarding no/' /etc/ssh/sshd_config + - sed -i -e '/^#MaxAuthTries/s/^.*$/MaxAuthTries 3/' /etc/ssh/sshd_config + - systemctl restart sshd.service diff --git a/dns.tf b/dns.tf new file mode 100644 index 0000000..384e1c4 --- /dev/null +++ b/dns.tf @@ -0,0 +1,21 @@ +# IONOS DNS + +data "ionosdeveloper_dns_zone" "selected" { + name = "twirling.de" +} + +resource "ionosdeveloper_dns_record" "main_ipv4" { + zone_id = data.ionosdeveloper_dns_zone.selected.id + name = "cloud.${data.ionosdeveloper_dns_zone.selected.name}" + type = "A" + content = hcloud_primary_ip.main_ipv4.ip_address + ttl = 3600 +} + +resource "ionosdeveloper_dns_record" "main_ipv6" { + zone_id = data.ionosdeveloper_dns_zone.selected.id + name = "cloud.${data.ionosdeveloper_dns_zone.selected.name}" + type = "AAAA" + content = hcloud_primary_ip.main_ipv6.ip_address + ttl = 3600 +} \ No newline at end of file diff --git a/firewall.tf b/firewall.tf new file mode 100644 index 0000000..5e8d56d --- /dev/null +++ b/firewall.tf @@ -0,0 +1,32 @@ +# Hetzner Cloud Firewall + +resource "hcloud_firewall" "icmp" { + name = "ICMP" + rule { + direction = "in" + protocol = "icmp" + source_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + apply_to { + label_selector = "env=prod" + } +} + +resource "hcloud_firewall" "ssh" { + name = "SSH" + rule { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = [ + var.ows_gateway.ipv4, + var.ows_gateway.ipv6 + ] + } + apply_to { + label_selector = "env=prod" + } +} diff --git a/instances.tf b/instances.tf new file mode 100644 index 0000000..5b9ccbc --- /dev/null +++ b/instances.tf @@ -0,0 +1,93 @@ +# Create a new SSH key in cloud console +resource "hcloud_ssh_key" "default" { + name = "terraform-ansible" + public_key = var.dtsv_hcloud_ssh_key +} + +# Hetzner Primary IP + +resource "hcloud_primary_ip" "main_ipv4" { + name = "primary_ipv4_web" + datacenter = "fsn1-dc14" + type = "ipv4" + assignee_type = "server" + auto_delete = false + labels = { + "mapping" : "WEB" + } +} + +resource "hcloud_primary_ip" "main_ipv6" { + name = "primary_ipv6_web" + datacenter = "fsn1-dc14" + type = "ipv6" + assignee_type = "server" + auto_delete = false + labels = { + "mapping" : "WEB" + } +} + +# Hetzner Cloud Servers + +resource "hcloud_server" "web" { + name = "WEB" + server_type = "cpx21" + image = "ubuntu-22.04" + datacenter = "fsn1-dc14" + ssh_keys = [hcloud_ssh_key.default.id] + user_data = file("cloud.userdata") + labels = { + "env" : "prod" + } + + network { + network_id = hcloud_network.vpc.id + ip = "10.0.0.2" + } + + public_net { + ipv4_enabled = true + ipv4 = hcloud_primary_ip.main_ipv4.id + ipv6_enabled = true + ipv6 = hcloud_primary_ip.main_ipv6.id + } + + # **Note**: the depends_on is important when directly attaching the + # server to a network. Otherwise Terraform will attempt to create + # server and sub-network in parallel. This may result in the server + # creation failing randomly. + depends_on = [ + hcloud_network_subnet.subnet + ] +} + +resource "hcloud_server" "db" { + name = "DB" + server_type = "cpx11" + image = "ubuntu-22.04" + datacenter = "fsn1-dc14" + ssh_keys = [hcloud_ssh_key.default.id] + user_data = file("cloud.userdata") + labels = { + "env" : "prod" + } + + network { + network_id = hcloud_network.vpc.id + ip = "10.0.0.3" + } + + public_net { + ipv4_enabled = true + ipv6_enabled = true + } + + # **Note**: the depends_on is important when directly attaching the + # server to a network. Otherwise Terraform will attempt to create + # server and sub-network in parallel. This may result in the server + # creation failing randomly. + depends_on = [ + hcloud_network_subnet.subnet + ] +} \ No newline at end of file diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..51e66c5 --- /dev/null +++ b/main.tf @@ -0,0 +1,34 @@ +# Providers +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + version = "1.35.2" + } + ionosdeveloper = { + source = "ionos-developer/ionosdeveloper" + version = ">= 0.0.1" + } + } +} + +# Set the variable value in *.tfvars file +# or using the -var="hcloud_token=..." CLI option +# or get from env variable (export = abc132) + +# Hetzner Cloud +variable "dtsv_hcloud_token" {} +# Configure the Hetzner Cloud Provider +provider "hcloud" { + token = var.dtsv_hcloud_token +} + +# Ionos Cloud +variable "dtsv_ionos_token" {} +# Configure the Ionos Developer Provider +provider "ionosdeveloper" { + api_key = var.dtsv_ionos_token +} + +# Public SSH Key +variable "dtsv_hcloud_ssh_key" {} diff --git a/network.tf b/network.tf new file mode 100644 index 0000000..321b2c4 --- /dev/null +++ b/network.tf @@ -0,0 +1,13 @@ +# Hetzner Cloud Networks + +resource "hcloud_network" "vpc" { + name = "VPC" + ip_range = "10.0.0.0/24" +} + +resource "hcloud_network_subnet" "subnet" { + type = "cloud" + network_id = hcloud_network.vpc.id + network_zone = "eu-central" + ip_range = "10.0.0.0/24" +} \ No newline at end of file diff --git a/volume.tf b/volume.tf new file mode 100644 index 0000000..44232b5 --- /dev/null +++ b/volume.tf @@ -0,0 +1,19 @@ +# Hetzner Cloud Volume + +resource "hcloud_volume" "web" { + name = "WEB" + location = "fsn1" + size = 10 + format = "ext4" + delete_protection = true + labels = { + "env" : "prod" + "attachment" : "WEB" + } +} + +resource "hcloud_volume_attachment" "volume_attachment_web" { + volume_id = hcloud_volume.web.id + server_id = hcloud_server.web.id + automount = false +} \ No newline at end of file