diff --git a/infrastructure/calico/felix-configuration.yaml b/infrastructure/calico/felix-configuration.yaml
index 8b26bdd42cca8dc19a2b0702d2607146c2652409..f11f478c810b57cc8a1a9b9782bd55953beef902 100644
--- a/infrastructure/calico/felix-configuration.yaml
+++ b/infrastructure/calico/felix-configuration.yaml
@@ -1,4 +1,4 @@
-apiVersion: crd.projectcalico.org/v1
+apiVersion: projectcalico.org/v3
 kind: FelixConfiguration
 metadata:
   name: default
diff --git a/infrastructure/firewall/controller-config.yaml b/infrastructure/firewall/controller-config.yaml
index 5882934a28ca0fbb2ca63a8067bf5d16902e7af1..5945fdb8018f65646b1a0f3a26a29810e0f559f5 100644
--- a/infrastructure/firewall/controller-config.yaml
+++ b/infrastructure/firewall/controller-config.yaml
@@ -1,4 +1,4 @@
-apiVersion: crd.projectcalico.org/v1
+apiVersion: projectcalico.org/v3
 kind: KubeControllersConfiguration
 metadata:
   annotations:
diff --git a/infrastructure/firewall/ingress-base.yaml b/infrastructure/firewall/ingress-base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2811c071ec076b41a9dcc991b6a33157b09fcb27
--- /dev/null
+++ b/infrastructure/firewall/ingress-base.yaml
@@ -0,0 +1,40 @@
+---
+apiVersion: projectcalico.org/v3
+kind: GlobalNetworkPolicy
+metadata:
+  name: ingress-k8s-base
+spec:
+  selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+  ingress:
+  # Allow ICMP from everywhere
+  - action: Allow
+    protocol: ICMP
+  # Allow SSH from everywhere
+  - action: Allow
+    protocol: TCP
+    destination:
+      ports:
+      - 22
+  # Allow DHCP from everywhere
+  - action: Allow
+    protocol: UDP
+    destination:
+      ports:
+        - 68
+  # Allow bird and typha for calico from all cluster nodes
+  - action: Allow
+    protocol: TCP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+    destination:
+      ports:
+        - 179
+        - 5473
+  - action: Allow
+    protocol: UDP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+    destination:
+      ports:
+        - 4789
+        - 40000:65534
diff --git a/infrastructure/firewall/ingress-control-plane.yaml b/infrastructure/firewall/ingress-control-plane.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a85e572d69e214aa79476e4d88a48173b7e679b5
--- /dev/null
+++ b/infrastructure/firewall/ingress-control-plane.yaml
@@ -0,0 +1,37 @@
+---
+apiVersion: projectcalico.org/v3
+kind: GlobalNetworkPolicy
+metadata:
+  name: ingress-k8s-control-plane
+spec:
+  selector: has(node-role.kubernetes.io/control-plane)
+  # Control plane ports
+  # https://kubernetes.io/docs/reference/ports-and-protocols/
+  ingress:
+  # Allow localhost access
+  - action: Allow
+    destination:
+      nets:
+      - 127.0.0.0/8
+  # Allow Kube API access from everywhere
+  - action: Allow
+    protocol: TCP
+    destination:
+      ports:
+      - 6443
+  # Allow Kubelet and etcd access from control-plane nodes
+  - action: Allow
+    protocol: TCP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane)
+    destination:
+      ports:
+      - 2379
+      - 2380
+      - 10250
+  # Allow NodePorts
+  - action: Allow
+    protocol: TCP
+    destination:
+      ports:
+        - 30000:32767
diff --git a/infrastructure/firewall/ingress-metallb.yaml b/infrastructure/firewall/ingress-metallb.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e0f4cde2af457a0479817a3f363cd406c09125b6
--- /dev/null
+++ b/infrastructure/firewall/ingress-metallb.yaml
@@ -0,0 +1,28 @@
+---
+apiVersion: projectcalico.org/v3
+kind: GlobalNetworkPolicy
+metadata:
+  name: ingress-k8s-metallb
+spec:
+  selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+  ingress:
+  # Allow access for metallb speaker
+  - action: Allow
+    protocol: TCP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+    destination:
+      ports:
+      # metallb-membership port
+      - 7946
+      # metallb-metrics port
+      - 7472
+  # Allow access for metallb speaker
+  - action: Allow
+    protocol: UDP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+    destination:
+      ports:
+      # metallb-membership port
+      - 7946
diff --git a/infrastructure/firewall/ingress-monitoring.yaml b/infrastructure/firewall/ingress-monitoring.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d4ec12b6ed81d0385419e3e0fb74aa0e01238bed
--- /dev/null
+++ b/infrastructure/firewall/ingress-monitoring.yaml
@@ -0,0 +1,17 @@
+---
+apiVersion: projectcalico.org/v3
+kind: GlobalNetworkPolicy
+metadata:
+  name: ingress-k8s-monitoring
+spec:
+  selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+  ingress:
+  # Allow access for metallb speaker
+  - action: Allow
+    protocol: TCP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane) || has(node-role.kubernetes.io/worker)
+    destination:
+      ports:
+      # node-exporter
+      - 9100
diff --git a/infrastructure/firewall/ingress-worker.yaml b/infrastructure/firewall/ingress-worker.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7387d3d1c98ee8b7289819fa2ef479a2e0f96b68
--- /dev/null
+++ b/infrastructure/firewall/ingress-worker.yaml
@@ -0,0 +1,29 @@
+---
+apiVersion: projectcalico.org/v3
+kind: GlobalNetworkPolicy
+metadata:
+  name: ingress-k8s-worker
+spec:
+  selector: has(node-role.kubernetes.io/worker)
+  # Control plane ports
+  # https://kubernetes.io/docs/reference/ports-and-protocols/
+  ingress:
+  # Allow localhost access
+  - action: Allow
+    destination:
+      nets:
+      - 127.0.0.0/8
+  # Allow kublet access from control-plane nodes
+  - action: Allow
+    protocol: TCP
+    source:
+      selector: has(node-role.kubernetes.io/control-plane)
+    destination:
+      ports:
+      - 10250
+  # Allow NodePorts
+  - action: Allow
+    protocol: TCP
+    destination:
+      ports:
+        - 30000:32767
diff --git a/infrastructure/firewall/kustomization.yaml b/infrastructure/firewall/kustomization.yaml
index 0d33fe9d24bd7ee4ea7bbf540457a7a6100979a9..865d3c4874b20ca8bb5c67dc5a482ccc56094800 100644
--- a/infrastructure/firewall/kustomization.yaml
+++ b/infrastructure/firewall/kustomization.yaml
@@ -3,3 +3,8 @@ kind: Kustomization
 namespace: default
 resources:
   - controller-config.yaml
+  - ingress-base.yaml
+  - ingress-control-plane.yaml
+  - ingress-worker.yaml
+  - ingress-metallb.yaml
+  - ingress-monitoring.yaml