WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit f95b436

Browse files
committed
Add ability to use "myipv4" as a pseudo-address in firewall rules. The ip-address is then fetched on terraform run from opendns (google as secondary)
1 parent ee1b6ba commit f95b436

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

data.tf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,38 @@ data "hcloud_ssh_keys" "keys_by_selector" {
3232
count = length(var.ssh_hcloud_key_label) > 0 ? 1 : 0
3333
with_selector = var.ssh_hcloud_key_label
3434
}
35+
36+
data "external" "my_ip" {
37+
count = local.is_ref_myipv4_used ? 1 : 0
38+
39+
program = [
40+
"bash",
41+
"-c",
42+
<<-EOT
43+
set -euo pipefail
44+
45+
error_exit() {
46+
echo "Error: $1" >&2
47+
exit 1
48+
}
49+
50+
if ! command -v dig &> /dev/null; then
51+
error_exit "'dig' command not found. Please install it (e.g., 'apt-get install dnsutils' or 'yum install bind-utils')."
52+
fi
53+
54+
IPV4_REGEX="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
55+
56+
IPV4=""
57+
58+
if ! [[ "$IPV4" =~ $IPV4_REGEX ]]; then
59+
IPV4=$(dig +time=5 +tries=2 -4 +short TXT o-o.myaddr.l.google.com @ns1.google.com | head -n 1 | tr -d '"' || true)
60+
fi
61+
62+
if [[ "$IPV4" =~ $IPV4_REGEX ]]; then
63+
echo "{\"ipv4\": \"$IPV4\"}"
64+
else
65+
error_exit "Failed to retrieve a valid public IPv4 address. Last value received was: '$IPV4'"
66+
fi
67+
EOT
68+
]
69+
}

