Balancing Security, Latency, and Operational Load
Zero Trust and micro-segmentation promise a network in which a single compromised host cannot reach everything else. Yet every additional boundary has a price. Traffic that crosses a boundary passes through a policy enforcement point and picks up latency. Every boundary also adds firewall rules that someone has to write, review, and audit.
Push segmentation to the extreme, one segment per asset, and the attack surface for lateral movement nearly disappears. The rule base then explodes, and east-west traffic pays a latency toll on almost every request. Leave the network flat and operations are trivial, but one phishing click can reach the crown jewels.
In this article we turn that tension into an optimization problem and solve it in Python for a concrete 30-asset network.
1. Problem Setting
We have $N = 30$ assets in six tiers: Web (5), App (8), DB (4), Admin (3), IoT (6), and Corp (4). Each asset $i$ has:
- a compromise probability $p_i$ (how exposed it is),
- an asset value $v_i$ (how much damage its loss causes).
Assets communicate according to a symmetric traffic matrix $T_{ij}$ in kreq/s. A link exists when $T_{ij} > 0$, and we write $L_{ij} = \mathbb{1}[T_{ij} > 0]$.
A design is an assignment $a_i \in {0, \dots, K_{\max}-1}$ of every asset to a segment. Define the cross-segment indicator
$$
x_{ij} = \mathbb{1}[a_i \neq a_j].
$$
Risk
Inside a segment the network is flat, so a compromised asset can reach every other member. Across segments, only the allowed flows leak, with a small residual factor $\varepsilon$:
$$
\mathrm{Risk}(a) = \sum_{s} \Big(\sum_{i \in s} p_i\Big)\Big(\sum_{j \in s} v_j\Big) - \sum_i p_i v_i ;+; \varepsilon \sum_{i,j} p_i v_j , L_{ij}, x_{ij}.
$$
Latency
Each cross-segment hop passes an enforcement point that adds $\delta$ ms. The traffic-weighted average added latency is
$$
\mathrm{Lat}(a) = \delta \cdot \frac{\sum_{i<j} T_{ij}, x_{ij}}{\sum_{i<j} T_{ij}}.
$$
Operational load
Operations cost grows with the number of segments to manage, $K_{\mathrm{used}}$, and with the number of firewall rules, one per communicating pair that crosses a boundary:
$$
\mathrm{Ops}(a) = c_{\mathrm{seg}}, K_{\mathrm{used}} + c_{\mathrm{rule}} \sum_{i<j} L_{ij}, x_{ij}.
$$
Normalized objective
To make the weights meaningful, each term is divided by its natural scale: the flat-network risk $R_0$, the maximum latency $\delta$, and the cost $\mathrm{Ops}_{\mathrm{micro}}$ of full micro-segmentation. We minimize
$$
J(a) = w_r \frac{\mathrm{Risk}(a)}{R_0} + w_l \frac{\mathrm{Lat}(a)}{\delta} + w_o \frac{\mathrm{Ops}(a)}{\mathrm{Ops}_{\mathrm{micro}}}, \qquad w_r + w_l + w_o = 1.
$$
The parameters are $\delta = 1.8$ ms, $\varepsilon = 0.08$, $c_{\mathrm{seg}} = 6$, $c_{\mathrm{rule}} = 1$, and the main scenario uses $(w_r, w_l, w_o) = (0.5, 0.3, 0.2)$.
This is a combinatorial problem: the number of ways to partition 30 assets is astronomically large, so brute force is out. We use simulated annealing, with one important speed-up described below.
2. Full Source Code
The whole experiment is a single script.
1 | import math |
3. Code Walkthrough
Section 1: building the network
The 30 assets are generated tier by tier. Every tier has a base compromise probability and asset value, with ±20% jitter per host. Databases are valuable but rarely compromised ($p=0.05$, $v=10$). IoT devices are the opposite: very exposed and nearly worthless on their own ($p=0.35$, $v=1$), which makes them ideal pivot points for an attacker.
The traffic matrix is sampled from two tier-level tables. link_prob gives the chance that two assets talk, and rate_mean gives their mean rate. Web–App and App–DB are dense and heavy, as in a classic three-tier architecture. Admin hosts touch everything at a trickle, and IoT devices only talk to a few App servers.
Section 2: the cost model
evaluate() computes the three terms directly from the formulas above. The in-segment risk uses a neat identity: $\sum_{i,j \in s,, i \ne j} p_i v_j = P_s V_s - \sum_{i\in s} p_i v_i$, where $P_s$ and $V_s$ are segment totals. A single np.bincount therefore replaces a double loop. The cross-segment terms use the mask cross, which is 1 where two assets sit in different segments.
evaluate() is the reference implementation. It is $O(N^2)$ per call and is used for reporting and for the initial state of the annealer.
Section 3: the fast simulated annealing
A naive annealer would call evaluate() at every move, which costs $O(N^2)$. Instead we compute the change in cost $\Delta J$ incrementally. All pairwise cross-segment costs (risk leak, latency, rules) are folded into one symmetric matrix $C_{ij}$ so that
$$
J_{\mathrm{cross}} = \sum_{i<j} C_{ij}, x_{ij}.
$$
We maintain a table $S_{i,s} = \sum_{j:,a_j = s} C_{ij}$, the total cross cost between asset $i$ and everything currently in segment $s$. Moving asset $i$ from segment $a$ to segment $b$ then changes the cross cost by exactly
$$
\Delta J_{\mathrm{cross}} = S_{i,a} - S_{i,b}.
$$
Neighbors left behind in $a$ become cross-segment, and neighbors in $b$ stop being cross-segment. That is an $O(1)$ lookup. After an accepted move, only two columns of $S$ are updated, which is $O(N)$.
The in-segment risk term is quadratic in the segment totals. Moving asset $i$ changes it by
$$
\Delta J_{\mathrm{in}} = \frac{w_r}{R_0}\Big[p_i (V_b - V_a) + v_i (P_b - P_a) + 2 p_i v_i\Big],
$$
where $P$ and $V$ are segment totals before the move. The segment-count penalty is added or removed when a segment becomes empty or newly occupied. A move is accepted with the Metropolis rule $\min(1, e^{-\Delta J / \tau})$, with the temperature $\tau$ cooled geometrically from 0.05 to $10^{-4}$.
best_of() runs several independent restarts with different seeds and keeps the best, which makes the result robust against unlucky starts.
Section 4: experiments
Three experiments are run:
- $K_{\max}$ sweep. For $K_{\max} = 1,\dots,12$ we search for the best partition using at most $K_{\max}$ segments, with the main weights $(0.5, 0.3, 0.2)$. The best result over all $K_{\max}$ is our optimized design.
- Baselines. A flat network, a classic tier-based design with six zones, and full micro-segmentation with one segment per asset.
- Weight sweep. For eight latency weights $w_l \in [0.05, 0.70]$, with $w_o = 0.2$ fixed and $w_r = 0.8 - w_l$, we repeat the $K_{\max}$ sweep. This produces the cost surface and the cloud of Pareto-style trade-off points.
Sections 5 and 6: report and figure
The console report prints a comparison table, the $K_{\max}$ sweep, the member list of each optimized segment, and the headline improvements. All six panels are drawn in one figure, so a single plt.show() produces everything.
4. Console Output
==============================================================================
Network segmentation design: problem summary
==============================================================================
Assets: 30 | communicating pairs: 130 | total traffic: 689.6 kreq/s
Weights (risk, latency, ops) = (0.5, 0.3, 0.2)
Scenario K Risk Lat[ms] Rules Ops J
------------------------------------------------------------------------
Flat (1 segment) 1 746.75 0.000 0 6.0 0.5039
Tier-based (6) 6 90.72 1.651 109 145.0 0.4295
Micro (1 per asset) 30 15.80 1.800 130 310.0 0.5106
Optimized (SA) 5 253.95 0.166 44 74.0 0.2454
Optimal number of segments versus the upper limit K_max
K_max K_used J
1 1 0.5039
2 2 0.3019
3 3 0.2564
4 4 0.2460
5 5 0.2454
6 5 0.2454
7 5 0.2454
8 5 0.2454
9 5 0.2454
10 5 0.2454
11 5 0.2454
12 5 0.2454
Optimized segments
Segment 1 (17 assets): Web1, Web2, Web3, Web4, Web5, App1, App2, App3, App4, App5, App6, App7, App8, DB1, DB2, DB3, DB4
Segment 2 (5 assets): IoT1, IoT2, IoT3, IoT4, IoT6
Segment 3 (3 assets): IoT5, Corp3, Corp4
Segment 4 (3 assets): Admin1, Admin2, Admin3
Segment 5 (2 assets): Corp1, Corp2
Risk reduction vs flat network : 66.0 %
Operational load reduction vs micro : 76.1 %
Total computation time : 24.2 s
5. Result Figure

