diff --git a/gso/services/provisioning_proxy.py b/gso/services/provisioning_proxy.py
index 13d90249b50917c899ef12c05f1d15758662b30c..2fd1cce9f66376605b4557bc0989a112f453b490 100644
--- a/gso/services/provisioning_proxy.py
+++ b/gso/services/provisioning_proxy.py
@@ -14,7 +14,7 @@ from orchestrator.forms import FormPage, ReadOnlyField
 from orchestrator.forms.validators import Accept, Label, LongText
 from orchestrator.types import FormGenerator, State, UUIDstr, strEnum
 from orchestrator.utils.json import json_dumps
-from orchestrator.workflow import Step, StepList
+from orchestrator.workflow import Step, StepList, abort
 from pydantic import validator
 
 from gso import settings
@@ -159,6 +159,7 @@ def _await_pp_results(subscription: SubscriptionModel, label_text: str = DEFAULT
         boolean set to `True`.
     :rtype: {class}`orchestrator.types.FormGenerator`
     """
+
     class ProvisioningResultPage(FormPage):
         class Config:
             title = f"Deploying {subscription.product.name}..."
@@ -179,7 +180,7 @@ def _await_pp_results(subscription: SubscriptionModel, label_text: str = DEFAULT
 
 
 @step("Reset Provisioning Proxy state")
-def reset_pp_success_state() -> State:
+def _reset_pp_success_state() -> State:
     """Reset the boolean that indicates a successful provisioning proxy result in the state of a running workflow.
 
     :return: A new state of the workflow, where the key `pp_did_succeed` has been (re)set to false.
@@ -224,8 +225,8 @@ def _confirm_pp_results(state: State) -> FormGenerator:
     return {"pp_did_succeed": successful_run}
 
 
-def pp_interaction(provisioning_step: Step) -> StepList:
-    """Wrapper function for an interaction with the provisioning proxy
+def pp_interaction(provisioning_step: Step, attempts: int) -> StepList:
+    """Interaction with the provisioning proxy.
 
     This method returns the three steps that make up an interaction with the provisioning proxy:
         - The provisioning step itself, given by the user as input.
@@ -236,15 +237,28 @@ def pp_interaction(provisioning_step: Step) -> StepList:
     already successful, these steps are skipped. This mechanism is quite a dirty hack, and it is planned to be addressed
     in a later release.
 
+    The parameter `attempts` indicates how many times a provisioning may be attempted. When this amount is exceeded, and
+    it is still not successful, the workflow will be aborted.
+
     :param provisioning_step: The step that executes an interaction with the provisioning proxy.
     :type provisioning_step: {class}`orchestrator.workflow.Step`
+    :param attempts: The maximum amount of times that a provisioning can be retried.
+    :type attempts: int
     :return: A list of three steps that form one interaction with the provisioning proxy.
     :rtype: {class}`orchestrator.workflow.StepList`
     """
     should_retry_pp_steps = conditional(lambda state: not state.get("pp_did_succeed"))
 
-    return (
-        should_retry_pp_steps(provisioning_step)
-        >> should_retry_pp_steps(_await_pp_results)
-        >> should_retry_pp_steps(_confirm_pp_results)
-    )
+    pp_steps = StepList([_reset_pp_success_state])
+
+    for _ in range(attempts):
+        pp_steps >>= (
+            should_retry_pp_steps(provisioning_step)
+            >> should_retry_pp_steps(_await_pp_results)
+            >> should_retry_pp_steps(_confirm_pp_results)
+        )
+
+    # Abort a workflow if provisioning has failed too many times
+    pp_steps >>= should_retry_pp_steps(abort)
+
+    return pp_steps
diff --git a/gso/workflows/device/create_device.py b/gso/workflows/device/create_device.py
index a06ee8cf37a3579afc2279f849d2fed053e3b6bc..e0a865f794e7ba7e56fab1985a934a1c51a1cfd1 100644
--- a/gso/workflows/device/create_device.py
+++ b/gso/workflows/device/create_device.py
@@ -18,7 +18,7 @@ from gso.products.product_types import device
 from gso.products.product_types.device import DeviceInactive, DeviceProvisioning
 from gso.products.product_types.site import Site
 from gso.services import _ipam, provisioning_proxy
-from gso.services.provisioning_proxy import pp_interaction, reset_pp_success_state
+from gso.services.provisioning_proxy import pp_interaction
 
 
 def site_selector() -> Choice:
@@ -165,17 +165,8 @@ def create_device() -> StepList:
         >> store_process_subscription(Target.CREATE)
         >> initialize_subscription
         >> get_info_from_ipam
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_device_dry)
-        >> pp_interaction(provision_device_dry)
-        >> pp_interaction(provision_device_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_device_real)
-        >> pp_interaction(provision_device_real)
-        >> pp_interaction(provision_device_real)
-        #
+        >> pp_interaction(provision_device_dry, 3)
+        >> pp_interaction(provision_device_real, 3)
         >> set_status(SubscriptionLifecycle.ACTIVE)
         >> resync
         >> done
diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py
index 3b1e4231743da65c3fb8e4c01d0503f259624422..e52ac500a2e733d3febbf932b06c8cd5cf05285f 100644
--- a/gso/workflows/iptrunk/create_iptrunk.py
+++ b/gso/workflows/iptrunk/create_iptrunk.py
@@ -14,7 +14,7 @@ from gso.products.product_blocks.iptrunk import IptrunkType
 from gso.products.product_types.device import Device
 from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning
 from gso.services import _ipam, provisioning_proxy
-from gso.services.provisioning_proxy import pp_interaction, reset_pp_success_state
+from gso.services.provisioning_proxy import pp_interaction
 
 
 def initial_input_form_generator(product_name: str) -> FormGenerator:
@@ -245,47 +245,14 @@ def create_iptrunk() -> StepList:
         >> store_process_subscription(Target.CREATE)
         >> initialize_subscription
         >> get_info_from_ipam
-        >> reset_pp_success_state
-        #
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_ldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_ldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_ldp_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_ldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_ldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_ldp_iface_real)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        #
+        >> pp_interaction(provision_ip_trunk_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_iface_real, 3)
+        >> pp_interaction(provision_ip_trunk_isis_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_isis_iface_real, 3)
+        >> pp_interaction(provision_ip_trunk_ldp_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_ldp_iface_real, 3)
+        >> pp_interaction(provision_ip_trunk_lldp_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_lldp_iface_real, 3)
         >> set_status(SubscriptionLifecycle.ACTIVE)
         >> resync
         >> done
diff --git a/gso/workflows/iptrunk/modify_generic.py b/gso/workflows/iptrunk/modify_generic.py
index f0439a9e34e87fe1086e431ce3d935afc31389b9..68294b2ed43ccf70e8f31d4e83facc4a286bd01d 100644
--- a/gso/workflows/iptrunk/modify_generic.py
+++ b/gso/workflows/iptrunk/modify_generic.py
@@ -12,7 +12,7 @@ from gso.products.product_blocks import PhyPortCapacity
 from gso.products.product_blocks.iptrunk import IptrunkType
 from gso.products.product_types.iptrunk import Iptrunk
 from gso.services import provisioning_proxy
-from gso.services.provisioning_proxy import pp_interaction, reset_pp_success_state
+from gso.services.provisioning_proxy import pp_interaction
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
@@ -153,27 +153,10 @@ def modify_generic() -> StepList:
         >> store_process_subscription(Target.MODIFY)
         >> unsync
         >> modify_iptrunk_subscription
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        >> pp_interaction(provision_ip_trunk_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        >> pp_interaction(provision_ip_trunk_iface_real)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        >> pp_interaction(provision_ip_trunk_lldp_iface_real)
-        #
+        >> pp_interaction(provision_ip_trunk_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_iface_real, 3)
+        >> pp_interaction(provision_ip_trunk_lldp_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_lldp_iface_real, 3)
         >> resync
         >> done
     )
diff --git a/gso/workflows/iptrunk/modify_isis_metric.py b/gso/workflows/iptrunk/modify_isis_metric.py
index 21af4c57b30676781b1349ca34ea327347cb2b2d..d7affd6a215db53caaf0cf7ac40bb2d5ae6bfee5 100644
--- a/gso/workflows/iptrunk/modify_isis_metric.py
+++ b/gso/workflows/iptrunk/modify_isis_metric.py
@@ -7,7 +7,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form
 
 from gso.products.product_types.iptrunk import Iptrunk
 from gso.services import provisioning_proxy
-from gso.services.provisioning_proxy import pp_interaction, reset_pp_success_state
+from gso.services.provisioning_proxy import pp_interaction
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
@@ -71,17 +71,8 @@ def modify_isis_metric() -> StepList:
         >> store_process_subscription(Target.MODIFY)
         >> unsync
         >> modify_iptrunk_subscription
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        >> pp_interaction(provision_ip_trunk_isis_iface_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        >> pp_interaction(provision_ip_trunk_isis_iface_real)
-        #
+        >> pp_interaction(provision_ip_trunk_isis_iface_dry, 3)
+        >> pp_interaction(provision_ip_trunk_isis_iface_real, 3)
         >> resync
         >> done
     )
diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py
index 2436c8e804a553bfb341ad64d2bf67a8b195216a..474ae707e493b862bc516917c8c40fdeba77186e 100644
--- a/gso/workflows/iptrunk/terminate_iptrunk.py
+++ b/gso/workflows/iptrunk/terminate_iptrunk.py
@@ -12,7 +12,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form
 from gso.products.product_types.iptrunk import Iptrunk
 from gso.services import ipam, provisioning_proxy
 from gso.services.ipam import V4ServiceNetwork, V6ServiceNetwork
-from gso.services.provisioning_proxy import pp_interaction, reset_pp_success_state
+from gso.services.provisioning_proxy import pp_interaction
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
@@ -92,22 +92,8 @@ def terminate_iptrunk() -> StepList:
         >> store_process_subscription(Target.TERMINATE)
         >> unsync
         >> modify_iptrunk_subscription
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(drain_traffic_from_ip_trunk)
-        >> pp_interaction(drain_traffic_from_ip_trunk)
-        >> pp_interaction(drain_traffic_from_ip_trunk)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(deprovision_ip_trunk_dry)
-        >> pp_interaction(deprovision_ip_trunk_dry)
-        >> pp_interaction(deprovision_ip_trunk_dry)
-        #
-        >> reset_pp_success_state
-        >> pp_interaction(deprovision_ip_trunk_real)
-        >> pp_interaction(deprovision_ip_trunk_real)
-        >> pp_interaction(deprovision_ip_trunk_real)
-        #
+        >> pp_interaction(drain_traffic_from_ip_trunk, 3)
+        >> pp_interaction(deprovision_ip_trunk_dry, 3)
         >> deprovision_ip_trunk_ipv4
         >> deprovision_ip_trunk_ipv6
         >> set_status(SubscriptionLifecycle.TERMINATED)