diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/README.md b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/README.md
new file mode 100644
index 00000000000..7c3fcd86a6a
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/README.md
@@ -0,0 +1,127 @@
+# _TF: IBM K8s s390x Build Cluster_
+These terraform resources define a IBM Cloud project containing a s390xVS cluster intended to serve as a "build cluster" for prow.k8s.io.
+
+---
+## Initial Setup
+
+### Supporting infrastructure
+
+#### Deploy k8s-infra-setup resources
+
+- this covers things like Resource Group, s390x Virtual Server Instances, Virtual Private Cloud, IBM Cloud Secret Manager Secrets, etc.
+- Once the deployment successfully completes, the `secrets_manager_id` will be generated and should be used in the subsequent steps.
+
+---
+#### Deploy k8s-s390x-build-cluster resources
+
+**1. Navigate to the correct directory**
+
 You need to be in the `k8s-s390x-build-cluster` directory to run the automation.
+
+**2. Export COS Secrets**
+
 Export `access_key` and `secret_key` as environment variables.
+```
+export AWS_ACCESS_KEY_ID=""
+export AWS_SECRET_ACCESS_KEY=""
+```
+
+**3. Initialize Terraform**
+
 Execute the following command to initialize Terraform in your project directory. This command will download the necessary provider plugins and prepare the working environment.
+```
+terraform init -reconfigure
+```
+
+**4. Check the `variables.tf` file**
+
 Open the `variables.tf` file to review all the available variables. This file lists all customizable inputs for your Terraform configuration.
+
+`ibmcloud_api_key`, `secrets_manager_id` are the only required variables that you must set in order to proceed. You can set this key either by adding it to your `var.tfvars` file or by exporting it as an environment variable.
+
+**Option 1:** Set in `var.tfvars` file
+Create `var.tfvars` file and set the following variables in `var.tfvars` file:
+```
+ibmcloud_api_key    = ""
+secrets_manager_id  = ""
+```
+Tip: To get the secrets_manager_id (GUID) for IBM Cloud Secrets Manager instance:
+```
+ibmcloud resource service-instances --service-name secrets-manager --output JSON | \
+jq -r '.[] | select(.name | contains("k8s-s390x")) | .guid'
+```
+**Option 2:** Export as an environment variable
+Alternatively, you can export above as an environment variable before running Terraform:
+```
+export TF_VAR_ibmcloud_api_key=""
+export TF_VAR_secrets_manager_id=$(ibmcloud resource service-instances --service-name secrets-manager --output JSON | \
+jq -r '.[] | select(.name | contains("k8s-s390x")) | .guid')
+```
+
+**5. Run Terraform Apply**
+
 After setting the necessary variables (particularly the API_KEY), execute the following command to apply the Terraform configuration and provision the infrastructure:
+```
+terraform apply -var-file var.tfvars
+```
+Terraform will display a plan of the actions it will take, and you'll be prompted to confirm the execution. Type `yes` to proceed.
+
+**6. Get Output Information**
+
 Once the infrastructure has been provisioned, use the terraform output command to list details about the provisioned resources.
+```
+terraform output
+```
+
+**7. Set up the Kubernetes cluster using ansible**
+Clone the repository `https://github.com/kubernetes-sigs/provider-ibmcloud-test-infra` and change the directory to `kubetest2-tf/data/k8s-ansible`:
+```
+cd kubetest2-tf/data/k8s-ansible
+```
+
+**8. Install ansible on the deployer VM**
+```
+dnf install ansible -y
+```
+
+**9. Update the fields under `group_vars/all` to include the Kubernetes version to install**
+
 The following lines will update the version to the latest stable release of Kubernetes. You can modify it accordingly to set up the CI (alpha) version.
