Find every copy of one person's data, and who decides about it

short · 45 min · Objective 3.3

Task

Build a data inventory for a small synthetic estate that records, for every store, where it is, which region it sits in, who owns it, who runs it and when its retention ends. Then use the inventory to answer the questions this lesson turns on: where is all of one person's data, which copy is in the wrong place, and which store should already have been destroyed.

Steps

  1. Create a synthetic estate under /tmp/estate: crm.csv, a small SQLite database orders.db, a docs/ directory of text files, app.log, and backup/crm-2019.csv, an old export. Put one synthetic person, identifier SUBJ-0001, in exactly three stores -- crm.csv, orders.db and the old export -- and nowhere else.
  2. Write /tmp/inventory.csv with the header store,path,region,owner,custodian,retention_until, one row per store. Give each store a business owner and an IT custodian. Record a region for each as if they were hosted in different places: eu-west for four of them and us-east for the old export, as if a backup had been replicated abroad. Write retention_until as YYYY-MM-DD, and give the old export a date already in the past.
  3. Write /tmp/find-subject.sh <identifier>: it reads the path column of the inventory, searches each store for the identifier -- the database with sqlite3, the rest with grep -r -- and prints one line, found in <store>, for each store that holds it. Driving the search from the inventory is the point: a store missing from the inventory is a store the search cannot find.
  4. Run it for SUBJ-0001 and check the answer against what you built: three stores, not four and not two.
  5. Write /tmp/estate-findings.md naming the store past its retention date and the store in the wrong region, and for each, which role acts: the owner decides, the custodian carries it out.

Verify

bash /tmp/find-subject.sh SUBJ-0001
python3 - <<'PY'
import csv, datetime, subprocess
inv = list(csv.DictReader(open('/tmp/inventory.csv')))
assert len(inv) >= 5, 'fewer than five stores inventoried'
for r in inv:
    assert r['owner'].strip() and r['custodian'].strip(), 'no owner or custodian for ' + r['store']
    assert r['owner'].strip().lower() != r['custodian'].strip().lower(), 'owner and custodian are the same for ' + r['store']
out = subprocess.run(['bash', '/tmp/find-subject.sh', 'SUBJ-0001'], capture_output=True, text=True).stdout
hits = out.lower().count('found in')
print('subject found in', hits, 'store(s)')
assert hits == 3, 'expected exactly three - the search misses a store or matches the wrong one'
today = datetime.date.today()
expired = [r['store'] for r in inv if datetime.date.fromisoformat(r['retention_until'].strip()) < today]
regions = sorted({r['region'].strip() for r in inv})
print('past retention:', expired, '| regions:', regions)
assert expired, 'no store is past its retention date'
assert len(regions) > 1, 'every copy is in one region - the location finding is missing'
PY
grep -ciE "owner|custodian" /tmp/estate-findings.md

The search must find the subject in exactly three stores: two means it misses a format, usually the database, and four means it matches something it should not. Either way the inventory could not answer an access request correctly. The owner and custodian must differ on every row, because a store whose owner is the person who runs it is the collapsed role the lesson calls a finding.

Notes

The old export fails twice. It is past retention, so it is pure liability, and it sits in the wrong region, which is exactly how the lesson says organisations get caught: the primary is in the right place and a copy is not. A subject access request would have forced you to find it and disclose it.

This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.