diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2b20ceed7d3bdf58fcf90232b297975ef4fac320..07ccec3490cd5be6ca0183fc9ed7467100f13acb 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -837,3 +837,4 @@ tf-apply-ovh:
     TF_VAR_flavor_k8s_master: "defa64c3-bd46-43b4-858a-d93bbae0a229" #s1-8
     TF_VAR_flavor_k8s_node: "defa64c3-bd46-43b4-858a-d93bbae0a229" #s1-8
     TF_VAR_image: "Ubuntu 18.04"
+    TF_VAR_k8s_allowed_remote_ips: '["0.0.0.0/0"]'
diff --git a/contrib/terraform/openstack/README.md b/contrib/terraform/openstack/README.md
index a488e37fb7c6bf26aaaf2eb8b76aa87a64a9eb80..c22c92e5c95a4c1530e27e1fde1c145e1b7fb026 100644
--- a/contrib/terraform/openstack/README.md
+++ b/contrib/terraform/openstack/README.md
@@ -243,6 +243,7 @@ For your cluster, edit `inventory/$CLUSTER/cluster.tf`.
 |`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 |
+|`k8s_allowed_remote_ips` | List of CIDR allowed to initiate a SSH connection, empty 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 |
 
 #### Terraform state files
diff --git a/contrib/terraform/openstack/kubespray.tf b/contrib/terraform/openstack/kubespray.tf
index 8ee77f5318bd4de6c1e4e59ecbe02b5a64a6cd11..93693e3cba075feec812f4f88e52da7a75e48704 100644
--- a/contrib/terraform/openstack/kubespray.tf
+++ b/contrib/terraform/openstack/kubespray.tf
@@ -52,6 +52,7 @@ module "compute" {
   k8s_node_fips                                = "${module.ips.k8s_node_fips}"
   bastion_fips                                 = "${module.ips.bastion_fips}"
   bastion_allowed_remote_ips                   = "${var.bastion_allowed_remote_ips}"
+  k8s_allowed_remote_ips                       = "${var.k8s_allowed_remote_ips}"
   supplementary_master_groups                  = "${var.supplementary_master_groups}"
   supplementary_node_groups                    = "${var.supplementary_node_groups}"
   worker_allowed_ports                         = "${var.worker_allowed_ports}"
diff --git a/contrib/terraform/openstack/modules/compute/main.tf b/contrib/terraform/openstack/modules/compute/main.tf
index 5870a51ab0274c28c3df5cc8d8b4491cafffdbd1..fa2d76c5a5c704781ab99819b314503f3797992c 100644
--- a/contrib/terraform/openstack/modules/compute/main.tf
+++ b/contrib/terraform/openstack/modules/compute/main.tf
@@ -47,6 +47,17 @@ resource "openstack_networking_secgroup_rule_v2" "k8s" {
   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"
+  ethertype         = "IPv4"
+  protocol          = "tcp"
+  port_range_min    = "22"
+  port_range_max    = "22"
+  remote_ip_prefix  = "${var.k8s_allowed_remote_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"
@@ -102,20 +113,17 @@ resource "openstack_compute_instance_v2" "k8s_master" {
     name = "${var.network_name}"
   }
 
-  # The join() hack is described here: https://github.com/hashicorp/terraform/issues/11566
-  # As a workaround for creating "dynamic" lists (when, for example, no bastion host is created)
-
-  security_groups = ["${compact(list(
-    openstack_networking_secgroup_v2.k8s_master.name,
-    join(" ", openstack_networking_secgroup_v2.bastion.*.id),
-    openstack_networking_secgroup_v2.k8s.name,
+  security_groups = ["${openstack_networking_secgroup_v2.k8s_master.name}",
+    "${openstack_networking_secgroup_v2.k8s.name}",
     "default",
-   ))}"]
+  ]
+
   metadata = {
     ssh_user         = "${var.ssh_user}"
     kubespray_groups = "etcd,kube-master,${var.supplementary_master_groups},k8s-cluster,vault"
     depends_on       = "${var.network_id}"
   }
+
   provisioner "local-exec" {
     command = "sed s/USER/${var.ssh_user}/ contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element( concat(var.bastion_fips, var.k8s_master_fips), 0)}/ > contrib/terraform/group_vars/no-floating.yml"
   }
@@ -133,11 +141,10 @@ resource "openstack_compute_instance_v2" "k8s_master_no_etcd" {
     name = "${var.network_name}"
   }
 
-  security_groups = ["${compact(list(
-    openstack_networking_secgroup_v2.k8s_master.name,
-    join(" ", openstack_networking_secgroup_v2.bastion.*.id),
-    openstack_networking_secgroup_v2.k8s.name,
-   ))}"]
+  security_groups = ["${openstack_networking_secgroup_v2.k8s_master.name}",
+    "${openstack_networking_secgroup_v2.k8s.name}",
+    "default",
+  ]
 
   metadata = {
     ssh_user         = "${var.ssh_user}"
@@ -230,12 +237,10 @@ resource "openstack_compute_instance_v2" "k8s_node" {
     name = "${var.network_name}"
   }
 
-  security_groups = ["${compact(list(
-    openstack_networking_secgroup_v2.k8s_master.name,
-    join(" ", openstack_networking_secgroup_v2.bastion.*.id),
-    openstack_networking_secgroup_v2.k8s.name,
+  security_groups = ["${openstack_networking_secgroup_v2.k8s.name}",
+    "${openstack_networking_secgroup_v2.worker.name}",
     "default",
-   ))}"]
+  ]
 
   metadata = {
     ssh_user         = "${var.ssh_user}"
diff --git a/contrib/terraform/openstack/modules/compute/variables.tf b/contrib/terraform/openstack/modules/compute/variables.tf
index 7c004fdc435aa906bbb967e9db9decfab9340f0c..75b5e5e6d79f3276752c7de88cf6f20a75d452a0 100644
--- a/contrib/terraform/openstack/modules/compute/variables.tf
+++ b/contrib/terraform/openstack/modules/compute/variables.tf
@@ -66,6 +66,10 @@ variable "bastion_allowed_remote_ips" {
   type = "list"
 }
 
+variable "k8s_allowed_remote_ips" {
+  type = "list"
+}
+
 variable "supplementary_master_groups" {
   default = ""
 }
diff --git a/contrib/terraform/openstack/variables.tf b/contrib/terraform/openstack/variables.tf
index 788eaab0cc5c691347cb2fcca483284f7617e8fa..8d53b9b4416d6beab45b9b606cd10d871d3c3fae 100644
--- a/contrib/terraform/openstack/variables.tf
+++ b/contrib/terraform/openstack/variables.tf
@@ -145,6 +145,12 @@ variable "bastion_allowed_remote_ips" {
   default     = ["0.0.0.0/0"]
 }
 
+variable "k8s_allowed_remote_ips" {
+  description = "An array of CIDRs allowed to SSH to hosts"
+  type        = "list"
+  default     = []
+}
+
 variable "worker_allowed_ports" {
   type = "list"