kube.tf.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,12 +784,14 @@ module "kube-hetzner" {
784784
# you would have to connect to any control plane node via SSH, as you can run kubectl from within these.
785785
# Please be advised that this setting has no effect on the load balancer when the use_control_plane_lb variable is set to true. This is
786786
# because firewall rules cannot be applied to load balancers yet.
787+
# Note: You can use the string "myipv4" as an IP address in the array and it will be replaced with the CIDR/32 of your IP as reported by myip.opendns.com. Use of "myipv4" requires `dig` to be available.
787788
# firewall_kube_api_source = null
788789

789790
# Allow SSH access from the specified networks. Default: ["0.0.0.0/0", "::/0"]
790791
# Allowed values: null (disable SSH rule entirely) or a list of allowed networks with CIDR notation.
791792
# Ideally you would set your IP there. And if it changes after cluster deploy, you can always update this variable and apply again.
792-
# firewall_ssh_source = ["1.2.3.4/32"]
793+
# Note: You can use the string "myipv4" as an IP address in the array and it will be replaced with the CIDR/32 of your IP as reported by myip.opendns.com. Use of "myipv4" requires `dig` to be available.
794+
# firewall_ssh_source = ["myipv4", "1.2.3.4/32"]
793795

794796
# By default, SELinux is enabled in enforcing mode on all nodes. For container-specific SELinux issues,
795797
# consider using the pre-installed 'udica' tool to create custom, targeted SELinux policies instead of
@@ -798,6 +800,7 @@ module "kube-hetzner" {
798800

799801
# Adding extra firewall rules, like opening a port
800802
# More info on the format here https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs/resources/firewall
803+
# Note: You can use the string "myipv4" as an IP address in the `source_ips` or `destination_ips` arrays and it will be replaced with the CIDR/32 of your IP as reported by myip.opendns.com. Use of "myipv4" requires `dig` to be available.
801804
# extra_firewall_rules = [
802805
# {
803806
# description = "For Postgres"

locals.tf

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ locals {
2727
dns_servers_ipv4 = [for ip in var.dns_servers : ip if provider::assert::ipv4(ip)]
2828
dns_servers_ipv6 = [for ip in var.dns_servers : ip if provider::assert::ipv6(ip)]
2929

30+
# My IPv4 related variables.
31+
is_ref_myipv4_used = (
32+
contains(coalesce(var.firewall_kube_api_source, []), var.myipv4_ref) ||
33+
contains(coalesce(var.firewall_ssh_source, []), var.myipv4_ref) ||
34+
contains(flatten([
35+
for rule in var.extra_firewall_rules : concat(coalesce(rule.source_ips, []), coalesce(rule.destination_ips, []))
36+
]), var.myipv4_ref)
37+
)
38+
my_public_ipv4_cidr = try("${data.external.my_ip[0].result.ipv4}/32", null)
39+
40+
3041
additional_k3s_environment = join("\n",
3142
[
3243
for var_name, var_value in var.additional_k3s_environment :
@@ -509,8 +520,15 @@ locals {
509520
# merge the two lists
510521
firewall_rules_merged = merge(local.firewall_rules, local.extra_firewall_rules)
511522

512-
# convert the merged list back to a list
513-
firewall_rules_list = values(local.firewall_rules_merged)
523+
# replace "myipv4" (var.myipv4_ref) with the actual value, merge to a list
524+
firewall_rules_list = [for key, rule in local.firewall_rules_merged : {
525+
description = rule.description
526+
direction = rule.direction
527+
protocol = rule.protocol
528+
port = rule.port
529+
source_ips = compact([for ip in lookup(rule, "source_ips", []) : ip == var.myipv4_ref ? local.my_public_ipv4_cidr : ip])
530+
destination_ips = compact([for ip in lookup(rule, "destination_ips", []) : ip == var.myipv4_ref ? local.my_public_ipv4_cidr : ip])
531+
} if rule != null]
514532

515533
labels = {
516534
"provisioner" = "terraform",

main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,11 @@ resource "hcloud_firewall" "k3s" {
7878
source_ips = lookup(rule.value, "source_ips", [])
7979
}
8080
}
81-
}
8281

82+
lifecycle {
83+
precondition {
84+
condition = !local.is_ref_myipv4_used || local.my_public_ipv4_cidr != null
85+
error_message = "Failed to retrieve public IPv4 address for 'myipv4' replacement. Please check your internet connection and ensure 'dig' is installed."
86+
}
87+
}
88+
}

variables.tf

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,9 +667,29 @@ variable "automatically_upgrade_os" {
667667
}
668668

669669
variable "extra_firewall_rules" {
670-
type = list(any)
670+
type = list(object({
671+
description = optional(string, "")
672+
direction = string
673+
protocol = optional(string, "tcp")
674+
port = optional(string, null)
675+
source_ips = optional(list(string), [])
676+
destination_ips = optional(list(string), [])
677+
}))
678+
671679
default = []
672680
description = "Additional firewall rules to apply to the cluster."
681+
682+
validation {
683+
condition = alltrue([
684+
for rule in var.extra_firewall_rules : (
685+
contains(["in", "out"], rule.direction) &&
686+
(rule.direction == "in" ? length(rule.source_ips) > 0 : true) &&
687+
(rule.direction == "out" ? length(rule.destination_ips) > 0 : true) &&
688+
(contains(["tcp", "udp"], rule.protocol) ? rule.port != null && rule.port != "" : true)
689+
)
690+
])
691+
error_message = "Invalid firewall rule configuration: direction must be 'in' or 'out'; source_ips must be defined (non-empty) for 'in' rules; destination_ips must be defined (non-empty) for 'out' rules; for 'tcp' or 'udp' protocols, port must be defined (non-null and non-empty)."
692+
}
673693
}
674694

675695
variable "firewall_kube_api_source" {
@@ -684,6 +704,12 @@ variable "firewall_ssh_source" {
684704
description = "Source networks that have SSH access to the servers."
685705
}
686706

707+
variable "myipv4_ref" {
708+
type = string
709+
default = "myipv4"
710+
description = "Name to be used in firewall rules as a substitute for your own IPv4 address."
711+
}
712+
687713
variable "use_cluster_name_in_node_name" {
688714
type = bool
689715
default = true

versions.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ terraform {
99
source = "hetznercloud/hcloud"
1010
version = ">= 1.51.0"
1111
}
12+
external = {
13+
source = "hashicorp/external"
14+
version = "~> 2.0"
15+
}
1216
local = {
1317
source = "hashicorp/local"
1418
version = ">= 2.5.2"

0 commit comments

Comments
 (0)