+```
+K8S_VERSION=$(curl -Ls https://dl.k8s.io/release/stable.txt)
+LOADBALANCER_EP=
+sed -i \
+-e "s/^directory: .*/directory: release/" \
+-e "s/build_version: .*/build_version: $K8S_VERSION/" \
+-e "s/release_marker: .*/release_marker: $K8S_VERSION/" \
+-e "s/loadbalancer: .*/loadbalancer: $LOADBALANCER_EP/" group_vars/all
+```
+
+**10. Update the fields under `examples/k8s-build-cluster/hosts.yml` to contain IP addresses of the VMs to set up Kubernetes**
+```
+For example:
+
+[bastion]
+56.77.34.6
+
+[masters]
+192.168.100.3
+192.168.100.4
+
+[workers]
+192.168.100.5
+192.168.100.6
+192.168.100.7
+
+[workers:vars]
+ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -i  -q root@56.77.34.6" -i '
+
+[masters:vars]
+ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -i  -q root@56.77.34.6" -i '
+```
+
+**11. Update the fields under `group_vars/bastion_configuration` to contain the information of the private network.**
+```
+For example:
+
+bastion_private_gateway: 192.168.100.1
+bastion_private_ip: 192.168.100.2
+```
+
+**12. Trigger the installation using ansible**
+```
+ansible-playbook -v -i examples/k8s-build-cluster/hosts.yml install-k8s-ha.yaml -e @group_vars/bastion_configuration --extra-vars @group_vars/all
+```
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/bastion.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/bastion.tf
new file mode 100644
index 00000000000..3d3be5f277c
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/bastion.tf
@@ -0,0 +1,98 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+locals {
+  bastion_nodes = {
+    "primary" = {
+      profile = var.bastion_profile
+      boot_volume = {
+        size = var.bastion_boot_volume_size
+      }
+    }
+  }
+}
+
+resource "ibm_is_instance" "bastion" {
+  for_each       = local.bastion_nodes
+  name           = "bastion-s390x-${each.key}"
+  vpc            = data.ibm_is_vpc.vpc.id
+  zone           = var.zone
+  profile        = each.value.profile
+  image          = var.image_id
+  keys           = [ibm_is_ssh_key.k8s_ssh_key.id]
+  resource_group = data.ibm_resource_group.resource_group.id
+
+  primary_network_interface {
+    name            = "public-nic-${each.key}"
+    subnet          = data.ibm_is_subnet.subnet.id
+    security_groups = [data.ibm_is_security_group.bastion.id]
+  }
+
+  boot_volume {
+    name = "boot-vol-bastion-${each.key}"
+    size = each.value.boot_volume.size
+  }
+
+  user_data = <<-EOF
+              #cloud-config
+              package_update: true
+              package_upgrade: true
+              packages:
+                - tcpdump
+                - net-tools
+                - iptables-persistent
+              write_files:
+                - path: /etc/ssh/sshd_config.d/99-bastion.conf
+                  content: |
+                    AllowTcpForwarding yes
+                    GatewayPorts yes
+                    PermitTunnel yes
+                    PermitRootLogin prohibit-password
+                    PasswordAuthentication no
+                    ClientAliveInterval 120
+                    ClientAliveCountMax 3
+                    MaxSessions 50
+                    MaxStartups 50:30:100
+                - path: /etc/systemd/network/10-eth1.network
+                  content: |
+                    [Match]
+                    Name=eth1
+                    [Network]
+                    Address=${data.ibm_is_subnet.subnet.ipv4_cidr_block}
+                    DNS=8.8.8.8
+                    DNS=8.8.4.4
+              runcmd:
+                - [sysctl, -w, net.ipv4.ip_forward=1]
+                - [echo, "net.ipv4.ip_forward = 1", ">>", /etc/sysctl.conf]
+                - [iptables, -t, nat, -A, POSTROUTING, -o, eth0, -j, MASQUERADE]
+                - [iptables, -A, FORWARD, -i, eth1, -o, eth0, -j, ACCEPT]
+                - [iptables, -A, FORWARD, -i, eth0, -o, eth1, -m, state, --state, RELATED,ESTABLISHED, -j, ACCEPT]
+                - [netfilter-persistent, save]
+                - [systemctl, restart, systemd-networkd]
+                - [systemctl, restart, sshd]
+                - [hostnamectl, set-hostname, "bastion-s390x-${each.key}.s390x-vpc.cloud.ibm.com"]
+                - [echo, "bastion-s390x-${each.key}.s390x-vpc.cloud.ibm.com", ">", /etc/hostname]
+                - [sed, -i, "s/^127.0.1.1.*/127.0.1.1\tbastion-s390x-${each.key}.s390x-vpc.cloud.ibm.com/", /etc/hosts]
+                - [touch, /var/lib/cloud/instance/bastion-setup-success]
+              EOF
+}
+
+resource "ibm_is_floating_ip" "bastion_fip" {
+  for_each       = ibm_is_instance.bastion
+  name           = "bastion-fip-${each.key}"
+  target         = each.value.primary_network_interface[0].id
+  resource_group = data.ibm_resource_group.resource_group.id
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/data.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/data.tf
new file mode 100644
index 00000000000..069f3827350
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/data.tf
@@ -0,0 +1,55 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+data "ibm_resource_group" "resource_group" {
+  name = "rg-build-cluster"
+}
+
+data "ibm_is_vpc" "vpc" {
+  name = "k8s-s390x-vpc"
+}
+
+data "ibm_is_subnet" "subnet" {
+  name = "k8s-s390x-subnet"
+}
+
+data "ibm_is_security_group" "bastion" {
+  name = "k8s-vpc-s390x-bastion-sg"
+  vpc  = data.ibm_is_vpc.vpc.id
+}
+
+data "ibm_is_security_group" "control_plane_sg" {
+  name = "k8s-vpc-s390x-control-plane-sg"
+  vpc  = data.ibm_is_vpc.vpc.id
+}
+
+data "ibm_is_security_group" "worker_sg" {
+  name = "k8s-vpc-s390x-worker-sg"
+  vpc  = data.ibm_is_vpc.vpc.id
+}
+
+data "ibm_sm_arbitrary_secret" "ssh_private_key" {
+  instance_id       = var.secrets_manager_id
+  region            = var.region
+  name              = "zvsi-ssh-private-key"
+  secret_group_name = "default"
+}
+
+data "ibm_sm_arbitrary_secret" "ssh_public_key" {
+  instance_id       = var.secrets_manager_id
+  region            = var.region
+  name              = "zvsi-ssh-public-key"
+  secret_group_name = "default"
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/load_balancer.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/load_balancer.tf
new file mode 100644
index 00000000000..d520c2472c3
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/load_balancer.tf
@@ -0,0 +1,51 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+resource "ibm_is_lb" "public" {
+  name            = "k8s-s390x-ci"
+  type            = "public"
+  subnets         = [data.ibm_is_subnet.subnet.id]
+  resource_group  = data.ibm_resource_group.resource_group.id
+  security_groups = [data.ibm_is_security_group.control_plane_sg.id]
+}
+
+resource "ibm_is_lb_pool" "k8s_api_pool" {
+  name                = "k8s-api-server-pool"
+  lb                  = ibm_is_lb.public.id
+  protocol            = "tcp"
+  algorithm           = "round_robin"
+  health_delay        = 5
+  health_retries      = 2
+  health_timeout      = 2
+  health_type         = "tcp"
+  health_monitor_url  = "/"
+  health_monitor_port = var.api_server_port
+}
+
+resource "ibm_is_lb_listener" "k8s_api_listener" {
+  lb           = ibm_is_lb.public.id
+  protocol     = "tcp"
+  port         = var.api_server_port
+  default_pool = ibm_is_lb_pool.k8s_api_pool.pool_id
+}
+
+resource "ibm_is_lb_pool_member" "k8s_api_members" {
+  for_each = ibm_is_instance.control_plane
+
+  lb             = ibm_is_lb.public.id
+  pool           = ibm_is_lb_pool.k8s_api_pool.pool_id
+  port           = var.api_server_port
+  target_address = each.value.primary_network_interface[0].primary_ipv4_address
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/nodes.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/nodes.tf
new file mode 100644
index 00000000000..511d480b3f0
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/nodes.tf
@@ -0,0 +1,85 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+locals {
+  control_plane_nodes = {
+    for idx in range(1, var.control_plane_node_count + 1) :
+    "${idx}" => {
+      profile = var.control_plane_node_profile
+      boot_volume = {
+        size = var.control_plane_boot_volume_size
+      }
+    }
+  }
+
+  compute_nodes = {
+    for idx in range(1, var.compute_node_count + 1) :
+    "${idx}" => {
+      profile = var.compute_node_profile
+      boot_volume = {
+        size = var.compute_boot_volume_size
+      }
+    }
+  }
+}
+resource "ibm_is_ssh_key" "k8s_ssh_key" {
+  name           = "k8s-s390x-ssh-key"
+  public_key     = data.ibm_sm_arbitrary_secret.ssh_public_key.payload
+  resource_group = data.ibm_resource_group.resource_group.id
+}
+
+resource "ibm_is_instance" "control_plane" {
+  for_each = local.control_plane_nodes
+
+  name           = "control-plane-s390x-${each.key}"
+  vpc            = data.ibm_is_vpc.vpc.id
+  zone           = var.zone
+  profile        = each.value.profile
+  image          = var.image_id
+  keys           = [ibm_is_ssh_key.k8s_ssh_key.id]
+  resource_group = data.ibm_resource_group.resource_group.id
+
+  primary_network_interface {
+    subnet          = data.ibm_is_subnet.subnet.id
+    security_groups = [data.ibm_is_security_group.control_plane_sg.id]
+  }
+
+  boot_volume {
+    name = "boot-vol-cp-s390x-${each.key}"
+    size = each.value.boot_volume.size
+  }
+}
+
+resource "ibm_is_instance" "compute" {
+  for_each = local.compute_nodes
+
+  name           = "worker-s390x-${each.key}"
+  vpc            = data.ibm_is_vpc.vpc.id
+  zone           = var.zone
+  profile        = each.value.profile
+  image          = var.image_id
+  keys           = [ibm_is_ssh_key.k8s_ssh_key.id]
+  resource_group = data.ibm_resource_group.resource_group.id
+
+  primary_network_interface {
+    subnet          = data.ibm_is_subnet.subnet.id
+    security_groups = [data.ibm_is_security_group.worker_sg.id]
+  }
+
+  boot_volume {
+    name = "boot-vol-worker-s390x-${each.key}"
+    size = each.value.boot_volume.size
+  }
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/outputs.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/outputs.tf
new file mode 100644
index 00000000000..35db025e621
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/outputs.tf
@@ -0,0 +1,43 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+output "bastion_private_ips_map" {
+  description = "Private IP addresses of the bastion hosts"
+  value       = { for k, instance in ibm_is_instance.bastion : k => instance.primary_network_interface[0].primary_ipv4_address }
+}
+
+output "bastion_public_ips_map" {
+  description = "Public IP addresses of the bastion hosts, keyed by instance name"
+  value       = { for k, fip in ibm_is_floating_ip.bastion_fip : k => fip.address }
+}
+
+output "control_plane_node_ips_map" {
+  description = "Private IP addresses of the control plane nodes, keyed by node name"
+  value       = { for k, instance in ibm_is_instance.control_plane : k => instance.primary_network_interface[0].primary_ipv4_address }
+}
+
+output "worker_node_ips_map" {
+  description = "Private IP addresses of the worker nodes, keyed by node name"
+  value       = { for k, instance in ibm_is_instance.compute : k => instance.primary_network_interface[0].primary_ipv4_address }
+}
+
+output "api_load_balancer_hostname" {
+  description = "Hostname of the Kubernetes API load balancer"
+  value       = ibm_is_lb.public.hostname
+}
+output "subnet_cidr" {
+  description = "CIDR block of the public subnet"
+  value       = data.ibm_is_subnet.subnet.ipv4_cidr_block
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/providers.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/providers.tf
new file mode 100644
index 00000000000..aca0b026bf7
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/providers.tf
@@ -0,0 +1,32 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+locals {
+  key    = var.ibmcloud_api_key
+  region = "eu-de"
+  zone   = "eu-de-1"
+}
+
+provider "ibm" {
+  ibmcloud_api_key = local.key
+  region           = local.region
+  zone             = local.zone
+}
+
+provider "ibm" {
+  alias            = "vpc"
+  ibmcloud_api_key = local.key
+  region           = "eu-de"
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/variables.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/variables.tf
new file mode 100644
index 00000000000..faa5590aa30
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/variables.tf
@@ -0,0 +1,121 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+variable "ibmcloud_api_key" {
+  type        = string
+  description = "IBM Cloud API key"
+  sensitive   = true
+}
+
+variable "region" {
+  type        = string
+  description = "IBM Cloud region"
+  default     = "eu-de"
+}
+
+variable "zone" {
+  type        = string
+  description = "IBM Cloud zone"
+  default     = "eu-de-1"
+}
+
+variable "image_id" {
+  type        = string
+  description = "Image ID for instances"
+  default     = "r010-bdd9c78f-4a2f-441f-a375-2ed288dcad15"
+}
+
+variable "keypair_name" {
+  type        = string
+  description = "SSH key pair name"
+  default     = "k8s-sshkey"
+}
+
+variable "secrets_manager_id" {
+  type        = string
+  description = "The instance ID of your secrets manager"
+  default     = ""
+
+  validation {
+    condition     = var.secrets_manager_id != ""
+    error_message = "The secrets_manager_id is required and cannot be empty."
+  }
+}
+
+variable "control_plane_node_count" {
+  description = "Number of control plane nodes to create"
+  type        = number
+  default     = 5
+}
+
+variable "control_plane_node_profile" {
+  description = "The profile to use for all control plane nodes"
+  type        = string
+  default     = "bz2-8x32"
+}
+
+variable "control_plane_boot_volume_size" {
+  description = "The boot volume size (in GB) for all control plane nodes"
+  type        = number
+  default     = 100
+}
+
+variable "compute_node_count" {
+  description = "Number of compute worker nodes to create"
+  type        = number
+  default     = 10
+}
+
+variable "compute_node_profile" {
+  description = "The profile to use for all compute nodes"
+  type        = string
+  default     = "bz2-8x32"
+}
+
+variable "compute_boot_volume_size" {
+  description = "The boot volume size (in GB) for all compute nodes"
+  type        = number
+  default     = 100
+}
+
+variable "connection_timeout" {
+  description = "Timeout in minutes for SSH connections"
+  type        = number
+  default     = 2
+}
+
+variable "bastion_boot_volume_size" {
+  description = "Size of the bastion boot volume in GB"
+  type        = number
+  default     = 100
+}
+
+variable "bastion_private_ip" {
+  description = "Private IP address for the bastion's secondary interface"
+  type        = string
+  default     = "192.168.100.10"
+}
+
+variable "bastion_profile" {
+  description = "Instance profile for the bastion host"
+  type        = string
+  default     = "bz2-8x32"
+}
+
+variable "api_server_port" {
+  description = "Port for the Kubernetes API server"
+  type        = number
+  default     = 6443
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-build-cluster/versions.tf b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/versions.tf
new file mode 100644
index 00000000000..f281b75ec98
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-build-cluster/versions.tf
@@ -0,0 +1,42 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+terraform {
+  backend "s3" {
+    bucket                      = "k8s-z-infra-tf-states"
+    key                         = "k8s-s390x-build-cluster/terraform.tfstate"
+    region                      = "eu-geo"
+    skip_region_validation      = true
+    skip_credentials_validation = true
+    endpoints = {
+      s3 = "https://s3.eu.cloud-object-storage.appdomain.cloud"
+    }
+  }
+  required_providers {
+    ibm = {
+      source  = "IBM-Cloud/ibm"
+      version = "~> 1.82.0"
+    }
+    time = {
+      source  = "hashicorp/time"
+      version = "~> 0.13.0"
+    }
+    null = {
+      source  = "hashicorp/null"
+      version = "~> 3.2.0"
+    }
+  }
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/README.md b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/README.md
new file mode 100644
index 00000000000..e69a5a4acbe
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/README.md
@@ -0,0 +1,55 @@
+# _TF: IBM K8s Account Infrastructure_
+This Terraform configuration sets up an organized structure for deploying various IBM Cloud resources using following modules. 
+
+## Modules Used:
+- **vpc**: IBM Cloud VPC, subnets, and networking components
+- **secrets_manager**: IBM Secrets Manager for credential storage
+- **resource_group**: IBM Resource Group management
+
+---
+# To run the automation, follow these steps in order:
+
+**1. Navigate to the correct directory**
+
 You need to be in the `k8s-s390x-infra-setup` directory to run the automation.
+
+**2. Export COS Secrets**
+
 Export `access_key` and `secret_key` as environment variables.
+```
+export AWS_ACCESS_KEY_ID=""
+export AWS_SECRET_ACCESS_KEY=""
+```
+**3. Initialize Terraform**
+
 Execute the following command to initialize Terraform in your project directory. This command will download the necessary provider plugins and prepare the working environment.
+```
+terraform init -upgrade
+```
+
+**4. Check the `variables.tf` file**
+
 Open the `variables.tf` file to review all the available variables. This file lists all customizable inputs for your Terraform configuration.
+
+`ibmcloud_api_key` is the only required variable that you must set in order to proceed. You can set this key either by adding it to your `var.tfvars` file or by exporting it as an environment variable.
+
+**Option 1:** Set in `var.tfvars` file
+Add the following line to the `var.tfvars` file:
+```
+ibmcloud_api_key = ""
+```
+
+**Option 2:** Export as an environment variable
+Alternatively, you can export the ibmcloud_api_key as an environment variable before running Terraform:
+```
+export TF_VAR_ibmcloud_api_key=""
+```
+
+**5. Run Terraform Apply**
+
 After setting the necessary variables (particularly the API_KEY), execute the following command to apply the Terraform configuration and provision the infrastructure:
+```
+terraform apply -var-file var.tfvars
+```
+Terraform will display a plan of the actions it will take, and you'll be prompted to confirm the execution. Type `yes` to proceed.
+
+**6 .Get Output Information**
+
 Once the infrastructure has been provisioned, use the terraform output command to list details about the provisioned resources.
+```
+terraform output
+```
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/main.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/main.tf
new file mode 100644
index 00000000000..44d076ab914
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/main.tf
@@ -0,0 +1,31 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+resource "ibm_resource_group" "build_resource_group" {
+  name = "rg-build-cluster"
+}
+
+module "secrets_manager" {
+  source            = "./modules/secrets_manager"
+  resource_group_id = ibm_resource_group.build_resource_group.id
+}
+module "vpc" {
+  providers = {
+    ibm = ibm.vpc
+  }
+  source            = "./modules/vpc"
+  zone              = var.zone
+  resource_group_id = ibm_resource_group.build_resource_group.id
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/outputs.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/outputs.tf
new file mode 100644
index 00000000000..6d876bae390
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/outputs.tf
@@ -0,0 +1,22 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+output "k8s_secrets_manager_id" {
+  value = ibm_resource_instance.secrets_manager.guid
+}
+
+output "k8s_z_ssh_public_key" {
+  value = tls_private_key.private_key.public_key_openssh
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/secret_manager.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/secret_manager.tf
new file mode 100644
index 00000000000..140a4e3a5a5
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/secret_manager.tf
@@ -0,0 +1,59 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+locals {
+  secrets_manager_region     = "eu-de"
+  secrets_manager_name       = "k8s-s390x-secrets-manager"
+  z_service_cred_secret_name = "k8s-s390x-sm-service-credentials-secret"
+}
+
+resource "ibm_resource_instance" "secrets_manager" {
+  name              = local.secrets_manager_name
+  resource_group_id = var.resource_group_id
+  service           = "secrets-manager"
+  plan              = "standard"
+  location          = local.secrets_manager_region
+  service_endpoints = "public-and-private"
+
+  timeouts {
+    create = "15m"
+    update = "15m"
+    delete = "15m"
+  }
+}
+
+# Generate RSA key
+resource "tls_private_key" "private_key" {
+  algorithm = "RSA"
+  rsa_bits  = 4096
+}
+
+# Arbitrary secrets - reference the resource directly
+resource "ibm_sm_arbitrary_secret" "z_ssh_private_key" {
+  name        = "zvsi-ssh-private-key"
+  instance_id = ibm_resource_instance.secrets_manager.guid # Direct reference
+  region      = local.secrets_manager_region
+  labels      = ["zvsi-ssh-private-key"]
+  payload     = tls_private_key.private_key.private_key_openssh
+}
+
+resource "ibm_sm_arbitrary_secret" "z_ssh_public_key" {
+  name        = "zvsi-ssh-public-key"
+  instance_id = ibm_resource_instance.secrets_manager.guid # Direct reference
+  region      = local.secrets_manager_region
+  labels      = ["zvsi-ssh-public-key"]
+  payload     = tls_private_key.private_key.public_key_openssh
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/variables.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/variables.tf
new file mode 100644
index 00000000000..ea28034f332
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/variables.tf
@@ -0,0 +1,19 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+variable "resource_group_id" {
+  description = "The ID of the IBM Cloud resource group where resources will be created"
+  type        = string
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/versions.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/versions.tf
new file mode 100644
index 00000000000..e51f5b24c6b
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/secrets_manager/versions.tf
@@ -0,0 +1,23 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+terraform {
+  required_providers {
+    ibm = {
+      source = "IBM-Cloud/ibm"
+    }
+  }
+}
+
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/outputs.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/outputs.tf
new file mode 100644
index 00000000000..859847fb749
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/outputs.tf
@@ -0,0 +1,40 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+output "vpc_id" {
+  value = ibm_is_vpc.vpc.id
+}
+output "subnet_id" {
+  value = ibm_is_subnet.subnet.id
+}
+
+output "bastion_sg_id" {
+  value = ibm_is_security_group.bastion_sg.id
+}
+
+output "crn" {
+  value = ibm_is_vpc.vpc.crn
+}
+output "bastion_sg_name" {
+  value = ibm_is_security_group.bastion_sg.name
+}
+
+output "control_plane_sg_name" {
+  value = ibm_is_security_group.control_plane_sg.name
+}
+
+output "worker_sg_name" {
+  value = ibm_is_security_group.worker_sg.name
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/variables.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/variables.tf
new file mode 100644
index 00000000000..7033b8873a0
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/variables.tf
@@ -0,0 +1,17 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+variable "resource_group_id" {}
+variable "zone" {}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/versions.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/versions.tf
new file mode 100644
index 00000000000..3987f68e95a
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/versions.tf
@@ -0,0 +1,23 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+terraform {
+  required_providers {
+    ibm = {
+      source = "IBM-Cloud/ibm"
+    }
+  }
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/vpc.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/vpc.tf
new file mode 100644
index 00000000000..9cf014b556e
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/modules/vpc/vpc.tf
@@ -0,0 +1,343 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+resource "ibm_is_vpc" "vpc" {
+  name           = "k8s-s390x-vpc"
+  resource_group = var.resource_group_id
+}
+
+# VPC
+resource "ibm_is_public_gateway" "public_gw" {
+  name           = "k8s-s390x-public-gw"
+  vpc            = ibm_is_vpc.vpc.id
+  zone           = var.zone
+  resource_group = var.resource_group_id
+}
+
+# Subnet
+resource "ibm_is_subnet" "subnet" {
+  name                     = "k8s-s390x-subnet"
+  vpc                      = ibm_is_vpc.vpc.id
+  zone                     = var.zone
+  resource_group           = var.resource_group_id
+  total_ipv4_address_count = 256
+  public_gateway           = ibm_is_public_gateway.public_gw.id
+}
+
+# Security Groups
+resource "ibm_is_security_group" "bastion_sg" {
+  name           = "k8s-vpc-s390x-bastion-sg"
+  vpc            = ibm_is_vpc.vpc.id
+  resource_group = var.resource_group_id
+}
+
+resource "ibm_is_security_group" "control_plane_sg" {
+  name           = "k8s-vpc-s390x-control-plane-sg"
+  vpc            = ibm_is_vpc.vpc.id
+  resource_group = var.resource_group_id
+}
+
+resource "ibm_is_security_group" "worker_sg" {
+  name           = "k8s-vpc-s390x-worker-sg"
+  vpc            = ibm_is_vpc.vpc.id
+  resource_group = var.resource_group_id
+}
+
+# Security Group Rules
+resource "ibm_is_security_group_rule" "bastion_inbound_ssh" {
+  group     = ibm_is_security_group.bastion_sg.id
+  direction = "inbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 22
+    port_max = 22
+  }
+}
+
+resource "ibm_is_security_group_rule" "bastion_outbound_all" {
+  group     = ibm_is_security_group.bastion_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+}
+
+## Master Rules
+
+resource "ibm_is_security_group_rule" "worker_inbound_ssh_from_bastion" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.bastion_sg.id
+  tcp {
+    port_min = 22
+    port_max = 22
+  }
+}
+
+
+resource "ibm_is_security_group_rule" "worker_internal" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+}
+
+resource "ibm_is_security_group_rule" "worker_control_plane_all" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.control_plane_sg.id
+}
+
+resource "ibm_is_security_group_rule" "bastion_private_inbound" {
+  group     = ibm_is_security_group.bastion_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+}
+
+resource "ibm_is_security_group_rule" "bastion_private_outbound" {
+  group     = ibm_is_security_group.bastion_sg.id
+  direction = "outbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+}
+
+
+resource "ibm_is_security_group_rule" "control_plane_to_worker_kubelet_api" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.control_plane_sg.id
+  tcp {
+    port_min = 10250
+    port_max = 10250
+  }
+}
+resource "ibm_is_security_group_rule" "allow_control_plane_to_worker_all" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.control_plane_sg.id
+  tcp {
+    port_min = 1
+    port_max = 65535
+  }
+}
+
+resource "ibm_is_security_group_rule" "allow_bastion_ssh_to_worker" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.bastion_sg.id
+  tcp {
+    port_min = 22
+    port_max = 22
+  }
+}
+
+resource "ibm_is_security_group_rule" "allow_vpc_cidr_to_worker" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+  tcp {
+    port_min = 1
+    port_max = 65535
+  }
+}
+resource "ibm_is_security_group_rule" "outbound_http" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 80
+    port_max = 80
+  }
+}
+
+resource "ibm_is_security_group_rule" "outbound_https" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 443
+    port_max = 443
+  }
+}
+
+resource "ibm_is_security_group_rule" "outbound_dns_tcp" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 53
+    port_max = 53
+  }
+}
+
+resource "ibm_is_security_group_rule" "outbound_dns_udp" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+  udp {
+    port_min = 53
+    port_max = 53
+  }
+}
+
+resource "ibm_is_security_group_rule" "outbound_k8s_api" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 6443
+    port_max = 6443
+  }
+}
+
+resource "ibm_is_security_group_rule" "worker_outbound_to_all" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "worker_pod_inbound" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+  tcp {
+    port_min = 10250
+    port_max = 10250
+  }
+}
+
+resource "ibm_is_security_group_rule" "worker_pod_outbound" {
+  group     = ibm_is_security_group.worker_sg.id
+  direction = "outbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+  tcp {
+    port_min = 10250
+    port_max = 10250
+  }
+}
+
+resource "ibm_is_security_group_rule" "control_plane_inbound_from_workers" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.worker_sg.id
+}
+
+resource "ibm_is_security_group_rule" "control_plane_inbound_from_bastion_ssh" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.bastion_sg.id
+  tcp {
+    port_min = 22
+    port_max = 22
+  }
+}
+
+resource "ibm_is_security_group_rule" "control_plane_inbound_from_internal_cidr" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+}
+
+resource "ibm_is_security_group_rule" "control_plane_inbound_from_self" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = ibm_is_security_group.control_plane_sg.id
+}
+
+resource "ibm_is_security_group_rule" "control_plane_inbound_api" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = "0.0.0.0/0"
+  tcp {
+    port_min = 6443
+    port_max = 6443
+  }
+}
+resource "ibm_is_security_group_rule" "control_plane_outbound_http" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  tcp {
+    port_min = 80
+    port_max = 80
+  }
+  remote = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_https" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  tcp {
+    port_min = 443
+    port_max = 443
+  }
+  remote = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_dns_tcp" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  tcp {
+    port_min = 53
+    port_max = 53
+  }
+  remote = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_dns_udp" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  udp {
+    port_min = 53
+    port_max = 53
+  }
+  remote = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_api" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  tcp {
+    port_min = 6443
+    port_max = 6443
+  }
+  remote = "0.0.0.0/0"
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_to_workers" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  remote    = ibm_is_security_group.control_plane_sg.id
+}
+
+resource "ibm_is_security_group_rule" "control_plane_outbound_to_all" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  remote    = "0.0.0.0/0"
+}
+resource "ibm_is_security_group_rule" "control_plane_pod_inbound" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "inbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+  tcp {
+    port_min = 10250
+    port_max = 10250
+  }
+}
+
+resource "ibm_is_security_group_rule" "control_plane_pod_outbound" {
+  group     = ibm_is_security_group.control_plane_sg.id
+  direction = "outbound"
+  remote    = ibm_is_subnet.subnet.ipv4_cidr_block
+  tcp {
+    port_min = 10250
+    port_max = 10250
+  }
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/providers.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/providers.tf
new file mode 100644
index 00000000000..22d0abdec56
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/providers.tf
@@ -0,0 +1,32 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+locals {
+  key    = var.ibmcloud_api_key
+  region = "eu-de"
+  zone   = "eu-de-1"
+}
+
+provider "ibm" {
+  ibmcloud_api_key = local.key
+  region           = local.region
+  zone             = local.zone
+}
+provider "ibm" {
+  alias            = "vpc"
+  ibmcloud_api_key = local.key
+  region           = local.region
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/var.tfvars b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/var.tfvars
new file mode 100644
index 00000000000..01d700615fb
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/var.tfvars
@@ -0,0 +1 @@
+ibmcloud_api_key = ""
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/variables.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/variables.tf
new file mode 100644
index 00000000000..a14f0e9d580
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/variables.tf
@@ -0,0 +1,31 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+variable "ibmcloud_api_key" {
+  type        = string
+  description = "IBM Cloud API key associated with user's identity"
+  sensitive   = true
+
+  validation {
+    condition     = var.ibmcloud_api_key != ""
+    error_message = "The ibmcloud_api_key is required and cannot be empty."
+  }
+}
+variable "zone" {
+  description = "IBM Cloud zone for resources"
+  type        = string
+  default     = "eu-de-1"
+}
diff --git a/infra/ibmcloud/terraform/k8s-s390x-infra-setup/versions.tf b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/versions.tf
new file mode 100644
index 00000000000..7eef45bc572
--- /dev/null
+++ b/infra/ibmcloud/terraform/k8s-s390x-infra-setup/versions.tf
@@ -0,0 +1,42 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+terraform {
+  backend "s3" {
+    bucket                      = "k8s-z-infra-tf-states"
+    key                         = "k8s-s390x-infra-setup/terraform.tfstate"
+    region                      = "eu-geo"
+    skip_region_validation      = true
+    skip_credentials_validation = true
+    endpoints = {
+      s3 = "https://s3.eu.cloud-object-storage.appdomain.cloud"
+    }
+  }
+  required_providers {
+    ibm = {
+      source  = "IBM-Cloud/ibm"
+      version = "~> 1.82.0"
+    }
+    time = {
+      source  = "hashicorp/time"
+      version = "~> 0.13.0"
+    }
+    null = {
+      source  = "hashicorp/null"
+      version = "~> 3.2.0"
+    }
+  }
+}