Chapter 12 — OT, IoT and cyber-physical security: data flows
Lesson map
Lesson 12 published. Map, example, EX034.
flowchart TD
N0["Learning outcomes"]
N1["12.1 The flow matrix"]
N2["12.2 Unapproved flows"]
N3["12.3 Approved but unused"]
N4["12.4 From comparison to change"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX034"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["12.1 The flow matrix"]
N2["12.2 Unapproved flows"]
N3["12.3 Approved but unused"]
N4["12.4 From comparison to change"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX034"]
[Learning outcomes]
|
v
[12.1 The flow matrix]
|
v
[12.2 Unapproved flows]
|
v
[12.3 Approved but unused]
|
v
[12.4 From comparison to change]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX034]
Learning outcomes
You will (1) write an approved flow matrix; (2) compare observed flows with it; (3) interpret unapproved and unused approved flows; and (4) turn the comparison into firewall changes.
12.1 The flow matrix
A flow matrix lists every permitted conversation: source, destination, port and purpose. It is the conduit table of Chapter 8 made precise enough to test. NCS has four approved flows: HMI-C to each PLC on Modbus/TCP 502, the historian polling PLC-R1, and GW-LOG to the vendor cloud on 443.
"""Lab 12: compare observed synthetic flows with the approved flow matrix."""
approved = {("HMI-C", "PLC-R1", 502), ("HMI-C", "PLC-R2", 502), ("GW-LOG", "CLOUD-LOG", 443), ("HIST", "PLC-R1", 502)}
observed = [("HMI-C", "PLC-R1", 502), ("GW-LOG", "CLOUD-LOG", 443), ("OFFICE-7", "PLC-R2", 502),
("HIST", "PLC-R1", 502), ("GW-LOG", "PLC-R1", 502)]
for f in observed:
print(f"{f[0]:8} -> {f[1]:9} :{f[2]:<4} {'approved' if f in approved else 'UNAPPROVED'}")
print("approved but not seen:", sorted(approved - set(observed)))
Run with python3 lab_flows.py. Verified output:
HMI-C -> PLC-R1 :502 approved
GW-LOG -> CLOUD-LOG :443 approved
OFFICE-7 -> PLC-R2 :502 UNAPPROVED
HIST -> PLC-R1 :502 approved
GW-LOG -> PLC-R1 :502 UNAPPROVED
approved but not seen: [('HMI-C', 'PLC-R2', 502)]
The lab compares those four approved flows with five observed conversations.
The two unapproved rows, OFFICE-7 talking to PLC-R2 and GW-LOG reaching PLC-R1, are the ones to investigate first, while the unseen HMI-C to PLC-R2 flow may simply not have occurred during the capture. Chapter 27 later shows that the list was missing the historian's polling of PLC-R2, an approved flow nobody had written down.
12.2 Unapproved flows
OFFICE-7 talking Modbus to PLC-R2 is exactly what rule 9 allowed. It might be an engineer's spreadsheet macro, or malware. Either way it is a path from the office to a compressor controller. GW-LOG talking to PLC-R1 is stranger: the logger gateway has no reason to speak Modbus. It could be a vendor "integration" feature or a sign of compromise.
Priya traced both. OFFICE-7 ran an energy report macro reading compressor run hours from PLC-R2; the logger vendor confirmed an unused "PLC integration" feature on GW-LOG, enabled by default, which was disabled.
12.3 Approved but unused
HMI-C → PLC-R2 did not appear. Perhaps the window was short; perhaps the HMI reads PLC-R2 through PLC-R1. Unused approvals are candidates for removal after checking with operations — fewer open paths, less to defend.
Chapter 27 shows the risk of reading this too quickly. The observation window also missed the historian polling PLC-R2, so the flow matrix listed HIST → PLC-R1 only. When the new rule set went live, HIST stopped receiving PLC-R2 tags within four minutes and Priya rolled back. An approved-but-unseen flow is a question for operations and the vendors, not proof the flow is unused.
12.4 From comparison to change
Each unapproved flow gets an owner and a decision: approve with justification (and update the matrix), or block. Blocking happens in a planned window with operations informed, because a "mystery" flow may turn out to be something the plant needs.
Priya's two decisions: OFFICE-7's energy macro was moved to read run hours from the historian replica in the DMZ, and office → control was blocked in the 20 March maintenance window after the switch; GW-LOG's "PLC integration" feature was disabled with the logger vendor's agreement, and the flow disappeared without a firewall change.
Worked example (synthetic NCS)
Priya asks the office: OFFICE-7 runs an energy report macro that reads compressor run hours directly from PLC-R2. She proposes reading the same values from the historian replica in the DMZ instead, then blocking office → control. For GW-LOG → PLC-R1 she contacts the logger vendor, who confirms an unused "PLC integration" feature enabled by default; it is disabled and the flow disappears.
Synthetic case — Northgate Cold Storage. Flows and explanations are invented.
Errors and limits
Observation windows miss monthly or seasonal flows such as defrost schedules or end-of-month reports. Ports do not prove protocol; a flow on 502 may not be Modbus.
Exercises
- EX034 — Classifying a new observation. Add
("HMI-C", "PLC-R2", 502)toobserved. What changes in the output? Rubric: 3 = it prints approved and the not-seen list becomes empty; 2 = one effect; 1 = unapproved; 0 = none. - EX035 — Decision for OFFICE-7. Write the decision record for the OFFICE-7 flow. Rubric: 3 = cause, replacement path via DMZ, block date, owner; 2 = three; 1 = "block it"; 0 = none.
- EX036 — Why GW-LOG → PLC-R1 is suspicious. Explain in two sentences. Rubric: 3 = no business need for logger gateway to speak Modbus; bridges internet-connected zone to control; 2 = one; 1 = vague; 0 = none.
Synthesis
Comparing observed flows with an approved matrix finds the paths nobody intended, and each one ends in an owned decision.
Continue studying — chapter 12 of 30
← Chapter 11 (draft) · Course chapter index · Chapter 13 (draft) →