feat: refactor, deploy and provisioning
This commit is contained in:
parent
a9639a9340
commit
31bed3964b
13 changed files with 404 additions and 205 deletions
25
install.sh
25
install.sh
|
@ -1,6 +1,21 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
##
|
||||||
|
# Source Code
|
||||||
|
|
||||||
|
# We store all initial configs in the /srv location
|
||||||
|
cd /srv
|
||||||
|
|
||||||
|
# Clone if not yet cloned
|
||||||
|
if [ ! -d .git ]; then
|
||||||
|
git clone https://code.tjo.space/tjo-cloud/ingress.git .
|
||||||
|
else
|
||||||
|
git pull
|
||||||
|
fi
|
||||||
|
|
||||||
|
##
|
||||||
|
# Metadata
|
||||||
SERVICE_NAME="ingress.tjo.cloud"
|
SERVICE_NAME="ingress.tjo.cloud"
|
||||||
SERVICE_VERSION="$(git describe --tags --always --dirty)"
|
SERVICE_VERSION="$(git describe --tags --always --dirty)"
|
||||||
CLOUD_REGION="$(hostname -s)"
|
CLOUD_REGION="$(hostname -s)"
|
||||||
|
@ -26,11 +41,11 @@ mkdir -p /etc/apt/keyrings/
|
||||||
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg >/dev/null
|
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg >/dev/null
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | tee /etc/apt/sources.list.d/grafana.list
|
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | tee /etc/apt/sources.list.d/grafana.list
|
||||||
apt update -y
|
apt update -y
|
||||||
apt get install -y alloy
|
apt install -y alloy
|
||||||
|
|
||||||
##
|
##
|
||||||
# Copy Sysmtemd service/units
|
# Copy Sysmtemd service/units
|
||||||
cp -r root/etc/systemd/* /
|
#cp -r root/etc/systemd/* /
|
||||||
|
|
||||||
##
|
##
|
||||||
# Ensure services are enabled
|
# Ensure services are enabled
|
||||||
|
@ -55,10 +70,10 @@ systemctl reload alloy
|
||||||
|
|
||||||
##
|
##
|
||||||
# Configure NGINX
|
# Configure NGINX
|
||||||
cp -r root/etc/nginx/* /etc/nginx/
|
#cp -r root/etc/nginx/* /etc/nginx/
|
||||||
systemctl reload nginx
|
systemctl reload nginx
|
||||||
|
|
||||||
##
|
##
|
||||||
# Configure Webhook
|
# Configure Webhook
|
||||||
cp -r root/etc/webhook/* /etc/webhook/
|
#cp -r root/etc/webhook/* /etc/webhook/
|
||||||
systemctl reload webhook
|
systemctl restart webhook
|
||||||
|
|
46
justfile
46
justfile
|
@ -10,6 +10,10 @@ lint:
|
||||||
@tofu fmt -check -recursive .
|
@tofu fmt -check -recursive .
|
||||||
@tflint --recursive
|
@tflint --recursive
|
||||||
|
|
||||||
|
format:
|
||||||
|
@tofu fmt -recursive .
|
||||||
|
@tflint --recursive
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
cd {{justfile_directory()}}/terraform
|
cd {{justfile_directory()}}/terraform
|
||||||
|
@ -20,3 +24,45 @@ destroy:
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
cd {{justfile_directory()}}/terraform
|
cd {{justfile_directory()}}/terraform
|
||||||
tofu destroy
|
tofu destroy
|
||||||
|
|
||||||
|
# Create a list of blocked IP ranges. Traffic we don't want.
|
||||||
|
ingress-blocked-list:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
GOOGLE_BOT_IPV4=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/googlebot/ipv4_merged.txt)
|
||||||
|
GOOGLE_BOT_IPV6=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/googlebot/ipv6_merged.txt)
|
||||||
|
echo "# GOOGLE_BOT IPV4 $(echo $GOOGLE_BOT_IPV4 | wc -w)"
|
||||||
|
echo "# GOOGLE_BOT IPV6 $(echo $GOOGLE_BOT_IPV6 | wc -w)"
|
||||||
|
|
||||||
|
BING_BOT_IPV4=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/bing/ipv4_merged.txt)
|
||||||
|
echo "# BING_BOT IPV4 $(echo $BING_BOT_IPV4 | wc -w)"
|
||||||
|
|
||||||
|
OPENAI_IPV4=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/openai/ipv4_merged.txt)
|
||||||
|
echo "# OPENAI IPV4 $(echo $OPENAI_IPV4 | wc -w)"
|
||||||
|
|
||||||
|
FACEBOOK_IPV4=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/facebook/ipv4_merged.txt)
|
||||||
|
FACEBOOK_IPV6=$(curl -s https://raw.githubusercontent.com/lord-alfred/ipranges/main/facebook/ipv6_merged.txt)
|
||||||
|
echo "# FACEBOOK IPV4 $(echo $FACEBOOK_IPV4 | wc -w)"
|
||||||
|
echo "# FACEBOOK IPV6 $(echo $FACEBOOK_IPV6 | wc -w)"
|
||||||
|
|
||||||
|
IP_RANGES=$(echo -e "$GOOGLE_BOT_IPV4\n$GOOGLE_BOT_IPV6\n$BING_BOT_IPV4\n$BING_BOT_IPV6\n$OPENAI_IPV4\n$FACEBOOK_IPV4\n$FACEBOOK_IPV6" | sort | uniq)
|
||||||
|
echo "#!!DO NOT EDIT!! Generated by using just ingress-blocked-list command." > root/etc/nginx/partials/blocked.conf
|
||||||
|
for ip in $IP_RANGES; do
|
||||||
|
echo "deny $ip;" >> root/etc/nginx/partials/blocked.conf
|
||||||
|
done
|
||||||
|
|
||||||
|
provision:
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eou pipefail
|
||||||
|
|
||||||
|
pushd {{justfile_directory()}}/terraform > /dev/null
|
||||||
|
NODES=$(tofu output -json | jq -r '.nodes.value[]')
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
for NODE in $NODES
|
||||||
|
do
|
||||||
|
echo "Provisioning node ${NODE}"
|
||||||
|
|
||||||
|
ssh ubuntu@${NODE} 'sudo rm -rf /srv && sudo mkdir /srv && sudo chown ubuntu:ubuntu /srv'
|
||||||
|
|
||||||
|
cat install.sh | ssh ubuntu@${NODE} 'sudo bash -s'
|
||||||
|
done
|
||||||
|
|
91
root/etc/nginx/nginx.conf
Normal file
91
root/etc/nginx/nginx.conf
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
user www-data;
|
||||||
|
worker_processes auto;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
include /etc/nginx/modules-enabled/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /dev/stderr error;
|
||||||
|
|
||||||
|
stream {
|
||||||
|
# Map of Host -> IP
|
||||||
|
# We will route the traffic to this endpoints.
|
||||||
|
map $ssl_preread_server_name $selected_upstream {
|
||||||
|
hostnames;
|
||||||
|
|
||||||
|
# if not knonw, use some non existing response thingy :shrug:
|
||||||
|
default 255.255.255.255:1;
|
||||||
|
|
||||||
|
## CLOUD
|
||||||
|
proxmox.tjo.cloud batuu.system.tjo.space:4443;
|
||||||
|
postgresql.tjo.cloud batuu.system.tjo.space:4443;
|
||||||
|
monitor.tjo.cloud hetzner.system.tjo.cloud:4443;
|
||||||
|
loki.monitor.tjo.cloud hetzner.system.tjo.cloud:4443;
|
||||||
|
prometheus.monitor.tjo.cloud hetzner.system.tjo.cloud:4443;
|
||||||
|
grpc.otel.monitor.tjo.cloud hetzner.system.tjo.cloud:4443;
|
||||||
|
http.otel.monitor.tjo.cloud hetzner.system.tjo.cloud:4443;
|
||||||
|
vault.tjo.cloud batuu.system.tjo.space:4443;
|
||||||
|
|
||||||
|
## HETZNER
|
||||||
|
tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
chat.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
webhook.chat.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
matrix.chat.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
yt.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
search.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
send.tjo.space hetzner.system.tjo.cloud:4443;
|
||||||
|
|
||||||
|
## BATUU
|
||||||
|
cloud.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
collabora.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
code.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
vault.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
rss.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
id.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
ldap.id.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
mnts.dev batuu.system.tjo.space:4443;
|
||||||
|
paperless.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
penpot.tjo.space batuu.system.tjo.space:4443;
|
||||||
|
|
||||||
|
## JAKKU
|
||||||
|
books.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
next.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
request.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
tdarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
stuff.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
auth.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
sonarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
radarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
lidarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
prowlarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
qbittorrent.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
bazarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
readarr.media.tjo.space jakku.system.tjo.space:4443;
|
||||||
|
}
|
||||||
|
|
||||||
|
geoip2 /var/geoip.mmdb {
|
||||||
|
$geoip2_data_country_iso_code country iso_code;
|
||||||
|
$geoip2_data_latitude location latitude;
|
||||||
|
$geoip2_data_longitude location longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_format basic 'country=$geoip2_data_country_iso_code lat=$geoip2_data_latitude long=$geoip2_data_longitude '
|
||||||
|
'ip=$remote_addr '
|
||||||
|
'protocol=$protocol server_name=$ssl_preread_server_name upstream=$selected_upstream status=$status bytes_sent=$bytes_sent bytes_received=$bytes_received '
|
||||||
|
'session_time=$session_time';
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 0.0.0.0:443 default_server;
|
||||||
|
listen [::]:443 default_server;
|
||||||
|
server_name _;
|
||||||
|
proxy_pass $selected_upstream;
|
||||||
|
|
||||||
|
proxy_protocol on;
|
||||||
|
include /etc/nginx/partials/server.conf;
|
||||||
|
include /etc/nginx/partials/blocked.conf;
|
||||||
|
}
|
||||||
|
}
|
164
root/etc/nginx/partials/blocked.conf
Normal file
164
root/etc/nginx/partials/blocked.conf
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
#!!DO NOT EDIT!! Generated by using just ingress-blocked-list command.
|
||||||
|
deny 102.132.96.0/19;
|
||||||
|
deny 102.221.188.0/22;
|
||||||
|
deny 103.4.96.0/22;
|
||||||
|
deny 129.134.0.0/16;
|
||||||
|
deny 13.66.139.0/24;
|
||||||
|
deny 13.66.144.0/24;
|
||||||
|
deny 13.67.10.16/28;
|
||||||
|
deny 13.69.66.240/28;
|
||||||
|
deny 13.71.172.224/28;
|
||||||
|
deny 139.217.52.0/28;
|
||||||
|
deny 147.75.208.0/20;
|
||||||
|
deny 157.240.0.0/16;
|
||||||
|
deny 157.55.39.0/24;
|
||||||
|
deny 163.114.128.0/20;
|
||||||
|
deny 163.70.128.0/17;
|
||||||
|
deny 163.77.128.0/17;
|
||||||
|
deny 173.252.64.0/18;
|
||||||
|
deny 179.60.192.0/22;
|
||||||
|
deny 185.60.216.0/22;
|
||||||
|
deny 185.89.216.0/22;
|
||||||
|
deny 191.233.204.224/28;
|
||||||
|
deny 192.178.5.0/27;
|
||||||
|
deny 192.178.6.0/27;
|
||||||
|
deny 196.49.68.0/23;
|
||||||
|
deny 199.201.64.0/22;
|
||||||
|
deny 199.30.24.0/23;
|
||||||
|
deny 2001:4860:4801:10::/60;
|
||||||
|
deny 2001:4860:4801:20::/60;
|
||||||
|
deny 2001:4860:4801:2::/64;
|
||||||
|
deny 2001:4860:4801:31::/64;
|
||||||
|
deny 2001:4860:4801:32::/63;
|
||||||
|
deny 2001:4860:4801:34::/62;
|
||||||
|
deny 2001:4860:4801:38::/62;
|
||||||
|
deny 2001:4860:4801:3c::/63;
|
||||||
|
deny 2001:4860:4801:3e::/64;
|
||||||
|
deny 2001:4860:4801:40::/61;
|
||||||
|
deny 2001:4860:4801:48::/62;
|
||||||
|
deny 2001:4860:4801:50::/63;
|
||||||
|
deny 2001:4860:4801:53::/64;
|
||||||
|
deny 2001:4860:4801:54::/63;
|
||||||
|
deny 2001:4860:4801:60::/60;
|
||||||
|
deny 2001:4860:4801:70::/61;
|
||||||
|
deny 2001:4860:4801:78::/63;
|
||||||
|
deny 2001:4860:4801:80::/61;
|
||||||
|
deny 2001:4860:4801:88::/64;
|
||||||
|
deny 2001:4860:4801:90::/62;
|
||||||
|
deny 2001:4860:4801:94::/64;
|
||||||
|
deny 2001:4860:4801:c::/64;
|
||||||
|
deny 2001:4860:4801:f::/64;
|
||||||
|
deny 20.125.163.80/28;
|
||||||
|
deny 20.15.133.160/27;
|
||||||
|
deny 20.36.108.32/28;
|
||||||
|
deny 204.15.20.0/22;
|
||||||
|
deny 20.43.120.16/28;
|
||||||
|
deny 20.74.197.0/28;
|
||||||
|
deny 207.46.13.0/24;
|
||||||
|
deny 20.79.107.240/28;
|
||||||
|
deny 2401:db00::/32;
|
||||||
|
deny 2620:0:1c00::/40;
|
||||||
|
deny 2620:10d:c090::/44;
|
||||||
|
deny 2803:6080::/29;
|
||||||
|
deny 2a03:2880::/31;
|
||||||
|
deny 2a03:2887:ff02::/47;
|
||||||
|
deny 2a03:2887:ff04::/46;
|
||||||
|
deny 2a03:2887:ff08::/47;
|
||||||
|
deny 2a03:2887:ff18::/47;
|
||||||
|
deny 2a03:2887:ff1b::/48;
|
||||||
|
deny 2a03:2887:ff1c::/46;
|
||||||
|
deny 2a03:2887:ff21::/48;
|
||||||
|
deny 2a03:2887:ff23::/48;
|
||||||
|
deny 2a03:2887:ff24::/47;
|
||||||
|
deny 2a03:2887:ff27::/48;
|
||||||
|
deny 2a03:2887:ff28::/45;
|
||||||
|
deny 2a03:2887:ff30::/48;
|
||||||
|
deny 2a03:2887:ff33::/48;
|
||||||
|
deny 2a03:2887:ff35::/48;
|
||||||
|
deny 2a03:2887:ff36::/47;
|
||||||
|
deny 2a03:2887:ff38::/46;
|
||||||
|
deny 2a03:2887:ff3f::/48;
|
||||||
|
deny 2a03:2887:ff40::/46;
|
||||||
|
deny 2a03:2887:ff44::/47;
|
||||||
|
deny 2a03:2887:ff48::/46;
|
||||||
|
deny 2a03:2887:ff4d::/48;
|
||||||
|
deny 2a03:2887:ff4e::/47;
|
||||||
|
deny 2a03:2887:ff50::/45;
|
||||||
|
deny 2a03:2887:ff58::/47;
|
||||||
|
deny 2a03:2887:ff60::/45;
|
||||||
|
deny 2a03:2887:ff68::/47;
|
||||||
|
deny 2a03:83e0::/32;
|
||||||
|
deny 2a10:f781:10:cee0::/64;
|
||||||
|
deny 2c0f:ef78:10::/47;
|
||||||
|
deny 2c0f:ef78:12::/48;
|
||||||
|
deny 2c0f:ef78:3::/48;
|
||||||
|
deny 2c0f:ef78::/47;
|
||||||
|
deny 2c0f:ef78:5::/48;
|
||||||
|
deny 2c0f:ef78:6::/48;
|
||||||
|
deny 2c0f:ef78:9::/48;
|
||||||
|
deny 2c0f:ef78:c::/46;
|
||||||
|
deny 31.13.24.0/21;
|
||||||
|
deny 31.13.64.0/18;
|
||||||
|
deny 34.100.182.96/28;
|
||||||
|
deny 34.101.50.144/28;
|
||||||
|
deny 34.118.254.0/28;
|
||||||
|
deny 34.118.66.0/28;
|
||||||
|
deny 34.126.178.96/28;
|
||||||
|
deny 34.146.150.144/28;
|
||||||
|
deny 34.147.110.144/28;
|
||||||
|
deny 34.151.74.144/28;
|
||||||
|
deny 34.152.50.64/28;
|
||||||
|
deny 34.154.114.144/28;
|
||||||
|
deny 34.155.98.32/28;
|
||||||
|
deny 34.165.18.176/28;
|
||||||
|
deny 34.175.160.64/28;
|
||||||
|
deny 34.176.130.16/28;
|
||||||
|
deny 34.22.85.0/27;
|
||||||
|
deny 34.64.82.64/28;
|
||||||
|
deny 34.65.242.112/28;
|
||||||
|
deny 34.80.50.80/28;
|
||||||
|
deny 34.88.194.0/28;
|
||||||
|
deny 34.89.10.80/28;
|
||||||
|
deny 34.89.198.80/28;
|
||||||
|
deny 34.96.162.48/28;
|
||||||
|
deny 35.247.243.240/28;
|
||||||
|
deny 40.77.139.0/25;
|
||||||
|
deny 40.77.167.0/24;
|
||||||
|
deny 40.77.177.0/24;
|
||||||
|
deny 40.77.178.0/23;
|
||||||
|
deny 40.77.188.0/22;
|
||||||
|
deny 40.77.202.0/24;
|
||||||
|
deny 40.79.131.208/28;
|
||||||
|
deny 40.79.186.176/28;
|
||||||
|
deny 45.64.40.0/22;
|
||||||
|
deny 51.105.67.0/28;
|
||||||
|
deny 52.167.144.0/24;
|
||||||
|
deny 52.230.152.0/24;
|
||||||
|
deny 52.231.148.0/28;
|
||||||
|
deny 52.233.106.0/24;
|
||||||
|
deny 57.141.0.0/21;
|
||||||
|
deny 57.141.12.0/23;
|
||||||
|
deny 57.141.8.0/22;
|
||||||
|
deny 57.144.0.0/14;
|
||||||
|
deny 65.55.210.0/24;
|
||||||
|
deny 66.220.144.0/20;
|
||||||
|
deny 66.249.64.0/25;
|
||||||
|
deny 66.249.64.128/26;
|
||||||
|
deny 66.249.64.224/27;
|
||||||
|
deny 66.249.65.0/24;
|
||||||
|
deny 66.249.66.0/25;
|
||||||
|
deny 66.249.66.160/27;
|
||||||
|
deny 66.249.66.192/27;
|
||||||
|
deny 66.249.68.0/25;
|
||||||
|
deny 66.249.69.0/24;
|
||||||
|
deny 66.249.70.0/23;
|
||||||
|
deny 66.249.72.0/23;
|
||||||
|
deny 66.249.74.0/25;
|
||||||
|
deny 66.249.74.128/27;
|
||||||
|
deny 66.249.75.0/24;
|
||||||
|
deny 66.249.76.0/23;
|
||||||
|
deny 66.249.78.0/26;
|
||||||
|
deny 66.249.79.0/24;
|
||||||
|
deny 69.171.224.0/19;
|
||||||
|
deny 69.63.176.0/20;
|
||||||
|
deny 74.119.76.0/22;
|
5
root/etc/nginx/partials/server.conf
Normal file
5
root/etc/nginx/partials/server.conf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Default server configuration
|
||||||
|
access_log /dev/stdout basic;
|
||||||
|
resolver 9.9.9.9 1.1.1.1 8.8.8.8 8.8.4.4;
|
||||||
|
set_real_ip_from 0.0.0.0/0;
|
||||||
|
ssl_preread on;
|
|
@ -24,30 +24,6 @@ provider "registry.opentofu.org/bpg/proxmox" {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "registry.opentofu.org/digitalocean/digitalocean" {
|
|
||||||
version = "2.40.0"
|
|
||||||
constraints = "~> 2.0"
|
|
||||||
hashes = [
|
|
||||||
"h1:Y7VkuuqOBgv+1jgL/4Hi247K2BskXwXtR/Uk9ssK/e4=",
|
|
||||||
"zh:00235830abae70642ebefc4d9c00e5eb978e28b74abc6b34f16b078f242aa217",
|
|
||||||
"zh:09d77785f768bd568f85a121d3d79316083befe903ce4ccd5567689a23236fb0",
|
|
||||||
"zh:0c9c4e19b411702d316a6bd044903e2ec506a69d38495ed32cc31e3f3f26acae",
|
|
||||||
"zh:12b34c88faad5b6149e9a3ad1396680588e1bae263b20d6b19835460f111c190",
|
|
||||||
"zh:15f041fc57ea46673a828919efe2ef3f05f7c4b863b7d7881336b93e92bd1159",
|
|
||||||
"zh:45e01972de2fab1687a09ea8fb3e4519be11c93ef93a63f28665630850858a20",
|
|
||||||
"zh:4e18bf5c1d2ec1ec6b6a9f4b58045309006f510edf770168fc18e273e6a09289",
|
|
||||||
"zh:575528b7e36e3489d2309e0c6cb9bd9952595cac5459b914f2d2827de1a1e4fc",
|
|
||||||
"zh:67462192212f810875d556462c79f574a8f5713b7a869ba4fce25953bfcf2dd2",
|
|
||||||
"zh:7024637b31e8276b653265fdf3f479220182edde4b300b034562b4c287faefa5",
|
|
||||||
"zh:a7904721b2680be8330dde98dd826be15c67eb274da7876f042cbcd6592ac970",
|
|
||||||
"zh:b225d4b67037a19392b0ab00d1f5fc9e729db4dfc32d18d4b36225693270ef52",
|
|
||||||
"zh:bd1e8768819d6113b2ec16f939196a1f2ae6d2803824fde463a20d06e071b212",
|
|
||||||
"zh:c5da40dc0749548ee2e1943776fb41b952c994e50bbc404251df20a81f730242",
|
|
||||||
"zh:dabc3387392aaba297739e1e97fadf059258fc3efb4dff2f499dbc407b6e088d",
|
|
||||||
"zh:f42137cf424c3e7c9c935b3f73618e51096bd0367a8d364073e2d70588d2cbf2",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "registry.opentofu.org/goauthentik/authentik" {
|
provider "registry.opentofu.org/goauthentik/authentik" {
|
||||||
version = "2024.8.3"
|
version = "2024.8.3"
|
||||||
constraints = "2024.8.3"
|
constraints = "2024.8.3"
|
||||||
|
@ -69,43 +45,3 @@ provider "registry.opentofu.org/goauthentik/authentik" {
|
||||||
"zh:f6af0fd2e89ea7b7e692ef893cf5fdcc6f53c37fc0c6e066a28d9c834226c539",
|
"zh:f6af0fd2e89ea7b7e692ef893cf5fdcc6f53c37fc0c6e066a28d9c834226c539",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "registry.opentofu.org/hashicorp/dns" {
|
|
||||||
version = "3.4.1"
|
|
||||||
constraints = "~> 3.4.1"
|
|
||||||
hashes = [
|
|
||||||
"h1:6Tb2wZRxfKunvjLw47ihfkaoARWIQrJd+WCOXkx0hg4=",
|
|
||||||
"zh:53f46f16fc3b25d9bdce61d7cc9a67cea9c67ea5347fcde35833451d5011f1c4",
|
|
||||||
"zh:662669802c99c7e698ca52e7a32afc19acf66d97bbc05f5effacdf0fe471848f",
|
|
||||||
"zh:8289aee49df8a0cb2fcdfded575e68df1721fc3e6ce75555def499d31b7e910d",
|
|
||||||
"zh:90aa9b049d19137ed15ea3f88238824e1fde7d1a806378cb97520391e169a96d",
|
|
||||||
"zh:9e5795e10d65927ba689cfabc06b72085055543342d1db26ef5963ae5ab5d64a",
|
|
||||||
"zh:9f39b6e0ca35cf2405fe4e13af8a405cf9b0b0c34b6b06ad36f319631405a3aa",
|
|
||||||
"zh:c37a2c140c95b3eaa9d0aeb79496b220ba1a0456d01a77fcc68bd565bee7edd5",
|
|
||||||
"zh:cd40d356c5382f0b868df2d8539f95031e3cf0c210053674ec4c7cd20c73b82a",
|
|
||||||
"zh:fde59f09e4e62fc84012fff8493bc64eac287a0245e1c8abf29b0138d3018dfb",
|
|
||||||
"zh:ffee5b54936bd43247e9316de0ecc0dde36556a2cd50f090d7f6443a3f689b95",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "registry.opentofu.org/tailscale/tailscale" {
|
|
||||||
version = "0.16.1"
|
|
||||||
constraints = "0.16.1"
|
|
||||||
hashes = [
|
|
||||||
"h1:NDIIkEo0G/leQSvGoh2Mk74ZE2xWrWgHX/S8ZVyBDYU=",
|
|
||||||
"zh:0a9d28e5195e0e29ebf9b12b345cafcb686125008151fa01677c399d8f8f1321",
|
|
||||||
"zh:249bce2fcfd3414211ae9e49e179e31b5d3c23dd9da24dc45acdea34ad308cb0",
|
|
||||||
"zh:3129fb52a2aaa0c8c30aff21e7d4c0601d80898b3ecb9d7604b5933c14f54924",
|
|
||||||
"zh:4ec3e255f34bb4f6362ab41aa9e05a3ce040a791bc07445dec86188dee867f85",
|
|
||||||
"zh:68d3995e5a1722e24f89a385899f56a63542159b884cac989196e9538b53c6ce",
|
|
||||||
"zh:799840b3bfbd14537397f157f4e6a5e54080cd4fee51521bac675aa188e0b33e",
|
|
||||||
"zh:99f1da9fdaddd8a1255dce56edf8eb3e235293c72738cf70f1fb9ee9631b40e6",
|
|
||||||
"zh:9b18fd51e260b2f3100937c34feae5f6fe3515df9b5e27ae23d00af75249a6d4",
|
|
||||||
"zh:a7154cdce28aeb80e822a97c6bc8b8acb7a074304fd198e265ac9cbcbda0ca06",
|
|
||||||
"zh:b0ce2ca42f018e5235a2171cdd8ba9829c90c54a6b2d602bd38e0e90c43d5d5d",
|
|
||||||
"zh:c67609f7018fc6e48b17befd6eeb21197e8f524496185c5e29707efa6967a0a5",
|
|
||||||
"zh:d4c9dc9d2a5a535851fc10049506bad1e7ab88193d5dcd371f91ac1b84f43a0a",
|
|
||||||
"zh:da27f2a9b9d5a4c02ec3893a763874513825c7c4dc2bb870ba741cf7725bcf9f",
|
|
||||||
"zh:e5bc1797b97607ff3d841c6c0d40da89c3843156ad43e15ded7d41fc0ac27717",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
locals {
|
|
||||||
nodes_for_dns = { for k, v in var.nodes : k => v if v.public != null && v.internal != null }
|
|
||||||
}
|
|
||||||
|
|
||||||
data "digitalocean_domain" "ingress" {
|
|
||||||
name = "ingress.tjo.cloud"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "digitalocean_record" "public" {
|
|
||||||
for_each = merge(
|
|
||||||
{
|
|
||||||
for key, node in local.nodes_for_dns : key => {
|
|
||||||
node = node.name,
|
|
||||||
ip = node.public.ipv4,
|
|
||||||
type = "A",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
for key, node in local.nodes_for_dns : key => {
|
|
||||||
node = node.name,
|
|
||||||
ip = node.public.ipv6,
|
|
||||||
type = "AAAA",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
domain = data.digitalocean_domain.ingress.id
|
|
||||||
type = each.value.type
|
|
||||||
name = lower(each.value.node)
|
|
||||||
value = each.value.ip
|
|
||||||
ttl = 60
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "digitalocean_record" "internal" {
|
|
||||||
for_each = merge(
|
|
||||||
{
|
|
||||||
for key, node in local.nodes_for_dns : key => {
|
|
||||||
node = node.name,
|
|
||||||
ip = node.internal.ipv4,
|
|
||||||
type = "A",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
for key, node in local.nodes_for_dns : key => {
|
|
||||||
node = node.name,
|
|
||||||
ip = node.internal.ipv6,
|
|
||||||
type = "AAAA",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
domain = data.digitalocean_domain.ingress.id
|
|
||||||
type = each.value.type
|
|
||||||
name = "internal.${lower(each.value.node)}"
|
|
||||||
value = each.value.ip
|
|
||||||
ttl = 60
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "digitalocean_record" "srv" {
|
|
||||||
for_each = local.nodes_for_dns
|
|
||||||
|
|
||||||
domain = data.digitalocean_domain.ingress.id
|
|
||||||
type = "SRV"
|
|
||||||
name = digitalocean_record.internal[each.key].fqdn
|
|
||||||
value = "_nginx._tcp"
|
|
||||||
port = 9000
|
|
||||||
priority = 10
|
|
||||||
weight = 100
|
|
||||||
ttl = 60
|
|
||||||
}
|
|
|
@ -3,12 +3,12 @@ locals {
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
for k, v in var.nodes : k => merge(v, {
|
for k, v in var.nodes : k => merge(v, {
|
||||||
id = 700 + index(keys(var.nodes), k)
|
id = 800 + index(keys(var.nodes), k)
|
||||||
hash = sha1(v.name)
|
hash = sha1(v.host)
|
||||||
mac_address = "AA:BB:07:00:${format("%v:%v", substr(sha1(v.name), 0, 2), substr(sha1(v.name), 2, 2))}"
|
mac_address = "AA:BB:07:00:${format("%v:%v", substr(sha1(v.host), 0, 2), substr(sha1(v.host), 2, 2))}"
|
||||||
domain = local.domain
|
domain = local.domain
|
||||||
meta = {
|
meta = {
|
||||||
name = v.name
|
name = v.host
|
||||||
domain = local.domain
|
domain = local.domain
|
||||||
service_account = {
|
service_account = {
|
||||||
username = authentik_user.service_account[k].username
|
username = authentik_user.service_account[k].username
|
||||||
|
@ -17,12 +17,21 @@ locals {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv4_addresses = {
|
||||||
|
for key, node in local.nodes : key => {
|
||||||
|
for k, v in proxmox_virtual_environment_vm.nodes[key].ipv4_addresses :
|
||||||
|
proxmox_virtual_environment_vm.nodes[key].network_interface_names[k] => v
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_download_file" "ubuntu" {
|
resource "proxmox_virtual_environment_download_file" "ubuntu" {
|
||||||
|
for_each = local.nodes
|
||||||
|
|
||||||
content_type = "iso"
|
content_type = "iso"
|
||||||
datastore_id = var.common_storage
|
datastore_id = each.value.iso_storage
|
||||||
node_name = var.nodes[keys(var.nodes)[0]].host
|
node_name = each.value.host
|
||||||
url = "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
url = "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
||||||
overwrite = false
|
overwrite = false
|
||||||
}
|
}
|
||||||
|
@ -32,12 +41,12 @@ resource "proxmox_virtual_environment_file" "userdata" {
|
||||||
|
|
||||||
node_name = each.value.host
|
node_name = each.value.host
|
||||||
content_type = "snippets"
|
content_type = "snippets"
|
||||||
datastore_id = var.common_storage
|
datastore_id = each.value.iso_storage
|
||||||
|
|
||||||
source_raw {
|
source_raw {
|
||||||
data = <<-EOF
|
data = <<-EOF
|
||||||
#cloud-config
|
#cloud-config
|
||||||
hostname: ${each.value.name}.${each.value.domain}
|
hostname: ${each.value.host}.${each.value.domain}
|
||||||
write_files:
|
write_files:
|
||||||
- path: /etc/tjo.cloud/meta.json
|
- path: /etc/tjo.cloud/meta.json
|
||||||
encoding: base64
|
encoding: base64
|
||||||
|
@ -48,7 +57,7 @@ resource "proxmox_virtual_environment_file" "userdata" {
|
||||||
power_state:
|
power_state:
|
||||||
mode: reboot
|
mode: reboot
|
||||||
EOF
|
EOF
|
||||||
file_name = "${each.value.name}.ingress.tjo.cloud.userconfig.yaml"
|
file_name = "${each.value.host}.ingress.tjo.cloud.userconfig.yaml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +65,16 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
||||||
for_each = local.nodes
|
for_each = local.nodes
|
||||||
|
|
||||||
vm_id = each.value.id
|
vm_id = each.value.id
|
||||||
name = "${each.value.name}.${each.value.domain}"
|
name = "${each.value.host}.${each.value.domain}"
|
||||||
node_name = each.value.host
|
node_name = each.value.host
|
||||||
|
|
||||||
description = "Node ${each.value.name} for ${each.value.domain}."
|
description = <<EOT
|
||||||
tags = [each.value.domain]
|
An ingress.tjo.cloud instance for ${each.value.host}.
|
||||||
|
|
||||||
|
Repo: https://code.tjo.space/tjo-cloud/ingress
|
||||||
|
EOT
|
||||||
|
|
||||||
|
tags = [each.value.domain]
|
||||||
|
|
||||||
stop_on_destroy = true
|
stop_on_destroy = true
|
||||||
timeout_start_vm = 60
|
timeout_start_vm = 60
|
||||||
|
@ -79,7 +93,7 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
||||||
|
|
||||||
bios = "ovmf"
|
bios = "ovmf"
|
||||||
efi_disk {
|
efi_disk {
|
||||||
datastore_id = each.value.storage
|
datastore_id = each.value.boot_storage
|
||||||
}
|
}
|
||||||
|
|
||||||
operating_system {
|
operating_system {
|
||||||
|
@ -91,15 +105,15 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
||||||
}
|
}
|
||||||
|
|
||||||
network_device {
|
network_device {
|
||||||
bridge = each.value.bridge
|
bridge = "vmbr1"
|
||||||
mac_address = each.value.mac_address
|
mac_address = each.value.mac_address
|
||||||
}
|
}
|
||||||
|
|
||||||
scsi_hardware = "virtio-scsi-single"
|
scsi_hardware = "virtio-scsi-single"
|
||||||
disk {
|
disk {
|
||||||
file_id = proxmox_virtual_environment_download_file.ubuntu.id
|
file_id = proxmox_virtual_environment_download_file.ubuntu[each.key].id
|
||||||
interface = "virtio0"
|
interface = "virtio0"
|
||||||
datastore_id = each.value.storage
|
datastore_id = each.value.boot_storage
|
||||||
size = each.value.boot_size
|
size = each.value.boot_size
|
||||||
backup = true
|
backup = true
|
||||||
cache = "none"
|
cache = "none"
|
||||||
|
@ -108,7 +122,7 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
||||||
|
|
||||||
initialization {
|
initialization {
|
||||||
interface = "scsi0"
|
interface = "scsi0"
|
||||||
datastore_id = each.value.storage
|
datastore_id = each.value.boot_storage
|
||||||
user_data_file_id = proxmox_virtual_environment_file.userdata[each.key].id
|
user_data_file_id = proxmox_virtual_environment_file.userdata[each.key].id
|
||||||
|
|
||||||
ip_config {
|
ip_config {
|
||||||
|
|
5
terraform/outputs.tf
Normal file
5
terraform/outputs.tf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
output "nodes" {
|
||||||
|
value = [
|
||||||
|
for key, node in proxmox_virtual_environment_vm.nodes : local.ipv4_addresses[key]["eth0"][0]
|
||||||
|
]
|
||||||
|
}
|
|
@ -6,12 +6,11 @@ data "authentik_group" "monitoring_publisher" {
|
||||||
resource "authentik_user" "service_account" {
|
resource "authentik_user" "service_account" {
|
||||||
for_each = var.nodes
|
for_each = var.nodes
|
||||||
|
|
||||||
username = "${each.value.name}.ingress@svc.tjo.cloud"
|
username = "${each.value.host}.${local.domain}"
|
||||||
name = "${each.value.name}.ingress@svc.tjo.cloud"
|
name = "${each.value.host}.${local.domain}"
|
||||||
email = "${each.value.name}.ingress@svc.tjo.cloud"
|
|
||||||
|
|
||||||
type = "service_account"
|
type = "service_account"
|
||||||
path = "svc.tjo.cloud"
|
path = "ingress.tjo.cloud"
|
||||||
|
|
||||||
groups = [
|
groups = [
|
||||||
data.authentik_group.monitoring_publisher.id,
|
data.authentik_group.monitoring_publisher.id,
|
||||||
|
@ -21,9 +20,9 @@ resource "authentik_user" "service_account" {
|
||||||
resource "authentik_token" "service_account" {
|
resource "authentik_token" "service_account" {
|
||||||
for_each = var.nodes
|
for_each = var.nodes
|
||||||
|
|
||||||
identifier = "svc-tjo-cloud-service-account-${each.value.name}"
|
identifier = replace("service-account-${each.value.host}-${local.domain}", ".", "-")
|
||||||
user = authentik_user.service_account[each.key].id
|
user = authentik_user.service_account[each.key].id
|
||||||
description = "Service account for ${each.value.name} node"
|
description = "Service account for ${each.value.host}.${local.domain} node."
|
||||||
expiring = false
|
expiring = false
|
||||||
intent = "app_password"
|
intent = "app_password"
|
||||||
retrieve_key = true
|
retrieve_key = true
|
||||||
|
|
|
@ -1,21 +1,9 @@
|
||||||
terraform {
|
terraform {
|
||||||
required_providers {
|
required_providers {
|
||||||
digitalocean = {
|
|
||||||
source = "digitalocean/digitalocean"
|
|
||||||
version = "~> 2.0"
|
|
||||||
}
|
|
||||||
dns = {
|
|
||||||
source = "hashicorp/dns"
|
|
||||||
version = "~> 3.4.1"
|
|
||||||
}
|
|
||||||
proxmox = {
|
proxmox = {
|
||||||
source = "bpg/proxmox"
|
source = "bpg/proxmox"
|
||||||
version = "0.61.1"
|
version = "0.61.1"
|
||||||
}
|
}
|
||||||
tailscale = {
|
|
||||||
source = "tailscale/tailscale"
|
|
||||||
version = "0.16.1"
|
|
||||||
}
|
|
||||||
authentik = {
|
authentik = {
|
||||||
source = "goauthentik/authentik"
|
source = "goauthentik/authentik"
|
||||||
version = "2024.8.3"
|
version = "2024.8.3"
|
||||||
|
@ -30,21 +18,32 @@ provider "authentik" {
|
||||||
token = var.authentik_token
|
token = var.authentik_token
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "digitalocean" {
|
|
||||||
token = var.digitalocean_token
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "tailscale" {
|
|
||||||
api_key = var.tailscale_apikey
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "proxmox" {
|
provider "proxmox" {
|
||||||
# FIXME: Traefik/NGINX breaks this! 500 ERROR
|
# FIXME: Traefik/NGINX breaks this! 500 ERROR
|
||||||
endpoint = "https://178.63.49.225:8006/api2/json"
|
endpoint = "https://batuu.system.tjo.cloud:8006/api2/json"
|
||||||
insecure = true
|
insecure = true
|
||||||
api_token = var.proxmox_token
|
api_token = var.proxmox_token
|
||||||
|
|
||||||
ssh {
|
ssh {
|
||||||
agent = true
|
agent = true
|
||||||
username = "root"
|
username = "root"
|
||||||
|
|
||||||
|
node {
|
||||||
|
name = "batuu"
|
||||||
|
address = "batuu.system.tjo.cloud"
|
||||||
|
port = 22
|
||||||
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
name = "jakku"
|
||||||
|
address = "jakku.system.tjo.cloud"
|
||||||
|
port = 22
|
||||||
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
name = "nevaroo"
|
||||||
|
address = "nevaroo.system.tjo.cloud"
|
||||||
|
port = 22
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
nodes = {
|
nodes = {
|
||||||
de_01 = {
|
batuu = {
|
||||||
name = "de-01"
|
host = "batuu"
|
||||||
host = "hetzner"
|
iso_storage = "local"
|
||||||
bridge = "vmprivate0"
|
boot_storage = "local-nvme"
|
||||||
cloudinit = ""
|
|
||||||
}
|
}
|
||||||
de_02 = {
|
jakku = {
|
||||||
name = "de-02"
|
host = "jakku"
|
||||||
host = "hetzner"
|
iso_storage = "local"
|
||||||
bridge = "vmprivate0"
|
boot_storage = "local-nvme"
|
||||||
cloudinit = ""
|
}
|
||||||
|
nevaroo = {
|
||||||
|
host = "nevaroo"
|
||||||
|
iso_storage = "local"
|
||||||
|
boot_storage = "local"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_keys = [
|
ssh_keys = [
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXAlzwziqfUUb2qmFwNF/nrBYc5MNT1MMOx81ohBmB+ tine@little.sys.tjo.space"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXAlzwziqfUUb2qmFwNF/nrBYc5MNT1MMOx81ohBmB+ tine@little.sys.tjo.space"
|
||||||
]
|
]
|
||||||
|
|
||||||
common_storage = "proxmox-backup-tjo-cloud"
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
variable "nodes" {
|
variable "nodes" {
|
||||||
type = map(object({
|
type = map(object({
|
||||||
name = string
|
host = string
|
||||||
|
|
||||||
internal = optional(object({
|
internal = optional(object({
|
||||||
ipv4 = string
|
ipv4 = string
|
||||||
|
@ -11,16 +11,14 @@ variable "nodes" {
|
||||||
ipv6 = string
|
ipv6 = string
|
||||||
}))
|
}))
|
||||||
|
|
||||||
host = string
|
|
||||||
bridge = string
|
|
||||||
|
|
||||||
cores = optional(number, 1)
|
cores = optional(number, 1)
|
||||||
memory = optional(number, 512)
|
memory = optional(number, 512)
|
||||||
|
|
||||||
storage = optional(string, "main")
|
iso_storage = string
|
||||||
boot_size = optional(number, 8)
|
|
||||||
|
|
||||||
cloudinit = string
|
boot_storage = string
|
||||||
|
boot_size = optional(number, 8)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +26,6 @@ variable "ssh_keys" {
|
||||||
type = list(string)
|
type = list(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "common_storage" {
|
|
||||||
type = string
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "digitalocean_token" {
|
variable "digitalocean_token" {
|
||||||
type = string
|
type = string
|
||||||
sensitive = true
|
sensitive = true
|
||||||
|
|
Loading…
Reference in a new issue