From 200b63031944185473b83a9c47ad56308bc40f24 Mon Sep 17 00:00:00 2001
From: raviranjan <ravi.ranjan@elastisys.com>
Date: Mon, 28 Aug 2023 12:07:03 +0200
Subject: [PATCH] Adding egress IPv6 for node-local-dns queries

---
 contrib/terraform/openstack/README.md         |  7 ++
 contrib/terraform/openstack/kubespray.tf      |  7 ++
 .../openstack/modules/compute/main.tf         | 89 +++++++++++++++++++
 .../openstack/modules/compute/variables.tf    | 28 ++++++
 contrib/terraform/openstack/variables.tf      | 49 ++++++++++
 5 files changed, 180 insertions(+)

diff --git a/contrib/terraform/openstack/README.md b/contrib/terraform/openstack/README.md
index a99669276..f68e22531 100644
--- a/contrib/terraform/openstack/README.md
+++ b/contrib/terraform/openstack/README.md
@@ -269,11 +269,18 @@ For your cluster, edit `inventory/$CLUSTER/cluster.tfvars`.
 |`supplementary_master_groups` | To add ansible groups to the masters, such as `kube_node` for tainting them as nodes, empty by default. |
 |`supplementary_node_groups` | To add ansible groups to the nodes, such as `kube_ingress` for running ingress controller pods, empty by default. |
 |`bastion_allowed_remote_ips` | List of CIDR allowed to initiate a SSH connection, `["0.0.0.0/0"]` by default |
+|`bastion_allowed_remote_ipv6_ips` | List of IPv6 CIDR allowed to initiate a SSH connection, `["::/0"]` by default |
 |`master_allowed_remote_ips` | List of CIDR blocks allowed to initiate an API connection, `["0.0.0.0/0"]` by default |
+|`master_allowed_remote_ipv6_ips` | List of IPv6 CIDR blocks allowed to initiate an API connection, `["::/0"]` by default |
 |`bastion_allowed_ports` | List of ports to open on bastion node, `[]` by default |
+|`bastion_allowed_ports_ipv6` | List of ports to open on bastion node for IPv6 CIDR blocks, `[]` by default |
 |`k8s_allowed_remote_ips` | List of CIDR allowed to initiate a SSH connection, empty by default |
+|`k8s_allowed_remote_ips_ipv6` | List of IPv6 CIDR allowed to initiate a SSH connection, empty by default |
+|`k8s_allowed_egress_ipv6_ips` | List of IPv6 CIDRs allowed for egress traffic, `["::/0"]` by default |
 |`worker_allowed_ports` | List of ports to open on worker nodes, `[{ "protocol" = "tcp", "port_range_min" = 30000, "port_range_max" = 32767, "remote_ip_prefix" = "0.0.0.0/0"}]` by default |
+|`worker_allowed_ports_ipv6` | List of ports to open on worker nodes for IPv6 CIDR blocks, `[{ "protocol" = "tcp", "port_range_min" = 30000, "port_range_max" = 32767, "remote_ip_prefix" = "::/0"}]` by default |
 |`master_allowed_ports` | List of ports to open on master nodes, expected format is `[{ "protocol" = "tcp", "port_range_min" = 443, "port_range_max" = 443, "remote_ip_prefix" = "0.0.0.0/0"}]`, empty by default |
+|`master_allowed_ports_ipv6` | List of ports to open on master nodes for IPv6 CIDR blocks, expected format is `[{ "protocol" = "tcp", "port_range_min" = 443, "port_range_max" = 443, "remote_ip_prefix" = "::/0"}]`, empty by default |
 |`node_root_volume_size_in_gb` | Size of the root volume for nodes, 0 to use ephemeral storage |
 |`master_root_volume_size_in_gb` | Size of the root volume for masters, 0 to use ephemeral storage |
 |`master_volume_type` | Volume type of the root volume for control_plane, 'Default' by default |
