diff --git a/.gitlab-ci/packet.yml b/.gitlab-ci/packet.yml
index c6f9f2f7163e5121fa68cd389879e5911c2f08aa..d7f44f27d1d318ca5bf0700f7c1ccdd09b7edfa4 100644
--- a/.gitlab-ci/packet.yml
+++ b/.gitlab-ci/packet.yml
@@ -260,6 +260,11 @@ packet_debian11-kubelet-csr-approver:
   extends: .packet_pr
   when: manual
 
+packet_debian12-custom-cni-helm:
+  stage: deploy-part2
+  extends: .packet_pr
+  when: manual
+
 # ### PR JOBS PART3
 # Long jobs (45min+)
 
diff --git a/docs/ci.md b/docs/ci.md
index 466072edc45360018ed8ab454053fa9c5d0ecdda..0fed5e1062e75b64f19d275592a70d426c5bba0f 100644
--- a/docs/ci.md
+++ b/docs/ci.md
@@ -11,7 +11,7 @@ amazon |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
 centos7 |  :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: |
 debian10 |  :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: |
 debian11 |  :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
-debian12 |  :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian12 |  :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
 fedora37 |  :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: |
 fedora38 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: |
 opensuse |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
diff --git a/inventory/sample/group_vars/k8s_cluster/k8s-net-custom-cni.yml b/inventory/sample/group_vars/k8s_cluster/k8s-net-custom-cni.yml
new file mode 100644
index 0000000000000000000000000000000000000000..67b048103692b68fac4678ed30cde9b6596e15e1
--- /dev/null
+++ b/inventory/sample/group_vars/k8s_cluster/k8s-net-custom-cni.yml
@@ -0,0 +1,51 @@
+---
+# custom_cni network plugin configuration
+# There are two deployment options to choose from, select one
+
+## OPTION 1 - Static manifest files
+## With this option, referred manifest file will be deployed
+## as if the `kubectl apply -f` method was used with it.
+#
+## List of Kubernetes resource manifest files
+## See tests/files/custom_cni/README.md for example
+# custom_cni_manifests: []
+
+## OPTION 1 EXAMPLE - Cilium static manifests in Kubespray tree
+# custom_cni_manifests:
+#   - "{{ playbook_dir }}/../tests/files/custom_cni/cilium.yaml"
+
+## OPTION 2 - Helm chart application
+## This allows the CNI backend to be deployed to Kubespray cluster
+## as common Helm application.
+#
+## Helm release name - how the local instance of deployed chart will be named
+# custom_cni_chart_release_name: ""
+#
+## Kubernetes namespace to deploy into
+# custom_cni_chart_namespace: "kube-system"
+#
+## Helm repository name - how the local record of Helm repository will be named
+# custom_cni_chart_repository_name: ""
+#
+## Helm repository URL
+# custom_cni_chart_repository_url: ""
+#
+## Helm chart reference - path to the chart in the repository
+# custom_cni_chart_ref: ""
+#
+## Helm chart version
+# custom_cni_chart_version: ""
+#
+## Custom Helm values to be used for deployment
+# custom_cni_chart_values: {}
+
+## OPTION 2 EXAMPLE - Cilium deployed from official public Helm chart
+# custom_cni_chart_namespace: kube-system
+# custom_cni_chart_release_name: cilium
+# custom_cni_chart_repository_name: cilium
+# custom_cni_chart_repository_url: https://helm.cilium.io
+# custom_cni_chart_ref: cilium/cilium
+# custom_cni_chart_version: 1.14.3
+# custom_cni_chart_values:
+#   cluster:
+#     name: "cilium-demo"
diff --git a/roles/network_plugin/custom_cni/defaults/main.yml b/roles/network_plugin/custom_cni/defaults/main.yml
index 5cde372d5dbe23644a9aeb9a5cd329e6a6e092c9..0eab14374e3fb2e978d19fbeade1df4d2c89150f 100644
--- a/roles/network_plugin/custom_cni/defaults/main.yml
+++ b/roles/network_plugin/custom_cni/defaults/main.yml
@@ -1,3 +1,11 @@
 ---
 
 custom_cni_manifests: []