6. Interpreting the Results
Panel (a): the sorted traffic matrix
Sorting the traffic matrix by optimized segment makes the structure visible. Heavy traffic (bright cells) collapses into one large diagonal block: Web, App, and DB. Those three tiers exchange so much traffic that cutting between them would be costly in latency and rules. The remaining segments (IoT, Admin, Corp) have only faint traffic to the core, so boundaries around them are cheap. The optimizer found exactly the cut lines that sever the least traffic.
Panel (b): the segmentation map
The red edges are the only flows that cross a boundary. They are thin and sparse compared with the dense gray mass inside the big segment. Notably, the optimizer does not follow the tier structure blindly. It groups the IoT devices together, keeps the Admin hosts in their own segment, and splits the corporate machines depending on how they connect to the rest.
Panel (c): cost breakdown
Each design pays in a different currency:
- Flat: almost the entire cost is risk, since one compromised host exposes everything.
- Tier-based: risk is low, but the latency term is large because many Web–App and App–DB flows now cross a boundary.
- Micro-segmentation: risk nearly vanishes, but latency and operations dominate. Every one of the 130 communicating pairs needs its own rule.
- Optimized: a much smaller total than any baseline, because it accepts a moderate amount of in-segment risk in exchange for very little latency and operational cost.
Panel (d): the number of segments
Going from one segment to four, total cost drops steeply. Risk falls fast while latency and operations rise only slightly. Beyond five segments the curve is flat. Raising $K_{\max}$ further adds no benefit because the optimizer simply leaves the extra segments empty: any additional boundary would cost more in latency and rules than it saves in risk. The marginal-benefit logic of segmentation is visible here. The first few cuts are very valuable, and later cuts are not worth their price.
Panel (e): the 3D cost surface
The surface shows the optimal cost as a function of both the segment limit and the weight we place on latency. When latency is cheap (small $w_l$), the surface has a deep valley at moderate $K_{\max}$. As latency weighs more, the best designs shift toward fewer segments. The red markers trace the optimal $K_{\max}$ for each weight, showing how the right architecture depends on the business priorities rather than on a universal rule.
Panel (f): the Pareto cloud
Every dot is a solution found during the weight sweep, placed in the space of normalized risk, latency, and operations. The baselines sit at the extreme corners: flat at high risk, micro-segmentation at high operations. The optimized design lies near the point closest to the origin. Solutions on the surface between the extremes represent honest trade-offs. Moving along it, you can only buy lower risk by paying in latency or operations.
7. Conclusion
Network segmentation is not a matter of “more is safer”. With a simple quantitative model, simulated annealing finds a design with a handful of segments that is far better than both the flat network and the textbook tier-based layout under the stated weights. Two ingredients made it practical:
- the incremental cost update, which reduces each annealing step from a full matrix evaluation to a constant-time lookup plus a column update,
- multiple restarts, which guard against poor local optima.
The same framework extends naturally: add per-flow criticality, use measured latency per enforcement point, or constrain certain assets to share a segment for compliance. The objective keeps its shape, and only the cost matrix $C_{ij}$ changes.











