◇ OpenCyber Academy
Technologist · Chapter 6 · English

Chapter 6 — Operating systems and virtualization

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 6 — Operating systems and virtualization

Lesson map

Lesson 06 published. Map, example, EX016.

flowchart TD
  N0["Learning outcomes and connection"]
  N1["6.1 Hardening as subtraction"]
  N2["6.2 Service accounts and least privilege"]
  N3["6.3 Configuration files are security-relevant"]
  N4["6.4 File-integrity baselines"]
  N5["6.5 Virtualization"]
  N6["6.7 Practical activity: file-integrity baseline"]
  N7["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
  N7 --> EX["Worked example"]
  EX --> Q["Exercise EX016"]

Logical drawing

flowchart LR
  N0["Learning outcomes and connection"]
  N1["6.1 Hardening as subtraction"]
  N2["6.2 Service accounts and least privilege"]
  N3["6.3 Configuration files are security-relevant"]
  N4["6.4 File-integrity baselines"]
  N5["6.5 Virtualization"]
  N6["6.7 Practical activity: file-integrity baseline"]
  N7["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX016"]
[Learning outcomes and connection]
    |
    v
[6.1 Hardening as subtraction]
    |
    v
[6.2 Service accounts and least privilege]
    |
    v
[6.3 Configuration files are security-relevant]
    |
    v
[6.4 File-integrity baselines]
    |
    v
[6.5 Virtualization]
    |
    v
[6.7 Practical activity: file-integrity baseline]
    |
    v
[Chapter synthesis]
    |
    v
[Worked example] --> [Exercise EX016]

Learning outcomes and connection

After this chapter you should be able to:

LANTERN's relays and historian are ordinary servers. Most compromises of such servers, and many outages, come not from exotic flaws but from things left on them: an unused service listening on all interfaces, a debug option, a world-writable file, an old account. This chapter is about keeping a server small, known and checkable.

6.1 Hardening as subtraction

Hardening means reducing a system to what its function requires and configuring what remains securely. NIST's server-security guide recommends removing or disabling unneeded services, applications and network protocols, configuring authentication and resource controls, and keeping the system patched and monitored (NIST SP 800-123). For a relay, that means: no desktop environment, no compilers, no file-sharing services, SSH listening only on the management interface, the relay process listening only on its declared address and port, and nothing listening on 0.0.0.0 without a reason written down.

6.2 Service accounts and least privilege

Run each service as its own unprivileged account (relay, not root). Give that account read access to its configuration, write access only to its own data and log directories, and no shell login. Use the operating system's service manager to restart it on failure and to apply further restrictions (for example, a read-only view of most of the filesystem). If the relay process is ever compromised, these choices determine whether the attacker holds one service or the whole host.

On RLY-01 this is the service definition whose permissions changed to 0666.

6.3 Configuration files are security-relevant

On a relay, the most security-relevant files are its configuration (what it listens on, where it forwards, where its key lives), its allowlist of stations, and its service definition (which account it runs as, with what restrictions). A change to any of them changes the security of the service. File permissions matter as much as content: a service definition that has become writable by any user lets any local user decide what runs as the service.

RLY-01 showed both kinds: a content change, debug_listen 0.0.0.0:9000, and a permission change to 0666.

6.4 File-integrity baselines

A file-integrity baseline records a cryptographic hash and the permissions of each important file at a known-good moment. Later snapshots are compared with it; every difference is either explained by an approved change record or investigated. SHA-256, specified in FIPS 180-4, is a standard choice: any change to the file's content changes its digest. The baseline itself must be protected — stored off the host or signed — because an attacker who can change a file and the baseline can hide the change.

6.5 Virtualization

Virtualization runs several operating systems on one physical host through a hypervisor. It helps operations — snapshots, quick rebuilds, separate guests for separate functions — and it creates new things to protect. NIST's guide to full virtualization notes that the hypervisor and its management interfaces become high-value targets, and that guests on one host share physical resources and can affect each other (NIST SP 800-125). Practical consequences: the hypervisor management network is its own zone; whoever administers the hypervisor effectively administers every guest; snapshots contain secrets and must be protected like backups; and placing a station-facing relay and a corporate-facing report server on the same host joins two zones through shared hardware and a shared administrator.

6.6 Worked example: a baseline catches a debug listener (synthetic)

You baseline RLY-01's three configuration files. A week later the comparison shows four differences. The allowlist gained PS-11 under approved change CHG-118 — explained. The relay configuration gained debug_listen 0.0.0.0:9000 with no change record: someone enabled a debug port on every interface, perhaps while troubleshooting, and left it. The service definition's permissions changed from 0640 to 0666: any local user can now rewrite it. A new file helper.sh appeared in the units directory. Three unapproved changes on a critical host is an investigation, not a tidy-up: before reverting anything, preserve the current files and the comparison output, and ask who changed what (Chapter 20).

6.7 Practical activity: file-integrity baseline

Lab 6 (save as lab06.py, run with python3 lab06.py):

# Lab 6 - a file-integrity baseline for the relay host's configuration (offline, standard library only)
# Synthetic files are created in a temporary directory; nothing outside it is read or changed.
import hashlib, json, os, tempfile
def digest(path):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for block in iter(lambda: f.read(65536), b""):
            h.update(block)
    return h.hexdigest()
def snapshot(root):
    out = {}
    for d, _, files in os.walk(root):
        for name in sorted(files):
            p = os.path.join(d, name)
            st = os.stat(p)
            out[os.path.relpath(p, root)] = {"sha256": digest(p), "mode": oct(st.st_mode & 0o777)}
    return out
with tempfile.TemporaryDirectory() as root:
    files = {"relay.conf": "listen 10.30.0.5:8443\nupstream hist-01:443\nhmac_key_file /etc/relay/key\n",
             "allow.list": "PS-04\nPS-07\nPS-09\n", "units/relay.service": "[Service]\nUser=relay\n"}
    for rel, text in files.items():
        p = os.path.join(root, rel); os.makedirs(os.path.dirname(p), exist_ok=True)
        with open(p, "w") as f: f.write(text)
        os.chmod(p, 0o640)
    base = snapshot(root)
    print("baseline entries:", len(base), "| relay.conf", base["relay.conf"]["sha256"][:16])
    # simulated changes: one approved (change ticket CHG-118), one not, one permission change, one new file
    with open(os.path.join(root, "allow.list"), "a") as f: f.write("PS-11\n")
    with open(os.path.join(root, "relay.conf"), "a") as f: f.write("debug_listen 0.0.0.0:9000\n")
    os.chmod(os.path.join(root, "units/relay.service"), 0o666)
    with open(os.path.join(root, "units/helper.sh"), "w") as f: f.write("#!/bin/sh\n")
    approved = {"allow.list": "CHG-118"}
    now = snapshot(root)
    for rel in sorted(set(base) | set(now)):
        b, n = base.get(rel), now.get(rel)
        if b == n: continue
        kind = "added" if b is None else "removed" if n is None else "content" if b["sha256"] != n["sha256"] else "mode " + b["mode"] + "->" + n["mode"]
        print(f"{rel:<20} {kind:<16} {'approved ' + approved[rel] if rel in approved else 'UNAPPROVED - investigate'}")
    print("baseline json bytes:", len(json.dumps(base, sort_keys=True)))

Expected output (Python 3.13.5):

baseline entries: 3 | relay.conf 1defd9289ede0120
allow.list           content          approved CHG-118
relay.conf           content          UNAPPROVED - investigate
units/helper.sh      added            UNAPPROVED - investigate
units/relay.service  mode 0o640->0o666 UNAPPROVED - investigate
baseline json bytes: 342

The script creates its files in a temporary directory, so you can run it anywhere. Note that the digest printed for relay.conf depends only on the file's content: if you change one character of the synthetic content in the script, the digest changes completely.

Compare the output with the RLY-01 week described above: four differences, of which only the PS-11 allowlist entry under CHG-118 has a change record. Then make one edit of your own inside the script, for example add a second debug line or change a mode from 0640 to 0644, rerun it and confirm the comparison reports exactly that difference and nothing else. A baseline that reports more or less than you changed is not yet reliable enough to be evidence in an investigation.

6.8 Common errors and limits

File integrity detects change; it does not tell you whether the change was malicious, and it says nothing about changes in memory or in files you did not baseline.

Exercises — chapter 6

EX016 — Hardening review. Objective: apply hardening as subtraction. Inputs: a synthetic listing for RLY-02: listening on 0.0.0.0:22, 10.30.0.6:8443, 0.0.0.0:9000, 0.0.0.0:111; installed packages include a compiler and a desktop environment; relay runs as root. Constraints: propose changes only; each needs a reason. Steps: (1) list every change; (2) mark which need a change ticket and which can be done in the next standard change. Expected evidence: table. Rubric: 3 = SSH bound to management interface, debug 9000 removed, port 111 (RPC) disabled, compiler and desktop removed, relay moved to an unprivileged account with restrictions; sensible change classification; 2 = most; 1 = generic; 0 = none.

EX017 — Protect the baseline. Objective: design baseline storage. Inputs: Lab 6. Constraints: two designs. Steps: (1) describe storing the baseline off-host on a write-once location; (2) describe signing the baseline with a key not held on the relay; (3) compare what each protects against. Expected evidence: half page. Rubric: 3 = both designs correct; notes that an attacker with root on the relay can change files but cannot change an off-host or signed baseline undetected; notes that the comparison tool on the host itself can be subverted, so comparison should also run from outside; 2 = one design; 1 = vague; 0 = none.

EX018 — Hypervisor placement. Objective: reason about shared platforms. Inputs: proposal to run RLY-01 (station-facing), HIST-01 (corporate-facing) and the hospital's clinical gateway as guests on one FSTS hypervisor to save cost. Constraints: do not reject automatically; state conditions. Steps: (1) list what the zones would now share; (2) list conditions under which you would accept it; (3) name the residual risk and its owner. Expected evidence: one page. Rubric: 3 = shared hardware, hypervisor administrators, management network, storage and a single failure point across two sectors; conditions such as separate management zone, restricted admin group with MFA, separate virtual networks with no bridging, documented capacity headroom, and a failure plan for losing the host; residual risk owned by named service owners; 2 = partial; 1 = flat yes/no; 0 = none.

Chapter synthesis

Keep servers small and known: remove what the function does not need, run services under dedicated unprivileged accounts, bind listeners to declared addresses, and treat configuration files and their permissions as security-relevant. Baseline the files that matter with a cryptographic hash, protect the baseline, and investigate every unexplained difference. Virtualization simplifies operations but concentrates control in the hypervisor and its administrators; record which zones share a host.

Continue studying — chapter 06 of 30

← Chapter 05 · Course chapter index · Chapter 07 →

Continue to the next authored lesson.

Worked answers

EX016 — Hardening review. Bind SSH to the management interface only (normal change, because a mistake locks administrators out); remove the debug listener on 0.0.0.0:9000 (normal change, after preserving evidence of who enabled it — Chapter 20); disable RPC on port 111 (standard change if a procedure exists); remove the compiler and desktop environment (standard change); move the relay from root to a dedicated relay account with filesystem restrictions (normal change with testing). Each change has a reason tied to Sections 6.1–6.2.

EX017 — Protect the baseline. Design 1: after each approved change, the baseline is exported to a write-once store off the host (an append-only bucket or a server the relay administrators cannot modify). Design 2: the baseline file is signed with a key held by the security team, not on the relay; the comparison verifies the signature first. An attacker with root on the relay can alter files and even the local baseline copy, but cannot alter the off-host or signed baseline undetected. Because the comparison tool on the relay could itself be subverted, also run the comparison from outside (collect hashes remotely, or compare collected files off-host).

EX018 — Hypervisor placement. Shared: physical hardware and its failure; hypervisor administrators (who effectively administer all guests); management network; storage and snapshots; patch schedule. Conditions for acceptance: hypervisor management in its own zone reachable only from the jump host; a small hypervisor admin group with MFA and logging; separate virtual networks with no bridging between station-facing and corporate-facing guests; documented capacity headroom for all guests at peak; tested plan for losing the host (what fails for water and the hospital at once). Residual risk: a hypervisor compromise or failure affects two sectors; accepted jointly by the Water and hospital service owners. Rejecting outright without conditions earns less credit than this.