+
+custom_cni_chart_namespace: kube-system
+custom_cni_chart_release_name: ""
+custom_cni_chart_repository_name: ""
+custom_cni_chart_repository_url: ""
+custom_cni_chart_ref: ""
+custom_cni_chart_version: ""
+custom_cni_chart_values: {}
diff --git a/roles/network_plugin/custom_cni/meta/main.yml b/roles/network_plugin/custom_cni/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..361c406de2aff55fc509ef383ca37720aa2aeabc
--- /dev/null
+++ b/roles/network_plugin/custom_cni/meta/main.yml
@@ -0,0 +1,20 @@
+---
+dependencies:
+  - role: helm-apps
+    when:
+      - inventory_hostname == groups['kube_control_plane'][0]
+      - custom_cni_chart_release_name | length > 0
+    environment:
+      http_proxy: "{{ http_proxy | default('') }}"
+      https_proxy: "{{ https_proxy | default('') }}"
+    release_common_opts: {}
+    releases:
+      - name: "{{ custom_cni_chart_release_name }}"
+        namespace: "{{ custom_cni_chart_namespace }}"
+        chart_ref: "{{ custom_cni_chart_ref }}"
+        chart_version: "{{ custom_cni_chart_version }}"
+        wait: true
+        values: "{{ custom_cni_chart_values }}"
+    repositories:
+      - name: "{{ custom_cni_chart_repository_name }}"
+        url: "{{ custom_cni_chart_repository_url }}"
diff --git a/roles/network_plugin/custom_cni/tasks/main.yml b/roles/network_plugin/custom_cni/tasks/main.yml
index c4289445bc52de8de281547841101356a9b8cb10..8f5b4195f99162877b3e57dcc0c12ed17d1fd55f 100644
--- a/roles/network_plugin/custom_cni/tasks/main.yml
+++ b/roles/network_plugin/custom_cni/tasks/main.yml
@@ -1,26 +1,29 @@
 ---
-- name: Custom CNI | Check Custom CNI Manifests
-  assert:
-    that:
+- name: Custom CNI | Manifest deployment
+  when: not custom_cni_chart_release_name | length > 0
+  block:
+  - name: Custom CNI | Check Custom CNI Manifests
+    assert:
+      that:
       - "custom_cni_manifests | length > 0"
-    msg: "custom_cni_manifests should not be empty"
+      msg: "custom_cni_manifests should not be empty"
 
-- name: Custom CNI | Copy Custom manifests
-  template:
-    src: "{{ item }}"
-    dest: "{{ kube_config_dir }}/{{ item | basename | replace('.j2', '') }}"
-    mode: 0644
-  loop: "{{ custom_cni_manifests }}"
-  delegate_to: "{{ groups['kube_control_plane'] | first }}"
-  run_once: true
+  - name: Custom CNI | Copy Custom manifests
+    template:
+      src: "{{ item }}"
+      dest: "{{ kube_config_dir }}/{{ item | basename | replace('.j2', '') }}"
+      mode: 0644
+    loop: "{{ custom_cni_manifests }}"
+    delegate_to: "{{ groups['kube_control_plane'] | first }}"
+    run_once: true
 
-- name: Custom CNI | Start Resources
-  kube:
-    namespace: "kube-system"
-    kubectl: "{{ bin_dir }}/kubectl"
-    filename: "{{ kube_config_dir }}/{{ item | basename | replace('.j2', '') }}"
-    state: "latest"
-    wait: true
-  loop: "{{ custom_cni_manifests }}"
-  delegate_to: "{{ groups['kube_control_plane'] | first }}"
-  run_once: true
+  - name: Custom CNI | Start Resources
+    kube:
+      namespace: "kube-system"
+      kubectl: "{{ bin_dir }}/kubectl"
+      filename: "{{ kube_config_dir }}/{{ item | basename | replace('.j2', '') }}"
+      state: "latest"
+      wait: true
+    loop: "{{ custom_cni_manifests }}"
+    delegate_to: "{{ groups['kube_control_plane'] | first }}"
+    run_once: true
diff --git a/tests/files/packet_debian12-custom-cni-helm.yml b/tests/files/packet_debian12-custom-cni-helm.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0ed919828c749f68e73ae085149c838dcdc1331e
--- /dev/null
+++ b/tests/files/packet_debian12-custom-cni-helm.yml
@@ -0,0 +1,23 @@
+---
+# Instance settings
+cloud_image: debian-12
+mode: default
+
+# Kubespray settings
+kube_owner: root
+kube_network_plugin: custom_cni
+custom_cni_chart_namespace: kube-system
+custom_cni_chart_release_name: cilium
+custom_cni_chart_repository_name: cilium
+custom_cni_chart_repository_url: https://helm.cilium.io
+custom_cni_chart_ref: cilium/cilium
+custom_cni_chart_version: 1.14.3
+custom_cni_chart_values:
+  cluster:
+    name: kubespray
+  hubble:
+    enabled: false
+  ipam:
+    operator:
+      clusterPoolIPv4PodCIDRList:
+        - "{{ kube_pods_subnet }}"