Lesson 09 / 21
Encryption in Transit
What happens when transit encryption is enforced is counted: 9 of 16 connection legs are open, 4 have unknown status. Three-stage enforcement changes 23 configuration items and breaks 79 connections; 34 cannot be upgraded. Only one of six paths becomes proven end to end, and reaching all of them needs encryption in its own layer.
Published Updated
In this lesson
- Counts connection legs across three states: encrypted, open, unknown
- Measures the cost of enforcement: configuration items changed, connections broken, permanent breaks
- Records provider-internal traffic status as an assumption and counts not-knowing itself as a line item
Contents
The question for data at rest is answered. When data moves, though, there is not a single box in front of you — there is a chain: a measurement network record travels from the edge device to the intake endpoint, from there to the gateway, to the collector, and to the database; every hop is a separate leg, and every leg has its own status. This lesson’s question is not the cost of the handshake — that was measured earlier — nor where encryption terminates; that was measured too. The question here is enforcement: which legs are encrypted, which are left open on an “internal network” rationale, how many connections break when policy enforces it, and how many configuration items change.
There is a third state as well: whether transport inside the provider’s own network is encrypted
cannot be verified by the tenant. Those legs sit as “unknown,” the provider’s default is
written down as an assumption, and not knowing itself counts as a line item. The measurement
runs on the regional measurement network, is fictional, and is a model written with
node.
CS7. The data path breaks into 16 connection legs; the leg catalog, client counts, configuration items, and request volumes are fictional. CS8. Every leg is on one of three network types: public network, dedicated line, provider-internal network. CS9. A leg’s status is three-valued — encrypted, open, unknown. The third value is used only for provider-internal transport and cannot be verified. CS10. For every open leg, the number of clients that do not support encryption and how many of them can be upgraded is recorded; a client that cannot be upgraded breaks permanently under enforcement. CS11. Enforcement is in three stages: public network first, then dedicated line, then provider-internal network. The transition window is 90 days (fictional), and 61 days have passed in warning mode. CS12. That “unknown” legs are encrypted can only be proven by the tenant encrypting in its own layer; the configuration cost of that is recorded per leg.
Legs, Paths, and Staged Enforcement
// leg.mjs — transit legs, paths, and staged enforcement. MODEL. // The regional measurement network is FICTIONAL: the leg catalog, client counts, and request volumes are made up. // status "unknown" = provider-internal transport; the tenant cannot verify it, it stands as an ASSUMPTION. export const LEG = [ // id, name, network, status, clients, unsupported, configItems, requestsK, proofItems, upgradable ["b1", "edge device -> intake endpoint", "public", "open", 340, 54, 3, 4820, 0, 38], ["b2", "intake endpoint -> gateway", "provider-internal", "encrypted", 6, 0, 1, 4820, 0, 0], ["b3", "gateway -> collector", "provider-internal", "unknown", 12, 0, 2, 4820, 4, 0], ["b4", "collector -> database", "provider-internal", "open", 12, 0, 4, 1960, 0, 0], ["b5", "collector -> queue", "provider-internal", "open", 12, 2, 2, 3100, 0, 2], ["b6", "processor -> queue", "provider-internal", "open", 9, 0, 2, 3100, 0, 0], ["b7", "processor -> object store", "provider-internal", "unknown", 9, 0, 1, 640, 3, 0], ["b8", "processor -> cache", "provider-internal", "open", 9, 9, 2, 5400, 0, 0], ["b9", "service -> log collector", "provider-internal", "open", 21, 0, 3, 8900, 0, 0], ["b10", "log collector -> archive", "provider-internal", "unknown", 2, 0, 1, 190, 2, 0], ["b11", "archive -> secondary region", "provider-internal", "unknown", 2, 0, 1, 190, 2, 0], ["b12", "invoice export -> reconciliation", "public", "encrypted", 1, 0, 1, 12, 0, 0], ["b13", "partner feed -> intake", "public", "open", 7, 3, 2, 260, 0, 1], ["b14", "operator -> admin endpoint", "public", "encrypted", 20, 0, 1, 45, 0, 0], ["b15", "admin endpoint -> service", "provider-internal", "open", 20, 0, 3, 45, 0, 0], ["b16", "measurement network maintenance channel", "dedicated-line", "open", 28, 11, 2, 70, 0, 4], ].map(([id, name, net, status, clients, broken, cfg, req, proof, up]) => ({ id, name, net, status, clients, broken, cfg, req, proof, up })); export const PATH = { // the leg sequence a request travels "measurement intake": ["b1", "b2", "b3", "b4"], "summary generation": ["b5", "b6", "b7"], "log flow": ["b9", "b10", "b11"], "invoice export": ["b4", "b7", "b12"], "admin access": ["b14", "b15"], "partner intake": ["b13", "b3", "b4"], }; export const find = (id) => LEG.find((b) => b.id === id); export const NET = ["public", "dedicated-line", "provider-internal"]; // order of enforcement stages export const WINDOW = 90, ELAPSED = 61; // fictional transition window, days const total = (l, f) => l.reduce((a, b) => a + f(b), 0); const B = [28, 7, 11, 10, 13, 13, 15]; export const row = (h) => h.map((v, j) => j ? String(v).padStart(B[j]) : String(v).padEnd(B[0])) .join(""); if (import.meta.url === `file://${process.argv[1]}`) { console.log(`model: ${LEG.length} legs, ${Object.keys(PATH).length} paths, ` + `${total(LEG, (b) => b.req)} thousand requests/day (fictional)`); console.log("\n" + row(["network type", "legs", "encrypted", "open", "unknown", "clients", "requests(k)"])); for (const n of NET) { const l = LEG.filter((b) => b.net === n); const s = (d) => l.filter((b) => b.status === d).length; console.log(row([n, l.length, s("encrypted"), s("open"), s("unknown"), total(l, (b) => b.clients), total(l, (b) => b.req)])); } // staged enforcement: at each stage, the open legs of that network type move to encrypted. const status = new Map(LEG.map((b) => [b.id, b.status])); console.log("\n" + row(["stage", "legs", "cfg items", "broken", "requests(k)", "still open", "unknown"])); const emit = (name, l) => { for (const b of l) status.set(b.id, "encrypted"); console.log(row([name, l.length, total(l, (b) => b.cfg), total(l, (b) => b.broken), total(l, (b) => b.req), [...status.values()].filter((d) => d === "open").length, [...status.values()].filter((d) => d === "unknown").length])); }; emit("0. warning mode", []); for (const n of NET) emit(`${NET.indexOf(n) + 1}. ${n}`, LEG.filter((b) => b.net === n && status.get(b.id) === "open")); // per path, end to end: a path counts as proven only if every one of its legs is encrypted. const pathRow = (name, d) => { const l = PATH[name].map(find); const count = (x) => l.filter((b) => d(b) === x).length; console.log(row([name, l.length, count("encrypted"), count("open"), count("unknown"), count("unknown") === 0 && count("open") === 0 ? "proven" : "no", total(l.filter((b) => d(b) !== "encrypted"), (b) => b.req)])); }; console.log("\n" + row(["path (before enforcement)", "legs", "encrypted", "open", "unknown", "end to end", "unproven(k)"])); for (const name of Object.keys(PATH)) pathRow(name, (b) => b.status); console.log("\n" + row(["path (after three stages)", "legs", "encrypted", "open", "unknown", "end to end", "unproven(k)"])); for (const name of Object.keys(PATH)) pathRow(name, (b) => status.get(b.id)); }
model: 16 legs, 6 paths, 38372 thousand requests/day (fictional) network type legs encrypted open unknown clients requests(k) public 4 2 2 0 368 5137 dedicated-line 1 0 1 0 28 70 provider-internal 11 1 6 4 114 33165 stage legs cfg items broken requests(k) still open unknown 0. warning mode 0 0 0 0 9 4 1. public 2 5 57 5080 7 4 2. dedicated-line 1 2 11 70 6 4 3. provider-internal 6 16 11 22505 0 4 path (before enforcement) legs encrypted open unknown end to end unproven(k) measurement intake 4 1 2 1 no 11600 summary generation 3 0 2 1 no 6840 log flow 3 0 1 2 no 9280 invoice export 3 1 1 1 no 2600 admin access 2 1 1 0 no 45 partner intake 3 0 2 1 no 7040 path (after three stages) legs encrypted open unknown end to end unproven(k) measurement intake 4 3 0 1 no 4820 summary generation 3 2 0 1 no 640 log flow 3 1 0 2 no 380 invoice export 3 2 0 1 no 640 admin access 2 2 0 0 proven 0 partner intake 3 2 0 1 no 4820
The first table gives away a pattern immediately: 2 of the 4 legs on the public network are encrypted, only 1 of 11 provider-internal legs. Encryption has been applied to the outward-facing side and not applied on the inside — the rationale is written down: “internal network.” The volume that rationale carries is counted: 33,165 thousand requests a day pass through provider-internal legs, eighty-six percent of the total.
The Enforcement Ledger
The stage table splits the bill into three. The public-network stage is cheap — 2 legs, 5 configuration items — but it breaks 57 connections, because 54 edge devices and 3 clients of the partner feed do not support encrypted transport. The dedicated-line stage is 1 leg, 2 items, 11 broken. The provider-internal stage is the most expensive: 6 legs, 16 items, and the path for 22,505 thousand requests a day; yet it breaks only 11 connections. The distribution runs against intuition — the stage that changes the most configuration is the stage that breaks the fewest connections.
The path tables build the real sentence. Before enforcement, none of the six paths are encrypted end to end. After three stages, only one becomes proven: admin access, because both legs it passes through can be verified. The remaining five paths cannot be proven because each carries at least one “unknown” leg. Unproven volume drops from 11,600 to 4,820 thousand requests but does not hit zero; the reason is a single leg — the hop between the gateway and the collector, a shared part of both measurement intake and partner intake.
// ledger.mjs — the enforcement ledger: broken connections, permanent breaks, exceptions, and proof cost. import { LEG, PATH, WINDOW, ELAPSED } from "./leg.mjs"; const gen = (B) => (h) => h.map((v, j) => j ? String(v).padStart(B[j]) : String(v).padEnd(B[0])) .join(""); const row = gen([41, 9, 13, 10, 11, 11, 13]); // broken-connection table const dr = gen([27, 10, 17, 13, 13, 13, 15]); // decision table const LIMIT = 2; // fictional policy: permanent exception cap const total = (l, f) => l.reduce((a, b) => a + f(b), 0); const OPEN = LEG.filter((b) => b.status === "open"); const UNKNOWN = LEG.filter((b) => b.status === "unknown"); const permanent = (b) => b.broken - b.up; console.log(row(["broken leg", "clients", "unsupported", "upgrade", "permanent", "cfg items", "requests(k)"])); for (const b of OPEN.filter((x) => x.broken > 0)) console.log(row([b.name, b.clients, b.broken, b.up, permanent(b), b.cfg, b.req])); console.log(row(["total", total(OPEN, (b) => b.clients), total(OPEN, (b) => b.broken), total(OPEN, (b) => b.up), total(OPEN, permanent), total(OPEN, (b) => b.cfg), total(OPEN, (b) => b.req)])); // A decision: which legs get enforced, which get encrypted in their own layer, is a proxy set up. const evaluate = (enforced, own, proxy) => { const d = new Map(LEG.map((b) => [b.id, b.status])); let broken = 0, cfg = 0; for (const b of LEG) { if (enforced.has(b.id)) { d.set(b.id, "encrypted"); cfg += b.cfg; broken += proxy ? 0 : permanent(b); } if (own.has(b.id)) { d.set(b.id, "encrypted"); cfg += b.proof; } } if (proxy) cfg += 3 * LEG.filter((b) => enforced.has(b.id) && permanent(b) > 0).length; const proven = Object.values(PATH) .filter((y) => y.every((id) => d.get(id) === "encrypted")).length; const unproven = total(LEG.filter((b) => d.get(b.id) !== "encrypted"), (b) => b.req); return { broken, cfg, proven, unproven, exempt: LEG.filter((b) => b.status === "open" && !enforced.has(b.id)).length }; }; const ids = (l) => new Set(l.map((b) => b.id)); const none = new Set(); const permanentBreakers = OPEN.filter((b) => permanent(b) > 0); // legs that produce a permanent break const DECISION = { "0 warning mode": [none, none, false], "1 enforce, no exception": [ids(OPEN), none, false], "2 enforce + proxy layer": [ids(OPEN), none, true], "3 proxy + own encryption": [ids(OPEN), ids(UNKNOWN), true], "4 enforce + exception": [ids(OPEN.filter((b) => permanent(b) === 0)), none, false], }; console.log("\n" + dr(["decision", "enforced", "permanent break", "exempt open", "proven path", "extra cfg", "unproven(k)"])); for (const [name, [z, k, v]] of Object.entries(DECISION)) { const s = evaluate(z, k, v); console.log(dr([name, z.size, s.broken, s.exempt, `${s.proven}/${Object.keys(PATH).length}`, s.cfg, s.unproven])); } const openReq = total(OPEN, (b) => b.req); console.log(`\ntransition window: ${WINDOW} days, ${ELAPSED} days elapsed, ${WINDOW - ELAPSED} days left; ` + `${openReq * ELAPSED} thousand requests passed through open legs during the warning period`); console.log(`permanent exception cap ${LIMIT} legs (fictional policy); requested ${permanentBreakers.length}, ` + `${permanentBreakers.length - LIMIT} legs beyond the cap`); console.log(`client upgrades: ${total(OPEN, (b) => b.up)} clients, ` + `${OPEN.filter((b) => b.up > 0).length} legs; the remaining ${total(OPEN, permanent)} clients ` + `cannot be upgraded`); console.log(`\nunknown item: ${UNKNOWN.length} legs, ` + `${total(UNKNOWN, (b) => b.req)} thousand requests/day, proof cost ` + `${total(UNKNOWN, (b) => b.proof)} config items`); for (const b of UNKNOWN) console.log(` ${b.name.padEnd(28)} ${String(b.req).padStart(6)} k/day, ` + `proof ${b.proof} items, assumption: provider-internal transport is encrypted`);
broken leg clients unsupported upgrade permanent cfg items requests(k) edge device -> intake endpoint 340 54 38 16 3 4820 collector -> queue 12 2 2 0 2 3100 processor -> cache 9 9 0 9 2 5400 partner feed -> intake 7 3 1 2 2 260 measurement network maintenance channel 28 11 4 7 2 70 total 458 79 45 34 23 27655 decision enforced permanent break exempt open proven path extra cfg unproven(k) 0 warning mode 0 0 9 0/6 0 33495 1 enforce, no exception 9 34 0 1/6 23 5840 2 enforce + proxy layer 9 0 0 1/6 35 5840 3 proxy + own encryption 9 0 0 6/6 46 0 4 enforce + exception 5 0 4 1/6 14 16390 transition window: 90 days, 61 days elapsed, 29 days left; 1686955 thousand requests passed through open legs during the warning period permanent exception cap 2 legs (fictional policy); requested 4, 2 legs beyond the cap client upgrades: 45 clients, 4 legs; the remaining 34 clients cannot be upgraded unknown item: 4 legs, 5840 thousand requests/day, proof cost 11 config items gateway -> collector 4820 k/day, proof 4 items, assumption: provider-internal transport is encrypted processor -> object store 640 k/day, proof 3 items, assumption: provider-internal transport is encrypted log collector -> archive 190 k/day, proof 2 items, assumption: provider-internal transport is encrypted archive -> secondary region 190 k/day, proof 2 items, assumption: provider-internal transport is encrypted
The broken-connection table sets one number apart: 79 clients do not support encrypted transport, 45 can be upgraded, and 34 cannot. The harshest row is the cache leg: 9 of 9 clients do not support it, none can be upgraded, and that leg carries 5,400 thousand requests a day. Second is the edge devices: 16 of 54 devices are hardware sitting in the field whose software will not change.
The decision table lays five approaches side by side. Warning mode breaks nothing and proves nothing; over 61 days, 1,686,955 thousand requests passed through open legs and that cannot be closed retroactively. Enforcing without exception changes 23 items and permanently severs 34 connections. The proxy layer zeroes out breakage and adds 12 items: 35. None of these three decisions pushes the proven path count above 1/6; the one row that does is the fourth — encrypting “unknown” legs in the tenant’s own layer adds 11 more items, for a total of 46, and 6/6 paths become proven.
The last decision shows the opposite: exempting the 4 legs that produce a permanent break cuts the load to 14 items and breaks no connections, but pushes unproven volume up to 16,390 thousand requests a day. Fictional policy recognizes 2 permanent exceptions; 4 are requested, and 2 legs fall outside the cap. Of the transition window’s 90 days, 61 have passed — 29 days remain.
Next to each of the four “unknown” legs sits the same sentence: the assumption is that provider-internal transport is encrypted. They carry 5,840 thousand requests a day, and their status cannot be read from any configuration the tenant holds. Being unknown is not the same as being open, but it is not the same as being provable either.
Summary
- 3 of the 16 legs are encrypted, 9 are open, 4 have unknown status; only 1 of 11 provider-internal legs is encrypted, and 33,165 thousand requests a day pass through those legs.
- Three-stage enforcement changes 23 items; the most expensive stage (provider-internal, 16 items) breaks the fewest connections (11), and the cheapest stage breaks 57.
- 79 clients do not support encrypted transport; 45 can be upgraded, 34 cannot, and the proxy layer adds 12 items while saving those 34.
- Before enforcement, no path is encrypted end to end; after three stages it is 1/6, and once encryption is added in the tenant’s own layer it is 6/6, with unproven volume dropping from 33,495 to zero.
- The exemption path cuts the load to 14 items and pushes unproven volume up to 16,390 thousand requests/day; fictional policy recognizes 2 exceptions, and 2 legs fall outside the cap. 29 days remain in the transition window.
Next Step
Data has been made encrypted both at rest and in transit. Both rest on the same thing: a key or credential is stored somewhere, and services read it. The next lesson returns to that storage layer and measures a single question: when a secret rotates, how large should the window be where the old and new values are valid together — how many clients does a short window miss, and how much does a long window extend the leak duration.
To keep your progress and take notes, Log in
My notes
Log in to take notes.