TT Lab
Get started
Learn Learning paths Courses

Air-Gapped Sites — Defence and Government

Showing with evidence that nothing leaves the network

Continue in TT Lab

Goal

Using only the product configuration files and three kinds of records, judge "there is no unauthorized outside communication" and produce a summary that can be submitted to the audit as is. The scope you confirmed and what you could not confirm must be in the same document.

Why it matters

In a delivery to a network-separated environment, the sentence "nothing goes out" is not accepted. Products include update checks, license checks, remote diagnostics, usage statistics, and time synchronization, and most are on by default. This lab Pod has no kernel permissions at all, so neither tcpdump nor iptables works. That means there is no way to capture and show packets in the first place. In real sites too, that place is filled by the firewall policy copy and device logs that the network team hands over, and the material a developer can submit is configuration and records. So this lab makes its judgment based on settings and records. This is the assumption of this lab. More important than getting the numbers right is telling three things apart. Items hidden with comments versus items that are on by default, blocked attempts versus communication that went out, and what you cannot yet know because it cannot be checked by name.

Steps

  1. With python3 /root/egress/mkdata.py, create the material that will be the basis of the judgment. Out come 3 configurations, an allowlist, and proxy, DNS, and configuration change records.
  2. Extract every address pointing outside from the configurations and write it in /root/egress/endpoints.tsv as host port scheme state source.
  3. Check against the allowlist and sort into three branches in /root/egress/classify.tsv as host port state verdict.
  4. Count the attempts to disallowed destinations in the proxy records and write them in /root/egress/attempts.tsv as host port attempts ok auth blocked.
  5. Write the destinations that appear only in the query records in /root/egress/dns-only.tsv as host queries nxdomain, and leave your own direct observation of this Pod's name resolution in /root/egress/resolver.txt.
  6. Link the three records by time and write them in /root/egress/timeline.tsv as host change_id first_dns first_proxy.
  7. Keep the original, turn off the configuration in /root/egress/conf-after/, re-extract the records with python3 /root/egress/collect.py, and write the numbers before and after turning off in /root/egress/after.txt.
  8. Produce the audit submission summary in /root/egress/egress-report.json and /root/egress/egress-report.txt.

Notes

Create the material that will be the basis of the judgment, inside the network

Save and run /root/egress/mkdata.py, and also fetch and keep the re-collection tool /root/egress/collect.py.

It is an air-gapped network, so you cannot fetch the material from outside. The generation script is included as is in this step's solution, so save it and run it. Only if you use the script that does not use random numbers, as it is, does everyone get the same material and can check one another's judgments against each other. If you edit the files by hand, all the numbers in the later steps go off.

Extract every outside address from the configurations

Find every address pointing outside in the three configuration files and write it in /root/egress/endpoints.tsv as host port scheme state source.

A listen outside a section is a place to receive, not an outside address. List a destination hidden with a comment in the table as off, but do not remove it. In plugins.json, a missing enabled key and a value of false are different. Write only the file name for source.

Check against the allowlist and sort into three branches

Write it in /root/egress/classify.tsv as host port state verdict. verdict is one of allowed, denied, or unknown.

The allowlist is written by name and port. A destination whose address is written directly in the configuration has no way to be checked against that list, so it is neither allowed nor disallowed. That a private range makes it unlikely to have gone outside and that you confirmed it are different statements.

Count actual attempts in the proxy records by response

In /root/egress/attempts.tsv, write the attempts to disallowed destinations as host port attempts ok auth blocked.

ok is the count of 200, auth of 407, and blocked of 403, and attempts is the sum of the three. Do not put destinations that are in the allowlist in this table. If there is a destination that is not in the configuration but appears only in the records, that is also disallowed.

Find destinations that only had their name asked, with no connection

Write host queries nxdomain in /root/egress/dns-only.tsv, and in /root/egress/resolver.txt write the result of your own direct observation of this Pod's name resolution.

Communication that does not go through the proxy leaves nothing in the access records. A name that is in the query records but not in the access records is that trace. Leave out approved destinations. resolver.txt is three lines, nameserver, query, and status, and write status exactly as the string dig produced.

Link the three records by time and pinpoint since when

In /root/egress/timeline.tsv, write host change_id first_dns first_proxy for each disallowed destination. Leave missing fields as a single hyphen.

The targets are the destinations from step 4 and step 5 combined. If you look at which section of the configuration the item value in change.log points to, the changes and the destinations connect. If there is no change to pair with, it is a hyphen. Revealing destinations that arose outside configuration management is the use of this table.

Turn it off, re-collect, and show that it disappeared

In /root/egress/conf-after/, turn off the disallowed destinations, re-extract the records with python3 /root/egress/collect.py, and then write four numbers in /root/egress/after.txt.

The original configuration is evidence, so edit the copy. Do not delete items; only turn them off. For a feature that is truly needed, redirect it to a destination inside the allowlist instead of turning it off. You cannot make 0 by deleting the records by hand. The grader also checks that the approved destinations are still there.

Produce the audit submission summary

In /root/egress/egress-report.json and /root/egress/egress-report.txt, produce a summary that states the scope you confirmed and what you could not confirm together.

All the numbers come from the tables of the earlier steps. Put only destinations that could not be checked by name into unverified_hosts. direct_egress_checked and packet_capture_checked are things this material could not confirm, so write them honestly. The human-readable table must include one line for each destination that appeared only in the records.