diff --git a/README.md b/README.md
index f7ebb33cdb7881912644f9c10a107f5eb3af5ab4..cb17eb28b39471f9ed59f354d7d7ced2f69e6396 100644
--- a/README.md
+++ b/README.md
@@ -52,13 +52,7 @@ No modules.
 | [openstack_networking_router_interface_v2.router_available_interface](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_router_interface_v2) | resource |
 | [openstack_networking_router_interface_v2.router_default_interface](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_router_interface_v2) | resource |
 | [openstack_networking_router_v2.router_default](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_router_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.alltcp4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.alludp4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.http4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.https4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.icmp4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.lb4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
-| [openstack_networking_secgroup_rule_v2.ssh4](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
+| [openstack_networking_secgroup_rule_v2.secgroup_rules](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
 | [openstack_networking_secgroup_v2.secgroup_default](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_v2) | resource |
 | [openstack_networking_subnet_v2.subnet_default](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_subnet_v2) | resource |
 | [openstack_images_image_v2.nodes_image](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/data-sources/images_image_v2) | data source |
@@ -78,6 +72,7 @@ No modules.
 | <a name="input_control_nodes_name"></a> [control\_nodes\_name](#input\_control\_nodes\_name) | Name of the nodes. Must match [a-zA-Z0-9-]+ regexp. | `string` | `"control"` | no |
 | <a name="input_control_nodes_volume_size"></a> [control\_nodes\_volume\_size](#input\_control\_nodes\_volume\_size) | The size of the volume to create (in gigabytes) for root filesystem. | `string` | `"30"` | no |
 | <a name="input_create_lb_kube_api"></a> [create\_lb\_kube\_api](#input\_create\_lb\_kube\_api) | Create Load Balancer for kube-api | `bool` | `true` | no |
+| <a name="input_custom_security_group_rules"></a> [custom\_security\_group\_rules](#input\_custom\_security\_group\_rules) | Custom security group rules to override the defaults | <pre>map(object({<br>    description      = string<br>    direction        = string<br>    ethertype        = string<br>    protocol         = string<br>    port_range_min   = number<br>    port_range_max   = number<br>    remote_ip_prefix = string<br>  }))</pre> | `{}` | no |
 | <a name="input_infra_name"></a> [infra\_name](#input\_infra\_name) | Infrastructure (profile) name. Used as a name prefix. Must match [a-zA-Z0-9-]+ regexp. | `string` | `"general-tf-demo"` | no |
 | <a name="input_internal_network_cidr"></a> [internal\_network\_cidr](#input\_internal\_network\_cidr) | Internal network address, use CIDR notation | `string` | `"10.0.0.0/24"` | no |
 | <a name="input_internal_network_creation_enable"></a> [internal\_network\_creation\_enable](#input\_internal\_network\_creation\_enable) | Create dedicated internal network. true/false ~ create new / reuse existing personal network | `bool` | `true` | no |
@@ -91,6 +86,7 @@ No modules.
 | <a name="input_lb_kube_api_member_port"></a> [lb\_kube\_api\_member\_port](#input\_lb\_kube\_api\_member\_port) | Port number where kube-api listens. | `number` | `6443` | no |
 | <a name="input_nodes_image"></a> [nodes\_image](#input\_nodes\_image) | Image used for both control and worker servers | `string` | `"ubuntu-jammy-x86_64"` | no |
 | <a name="input_public_external_network"></a> [public\_external\_network](#input\_public\_external\_network) | Cloud public external network pool | `string` | `"public-cesnet-195-113-167-GROUP"` | no |
+| <a name="input_remove_rules"></a> [remove\_rules](#input\_remove\_rules) | List of default rule keys to be removed | `list(string)` | `[]` | no |
 | <a name="input_router_creation_enable"></a> [router\_creation\_enable](#input\_router\_creation\_enable) | Create dedicated router instance. true/false ~ create new / reuse existing personal router | `bool` | `true` | no |
 | <a name="input_ssh_public_key"></a> [ssh\_public\_key](#input\_ssh\_public\_key) | n/a | `string` | `"~/.ssh/id_rsa.pub"` | no |
 | <a name="input_ssh_user_name"></a> [ssh\_user\_name](#input\_ssh\_user\_name) | n/a | `string` | `"ubuntu"` | no |
diff --git a/locals.tf b/locals.tf
index 986c295ec4c3e70fd99c37e7b0c2b0eab5614742..c0bf6caae8e2a1e239ac1b947d75306bcc2294d0 100644
--- a/locals.tf
+++ b/locals.tf
@@ -9,4 +9,87 @@ locals {
       }
     ]
   ])
+
+  # Filter out any default rules that are listed in remove_rules
+  filtered_default_security_group_rules = {
+    for key, value in local.default_security_group_rules :
+    key => value if !contains(var.remove_rules, key)
+  }
+
+  # Combine default and custom rules, allowing custom rules to override defaults
+  final_security_group_rules = merge(local.filtered_default_security_group_rules, var.custom_security_group_rules)
+
+  default_security_group_rules = {
+    # Allow all internal TCP & UDP
+    alltcp = {
+      description      = "Allow all internal TCP communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "tcp"
+      port_range_min   = 0
+      port_range_max   = 0
+      remote_ip_prefix = "${var.internal_network_cidr}"
+    }
+    alludp = {
+      description      = "Allow all internal UDP communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "udp"
+      port_range_min   = 0
+      port_range_max   = 0
+      remote_ip_prefix = "${var.internal_network_cidr}"
+    }
+
+    # External communication
+    # HTTP(S)
+    https4 = {
+      description      = "Allow external HTTPS communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "tcp"
+      port_range_min   = 443
+      port_range_max   = 443
+      remote_ip_prefix = "0.0.0.0/0"
+    }
+    http4 = {
+      description      = "Allow external HTTP communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "tcp"
+      port_range_min   = 80
+      port_range_max   = 80
+      remote_ip_prefix = "0.0.0.0/0"
+    }
+
+    # SSH
+    ssh4 = {
+      description      = "Allow external SSH communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "tcp"
+      port_range_min   = 22
+      port_range_max   = 22
+      remote_ip_prefix = "0.0.0.0/0"
+    }
+    # ICMP
+    icmp4 = {
+      description      = "Allow external ICMP communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "icmp"
+      port_range_min   = 0
+      port_range_max   = 0
+      remote_ip_prefix = "0.0.0.0/0"
+    }
+    # LB
+    lb4 = {
+      description      = "Allow communication to Kubernetes cluster communication."
+      direction        = "ingress"
+      ethertype        = "IPv4"
+      protocol         = "tcp"
+      port_range_min   = var.lb_kube_api_member_port
+      port_range_max   = var.lb_kube_api_member_port
+      remote_ip_prefix = "0.0.0.0/0"
+    }
+  }
 }
diff --git a/secgroup_rules.tf b/secgroup_rules.tf
index 6a39561955b9b320e47da83abcc77de427032f5f..b34a0f2ef614fa165a580b2503210946223f1d05 100644
--- a/secgroup_rules.tf
+++ b/secgroup_rules.tf
@@ -7,78 +7,15 @@ resource "openstack_networking_secgroup_v2" "secgroup_default" {
   description = "${var.infra_name} Security group"
 }
 
-# Allow all internal TCP & UDP
-resource "openstack_networking_secgroup_rule_v2" "alltcp4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "tcp"
-  port_range_min    = 0 # 0 means ANY
-  port_range_max    = 0 # 0 means ANY
-  remote_ip_prefix  = var.internal_network_cidr
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-resource "openstack_networking_secgroup_rule_v2" "alludp4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "udp"
-  port_range_min    = 0 # 0 means ANY
-  port_range_max    = 0 # 0 means ANY
-  remote_ip_prefix  = var.internal_network_cidr
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-# External communication
-# HTTP(S)
-resource "openstack_networking_secgroup_rule_v2" "https4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "tcp"
-  port_range_min    = 443
-  port_range_max    = 443
-  remote_ip_prefix  = "0.0.0.0/0"
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-resource "openstack_networking_secgroup_rule_v2" "http4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "tcp"
-  port_range_min    = 80
-  port_range_max    = 80
-  remote_ip_prefix  = "0.0.0.0/0"
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-# ICMP
-resource "openstack_networking_secgroup_rule_v2" "icmp4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "icmp"
-  port_range_min    = 0
-  port_range_max    = 0
-  remote_ip_prefix  = "0.0.0.0/0"
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-# SSH
-resource "openstack_networking_secgroup_rule_v2" "ssh4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "tcp"
-  port_range_min    = 22
-  port_range_max    = 22
-  remote_ip_prefix  = "0.0.0.0/0"
-  security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
-}
-
-# LB
-resource "openstack_networking_secgroup_rule_v2" "lb4" {
-  direction         = "ingress"
-  ethertype         = "IPv4"
-  protocol          = "tcp"
-  port_range_min    = var.lb_kube_api_member_port
-  port_range_max    = var.lb_kube_api_member_port
-  remote_ip_prefix  = "0.0.0.0/0"
+resource "openstack_networking_secgroup_rule_v2" "secgroup_rules" {
+  for_each = local.final_security_group_rules
+
+  description       = each.value.description
+  direction         = each.value.direction
+  ethertype         = each.value.ethertype
+  protocol          = each.value.protocol
+  port_range_min    = each.value.port_range_min
+  port_range_max    = each.value.port_range_max
+  remote_ip_prefix  = each.value.remote_ip_prefix
   security_group_id = openstack_networking_secgroup_v2.secgroup_default.id
 }
diff --git a/variables.tf b/variables.tf
index 83441f7cad9130723ce6a40e01d9c044ff7bfb12..ecc753d399a6979edab456017ccbbe369da2fd61 100644
--- a/variables.tf
+++ b/variables.tf
@@ -144,3 +144,28 @@ variable "lb_kube_api_member_port" {
   type        = number
   default     = 6443
 }
+
+#################################
+# Security Groups rules setting #
+#################################
+
+variable "custom_security_group_rules" {
+  description = "Custom security group rules to override the defaults"
+  type = map(object({
+    description      = string
+    direction        = string
+    ethertype        = string
+    protocol         = string
+    port_range_min   = number
+    port_range_max   = number
+    remote_ip_prefix = string
+  }))
+  default = {}
+}
+
+# Variable to specify which default rules to remove
+variable "remove_rules" {
+  description = "List of default rule keys to be removed"
+  type        = list(string)
+  default     = []
+}