diff --git a/contrib/terraform/openstack/kubespray.tf b/contrib/terraform/openstack/kubespray.tf
index a17763432..32c00bd86 100644
--- a/contrib/terraform/openstack/kubespray.tf
+++ b/contrib/terraform/openstack/kubespray.tf
@@ -77,14 +77,21 @@ module "compute" {
   k8s_nodes_fips                               = module.ips.k8s_nodes_fips
   bastion_fips                                 = module.ips.bastion_fips
   bastion_allowed_remote_ips                   = var.bastion_allowed_remote_ips
+  bastion_allowed_remote_ipv6_ips              = var.bastion_allowed_remote_ipv6_ips
   master_allowed_remote_ips                    = var.master_allowed_remote_ips
+  master_allowed_remote_ipv6_ips               = var.master_allowed_remote_ipv6_ips
   k8s_allowed_remote_ips                       = var.k8s_allowed_remote_ips
+  k8s_allowed_remote_ips_ipv6                  = var.k8s_allowed_remote_ips_ipv6
   k8s_allowed_egress_ips                       = var.k8s_allowed_egress_ips
+  k8s_allowed_egress_ipv6_ips                  = var.k8s_allowed_egress_ipv6_ips
   supplementary_master_groups                  = var.supplementary_master_groups
   supplementary_node_groups                    = var.supplementary_node_groups
   master_allowed_ports                         = var.master_allowed_ports
+  master_allowed_ports_ipv6                    = var.master_allowed_ports_ipv6
   worker_allowed_ports                         = var.worker_allowed_ports
+  worker_allowed_ports_ipv6                    = var.worker_allowed_ports_ipv6
   bastion_allowed_ports                        = var.bastion_allowed_ports
+  bastion_allowed_ports_ipv6                   = var.bastion_allowed_ports_ipv6
   use_access_ip                                = var.use_access_ip
   master_server_group_policy                   = var.master_server_group_policy
   node_server_group_policy                     = var.node_server_group_policy
diff --git a/contrib/terraform/openstack/modules/compute/main.tf b/contrib/terraform/openstack/modules/compute/main.tf
index d161d26f6..2256ea2b4 100644
--- a/contrib/terraform/openstack/modules/compute/main.tf
+++ b/contrib/terraform/openstack/modules/compute/main.tf
@@ -70,6 +70,36 @@ resource "openstack_networking_secgroup_rule_v2" "k8s_master_ports" {
   security_group_id = openstack_networking_secgroup_v2.k8s_master.id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "k8s_master_ipv6_ingress" {
+  count             = length(var.master_allowed_remote_ipv6_ips)
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = "tcp"
+  port_range_min    = "6443"
+  port_range_max    = "6443"
+  remote_ip_prefix  = var.master_allowed_remote_ipv6_ips[count.index]
+  security_group_id = openstack_networking_secgroup_v2.k8s_master.id
+}
+
+resource "openstack_networking_secgroup_rule_v2" "k8s_master_ports_ipv6_ingress" {
+  count             = length(var.master_allowed_ports_ipv6)
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = lookup(var.master_allowed_ports_ipv6[count.index], "protocol", "tcp")
+  port_range_min    = lookup(var.master_allowed_ports_ipv6[count.index], "port_range_min")
+  port_range_max    = lookup(var.master_allowed_ports_ipv6[count.index], "port_range_max")
+  remote_ip_prefix  = lookup(var.master_allowed_ports_ipv6[count.index], "remote_ip_prefix", "::/0")
+  security_group_id = openstack_networking_secgroup_v2.k8s_master.id
+}
+
+resource "openstack_networking_secgroup_rule_v2" "master_egress_ipv6" {
+  count             = length(var.k8s_allowed_egress_ipv6_ips)
+  direction         = "egress"
+  ethertype         = "IPv6"
+  remote_ip_prefix  = var.k8s_allowed_egress_ipv6_ips[count.index]
+  security_group_id = openstack_networking_secgroup_v2.k8s_master.id
+}
+
 resource "openstack_networking_secgroup_v2" "bastion" {
   name                 = "${var.cluster_name}-bastion"
   count                = var.number_of_bastions != "" ? 1 : 0
@@ -99,6 +129,28 @@ resource "openstack_networking_secgroup_rule_v2" "k8s_bastion_ports" {
   security_group_id = openstack_networking_secgroup_v2.bastion[0].id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "bastion_ipv6_ingress" {
+  count             = var.number_of_bastions != "" ? length(var.bastion_allowed_remote_ipv6_ips) : 0
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = "tcp"
+  port_range_min    = "22"
+  port_range_max    = "22"
+  remote_ip_prefix  = var.bastion_allowed_remote_ipv6_ips[count.index]
+  security_group_id = openstack_networking_secgroup_v2.bastion[0].id
+}
+
+resource "openstack_networking_secgroup_rule_v2" "k8s_bastion_ports_ipv6_ingress" {
+  count             = length(var.bastion_allowed_ports_ipv6)
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = lookup(var.bastion_allowed_ports_ipv6[count.index], "protocol", "tcp")
+  port_range_min    = lookup(var.bastion_allowed_ports_ipv6[count.index], "port_range_min")
+  port_range_max    = lookup(var.bastion_allowed_ports_ipv6[count.index], "port_range_max")
+  remote_ip_prefix  = lookup(var.bastion_allowed_ports_ipv6[count.index], "remote_ip_prefix", "::/0")
+  security_group_id = openstack_networking_secgroup_v2.bastion[0].id
+}
+
 resource "openstack_networking_secgroup_v2" "k8s" {
   name                 = "${var.cluster_name}-k8s"
   description          = "${var.cluster_name} - Kubernetes"
@@ -112,6 +164,13 @@ resource "openstack_networking_secgroup_rule_v2" "k8s" {
   security_group_id = openstack_networking_secgroup_v2.k8s.id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "k8s_ipv6" {
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  remote_group_id   = openstack_networking_secgroup_v2.k8s.id
+  security_group_id = openstack_networking_secgroup_v2.k8s.id
+}
+
 resource "openstack_networking_secgroup_rule_v2" "k8s_allowed_remote_ips" {
   count             = length(var.k8s_allowed_remote_ips)
   direction         = "ingress"
@@ -123,6 +182,17 @@ resource "openstack_networking_secgroup_rule_v2" "k8s_allowed_remote_ips" {
   security_group_id = openstack_networking_secgroup_v2.k8s.id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "k8s_allowed_remote_ips_ipv6" {
+  count             = length(var.k8s_allowed_remote_ips_ipv6)
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = "tcp"
+  port_range_min    = "22"
+  port_range_max    = "22"
+  remote_ip_prefix  = var.k8s_allowed_remote_ips_ipv6[count.index]
+  security_group_id = openstack_networking_secgroup_v2.k8s.id
+}
+
 resource "openstack_networking_secgroup_rule_v2" "egress" {
   count             = length(var.k8s_allowed_egress_ips)
   direction         = "egress"
@@ -131,6 +201,14 @@ resource "openstack_networking_secgroup_rule_v2" "egress" {
   security_group_id = openstack_networking_secgroup_v2.k8s.id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "egress_ipv6" {
+  count             = length(var.k8s_allowed_egress_ipv6_ips)
+  direction         = "egress"
+  ethertype         = "IPv6"
+  remote_ip_prefix  = var.k8s_allowed_egress_ipv6_ips[count.index]
+  security_group_id = openstack_networking_secgroup_v2.k8s.id
+}
+
 resource "openstack_networking_secgroup_v2" "worker" {
   name                 = "${var.cluster_name}-k8s-worker"
   description          = "${var.cluster_name} - Kubernetes worker nodes"
@@ -155,6 +233,17 @@ resource "openstack_networking_secgroup_rule_v2" "worker" {
   security_group_id = openstack_networking_secgroup_v2.worker.id
 }
 
+resource "openstack_networking_secgroup_rule_v2" "worker_ipv6_ingress" {
+  count             = length(var.worker_allowed_ports_ipv6)
+  direction         = "ingress"
+  ethertype         = "IPv6"
+  protocol          = lookup(var.worker_allowed_ports_ipv6[count.index], "protocol", "tcp")
+  port_range_min    = lookup(var.worker_allowed_ports_ipv6[count.index], "port_range_min")
+  port_range_max    = lookup(var.worker_allowed_ports_ipv6[count.index], "port_range_max")
+  remote_ip_prefix  = lookup(var.worker_allowed_ports_ipv6[count.index], "remote_ip_prefix", "::/0")
+  security_group_id = openstack_networking_secgroup_v2.worker.id
+}
+
 resource "openstack_compute_servergroup_v2" "k8s_master" {
   count    = var.master_server_group_policy != "" ? 1 : 0
   name     = "k8s-master-srvgrp"
diff --git a/contrib/terraform/openstack/modules/compute/variables.tf b/contrib/terraform/openstack/modules/compute/variables.tf
index 1a78f503e..006cce9ef 100644
--- a/contrib/terraform/openstack/modules/compute/variables.tf
+++ b/contrib/terraform/openstack/modules/compute/variables.tf
@@ -104,18 +104,34 @@ variable "bastion_allowed_remote_ips" {
   type = list
 }
 
+variable "bastion_allowed_remote_ipv6_ips" {
+  type = list
+}
+
 variable "master_allowed_remote_ips" {
   type = list
 }
 
+variable "master_allowed_remote_ipv6_ips" {
+  type = list
+}
+
 variable "k8s_allowed_remote_ips" {
   type = list
 }
 
+variable "k8s_allowed_remote_ips_ipv6" {
+  type = list
+}
+
 variable "k8s_allowed_egress_ips" {
   type = list
 }
 
+variable "k8s_allowed_egress_ipv6_ips" {
+  type = list
+}
+
 variable "k8s_masters" {
   type = map(object({
     az                     = string
@@ -172,14 +188,26 @@ variable "master_allowed_ports" {
   type = list
 }
 
+variable "master_allowed_ports_ipv6" {
+  type = list
+}
+
 variable "worker_allowed_ports" {
   type = list
 }
 
+variable "worker_allowed_ports_ipv6" {
+  type = list
+}
+
 variable "bastion_allowed_ports" {
   type = list
 }
 
+variable "bastion_allowed_ports_ipv6" {
+  type = list
+}
+
 variable "use_access_ip" {}
 
 variable "master_server_group_policy" {
diff --git a/contrib/terraform/openstack/variables.tf b/contrib/terraform/openstack/variables.tf
index 4bb6efbfd..ef99c7713 100644
--- a/contrib/terraform/openstack/variables.tf
+++ b/contrib/terraform/openstack/variables.tf
@@ -220,30 +220,60 @@ variable "bastion_allowed_remote_ips" {
   default     = ["0.0.0.0/0"]
 }
 
+variable "bastion_allowed_remote_ipv6_ips" {
+  description = "An array of IPv6 CIDRs allowed to SSH to hosts"
+  type        = list(string)
+  default     = ["::/0"]
+}
+
 variable "master_allowed_remote_ips" {
   description = "An array of CIDRs allowed to access API of masters"
   type        = list(string)
   default     = ["0.0.0.0/0"]
 }
 
+variable "master_allowed_remote_ipv6_ips" {
+  description = "An array of IPv6 CIDRs allowed to access API of masters"
+  type        = list(string)
+  default     = ["::/0"]
+}
+
 variable "k8s_allowed_remote_ips" {
   description = "An array of CIDRs allowed to SSH to hosts"
   type        = list(string)
   default     = []
 }
 
+variable "k8s_allowed_remote_ips_ipv6" {
+  description = "An array of IPv6 CIDRs allowed to SSH to hosts"
+  type        = list(string)
+  default     = []
+}
+
 variable "k8s_allowed_egress_ips" {
   description = "An array of CIDRs allowed for egress traffic"
   type        = list(string)
   default     = ["0.0.0.0/0"]
 }
 
+variable "k8s_allowed_egress_ipv6_ips" {
+  description = "An array of CIDRs allowed for egress IPv6 traffic"
+  type        = list(string)
+  default     = ["::/0"]
+}
+
 variable "master_allowed_ports" {
   type = list(any)
 
   default = []
 }
 
+variable "master_allowed_ports_ipv6" {
+  type = list(any)
+
+  default = []
+}
+
 variable "worker_allowed_ports" {
   type = list(any)
 
@@ -257,12 +287,31 @@ variable "worker_allowed_ports" {
   ]
 }
 
+variable "worker_allowed_ports_ipv6" {
+  type = list(any)
+
+  default = [
+    {
+      "protocol"         = "tcp"
+      "port_range_min"   = 30000
+      "port_range_max"   = 32767
+      "remote_ip_prefix" = "::/0"
+    },
+  ]
+}
+
 variable "bastion_allowed_ports" {
   type = list(any)
 
   default = []
 }
 
+variable "bastion_allowed_ports_ipv6" {
+  type = list(any)
+
+  default = []
+}
+
 variable "use_access_ip" {
   default = 1
 }
-- 
GitLab