36.3 Hozzáférés, titkok és adatminimalizálás

36.3.1 Cél és konkrét helyzet

A Késő címke, teljesítmény és újratanítás alfejezetben felépített késői címke monitorozó szolgáltatás most a fejlesztői gépén fut, és a Streamlit mint ellenőrizhető bemutató streamlit demója ugyanazt a modellt tölti be. A CI: kódellenőrzés és kis számítás új környezetben CI-ja csak kis adatos teszteket futtat; a titkok és a személyes adatok kezelése viszont a helyi konfigurációban, naplókban és a kifelé irányuló kapcsolatokban dől el. Ebben az alfejezetben egy fiktív projektet, a northstar-monitor mappát auditáljuk: megkeressük, hol szivárog titok vagy indokolatlan személyes azonosító, és megtervezzük a javított határokat.

Konkrét bemenetek:

A megfigyelési egység egy-egy fájlsor. Az audit célja, hogy minden sorhoz besorolást adjon: inline-secret, raw-pii, env-reference vagy ok. Előzetes becslésként, mielőtt a kódot látnád: hány sorban vársz valódi titkot, hányban nyers személyes azonosítót, és a konfigurációs fájlban miért lehet nulla valódi titok? Jegyezd fel a becslésedet, a szakasz végén ellenőrizzük.

36.3.2 Fogalmi magyarázat

36.3.2.1 Secret environment

A titok (secret) olyan hitelesítő adat, amelynek ismerete önmagában hozzáférést adhat: jelszó, API-kulcs, token, privát kulcs. A biztonságos munkafolyamat elválasztja a titok tárolását a titok hivatkozásától. A kód nem a tényleges jelszót tartalmazza, hanem környezeti változóra hivatkozik:

import os
password = os.environ["DB_PASSWORD"]

A fejlesztői .env fájl a titkokat tárolja, ezért nem kerülhet verziókezelőbe. A .env.example ezzel szemben csak a változóneveket és replace_me helyőrzőket tartalmaz, és bekerülhet a repositoryba. Ha a .env mégis commitolódik, a puszta törlés a Git történetéből nem elég: a titkot érvényteleníteni, azaz rotálni kell. A környezeti változó sem automatikus védelem; ha a folyamat a környezetét kiírja egy naplóba, a titok ugyanúgy szivárog.

36.3.2.2 Least privilege

A legkisebb jogosultság elve (least privilege) azt mondja, hogy egy folyamat vagy felhasználó csak a feladatához szükséges minimális jogot kapja meg. A monitorozó szolgáltatásnak például olvasnia kell a predikciós táblát, de nincs szüksége DROP TABLE jogra; a batch predikció írhat a saját eredménytáblájába, de nem törölheti a nyers rendeléseket. A jogokat célszerű szerepkörönként szétválasztani: a monitor_readonly adatbázis-felhasználó más kapcsolati karakterláncot kap, mint a prediction_writer. Az audit szkript maga is legyen korlátozott: olvashatja a konfigurációt és a naplómintát, de ne kapjon írási jogot ugyanarra a mappára, ahol a titkok élhetnek.

Kis kontrollpélda: ha a monitorozó folyamat véletlenül DELETE FROM predictions utasítást hajtana végre, a least privilege szerint a művelet már az adatbázis-engedély szintjén meghiúsul, mielőtt a Python-kód tovább futna.

36.3.2.3 Logging redaction

A naplóredakció (logging redaction) azt jelenti, hogy a naplóüzenet eleve nem tartalmazhat titkot vagy felesleges személyes azonosítót. Nem a napló utólagos cenzúrázása az elsődleges védelem, hanem a naplózó hívás megtervezése: a logger formátumában nem szerepelhet a teljes kérés, a fejléc, az email vagy a jelszó. Helyette a napló kap egy pszeudonim hivatkozást vagy csak egy logikai tényt.

Rossz napló Javított napló
user=customer@example.com token=sk-abc123 user_ref=USER-7F3A auth=ok
password=ChangeMe9! db_auth=from-env
customer_id=CUST-0042 customer_ref=USER-7F3A

A naplóban a redakció célja nem a szépség, hanem az adatminimalizálás:

Biztonsági teszt. A redakció nem lehet kizárólag regex-alapú: a strukturált naplózásnál engedélyezett mezők listájával (allowlist), titokszkenneléssel és jogosultsággal védett naplótárolóval kell kiegészíteni. Az álnevesítés nem tesz személyes adatot automatikusan anonimmá. ha a diagnózishoz elég tudni, hogy a hitelesítés sikeres volt, akkor a jelszó soha ne jelenjen meg.

36.3.2.4 Retention

A megőrzési idő (retention) azt rögzíti, hogy az adott adatfajtát meddig szabad tárolni, és mi történik utána. A CI: kódellenőrzés és kis számítás új környezetben alfejezetben az átmeneti modellartefaktumok rövid megőrzését láttuk; ugyanez a naplókra és a pszeudonim leképezésekre is igaz. A forever nem alapértelmezés. Például az Anomália és ritka esemény felügyelet nélkül emberi anomália-vizsgálati listája hét napig él, utána csak az összesített P@k marad, az egyedi azonosítók nélkül. A törlést is tesztelni kell: egy retention_check.py naponta törölje a határidőnél régebbi fájlsorokat, és a CI ellenőrizze, hogy a törlés után a lemezhasználat ténylegesen csökken.

36.3.2.5 Pseudonym

A pszeudonimizálás (pseudonymization) az azonosító lecserélése egy kódra. A customer_id=CUST-0042 értéket leképezhetjük USER-7F3A alakra egy titkos, hosszú élettartamú kulccsal. A pszeudonim azonosító azonban nem anonim azonosító: ha a leképező kulcs vagy a maradék adatok rendelkezésre állnak, a kapcsolat visszaállítható. Egy ritka rendelési kombináció — például egy szokatlan basket_minor és egy ritka régió együttese — akár önmagában is egyetlen ügyfélre mutathat. A pszeudonim ID tehát továbbra is közvetett azonosításra alkalmas adatként kezelendő.

36.3.2.6 Provider boundary

A szolgáltatói határ (provider boundary) azt a vonalat jelöli, ahol az adat elhagyja a saját környezetünket. Minden kifelé irányuló kérésnél külön szerződés kell: mi az a minimális séma, amelyet a külső szolgáltató megkaphat. Ha a monitorozó szolgáltatás egy külső metrika-API-nak küld állapotot, a kimenő üzenet ne tartalmazza a nyers emailt, a kosár tartalmát vagy a pontos vásárlási időpontot; elég a modellverzió, a pszeudonim eseményazonosító, a predikció és a későbbi kimenet.

Példa kimenő szerződés:

{
  "model": "northstar-late-v3",
  "event_ref": "evt-7f3a",
  "prediction": 0.84,
  "outcome_label_days": 9,
  "provider_status": "ok"
}

A határ túloldalán lévő folyamat naplója is a mi adatvédelmi felelősségünk része, ezért a kimenő sémát ugyanúgy tesztelni kell, mint a belső konfigurációt.

36.3.3 Teljes minimális munkapélda

Induljunk ki a következő fájlokból. A munkakönyvtár ~/projects/northstar-monitor, a példa Python 3.12-t és csak a standard libraryt használ.

config.yaml:

database:
  host: db.internal
  user: monitor_readonly
  password: ${DB_PASSWORD}
model_artifact: artifacts/northstar_late_v3.joblib
retention_days: 30

.env.example:

DB_PASSWORD=replace_me
MONITOR_API_KEY=replace_me

logs/monitor_sample.log:

2026-10-20T09:15:00Z INFO monitor start user=customer@example.com customer_id=CUST-0042
2026-10-20T09:15:01Z DEBUG db_connect host=db.internal user=monitor password=ChangeMe9!
2026-10-20T09:15:02Z INFO prediction model=northstar-late-v3 event_id=evt-7f3a score=0.84
2026-10-20T09:15:03Z ERROR api call failed api_key=sk-live-7f3a9c2b1e5f8d4a

A naplóminta szándékosan tartalmazza a két leggyakoribb hibát: nyers emailt és ügyfél-azonosítót, egy beégetett jelszót, valamint egy API-kulcsot. Az audit szkript a fájlsoronkénti besorolást állítja elő. Fontos tervezési döntés, hogy a találat kimenete nem írja ki újra a titok tényleges karaktereit, csak a pozíciót és a hosszt; így az auditjelentés sem válik másodlagos szivárgási forrássá.

config_audit.py:

from pathlib import Path
import re

PROJECT = Path("~/projects/northstar-monitor").expanduser()
AUDIT_FILES = ["config.yaml", ".env.example", "logs/monitor_sample.log"]

SECRET_RULES = {
    "inline-password": re.compile(
        r"password\s*[:=]\s*([^\s'\"${]+)", re.I
    ),
    "api-key-literal": re.compile(r"\bsk-[A-Za-z0-9_-]{8,}"),
}

PII_RULES = {
    "raw-email": re.compile(
        r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
    ),
    "raw-customer-id": re.compile(r"\bCUST-\d{4}\b"),
}

PLACEHOLDER_OK = re.compile(r"replace[_ -]?me", re.I)

def audit_file(path: Path):
    findings = []
    for lineno, line in enumerate(
        path.read_text(encoding="utf-8").splitlines(), 1
    ):
        if PLACEHOLDER_OK.search(line):
            continue
        for rule_name, pattern in {**SECRET_RULES, **PII_RULES}.items():
            for m in pattern.finditer(line):
                findings.append({
                    "file": str(path.relative_to(PROJECT)),
                    "line": lineno,
                    "rule": rule_name,
                    "match": (
                        f"col {m.start() + 1}, "
                        f"length {len(m.group(0))}"
                    ),
                })
    return findings

for name in AUDIT_FILES:
    for finding in audit_file(PROJECT / name):
        print(finding)

Futtatás Linux/macOS terminálból:

cd ~/projects/northstar-monitor
python config_audit.py

Az alábbi kimenet szemléltető, a megadott bemenetből a szabályok alapján levezetett, nem helyi futásból mért:

{'file': 'logs/monitor_sample.log', 'line': 1, 'rule': 'raw-email', 'match': 'col 46, length 21'}
{'file': 'logs/monitor_sample.log', 'line': 1, 'rule': 'raw-customer-id', 'match': 'col 80, length 9'}
{'file': 'logs/monitor_sample.log', 'line': 2, 'rule': 'inline-password', 'match': 'col 58, length 11'}
{'file': 'logs/monitor_sample.log', 'line': 4, 'rule': 'api-key-literal', 'match': 'col 47, length 24'}

36.3.4 Eredmény értelmezése

A kézi kontroll négy találatot vár. Az első naplósorban az email és a CUST-0042 nyers azonosító külön-külön találat; a második sorban a ChangeMe9! jelszó; a negyedik sorban a sk-live-... kulcs. A harmadik sor tiszta, mert a predikció pontszáma és a modellverzió önmagában nem titok és nem közvetlen személyes azonosító.

A konfigurációs fájlban a password: ${DB_PASSWORD} sor nem hoz inline-password találatot, mert a szabály karakterosztálya kizárja a $ jelet. Ez a helyes viselkedés: a ${DB_PASSWORD} környezeti hivatkozás, nem beégetett titok. A .env.example sorai a replace_me helyőrző miatt kimaradnak; a fájl tehát publikálható a repositoryban. A naplóban szereplő titkok viszont már kompromittáltnak tekintendők: a jelszót és az API-kulcsot rotálni kell, a naplófájl korábbi másolatait pedig a retention szabály szerint törölni.

A javított napló lehet:

2026-10-20T09:15:00Z INFO monitor start user_ref=USER-7F3A occurred=1
2026-10-20T09:15:01Z DEBUG db_connect host=db.internal user=monitor auth=from-env
2026-10-20T09:15:02Z INFO prediction model=northstar-late-v3 event_id=evt-7f3a score=0.84
2026-10-20T09:15:03Z ERROR external call failed provider_ref=monitor-gw status=401

Ezen a javított naplón az audit már nulla találatot ad, mert a USER-7F3A nem illeszkedik a CUST-\d{4} mintára, és egyetlen sorban sem szerepel email vagy beégetett titok.

36.3.5 Feladatok

36.3.5.1 1. Értelmezés

A fejlesztő a .env fájlt felvette a .gitignore-ba, ezért úgy gondolja, a jelszó biztonságban van. Miért nem elegendő ez, ha a ChangeMe9! érték mégis megjelenik a monitor_sample.log-ban? Fogalmazd meg a titok tárolási és a naplóredakciós hiba különbségét.

36.3.5.2 2. Implementálás

Bővítsd a config_audit.py szkriptet egy env-reference szabállyal, amely a ${DB_PASSWORD} alakú környezeti hivatkozásokat jelöli. A bővített kódban a konfigurációs fájl password: ${DB_PASSWORD} sora env-reference besorolást kapjon, de ne inline-password hibát. Add meg a szabályt reguláris kifejezésként, és indokold, miért nem zavarja össze a két szabályt a sorrend.

36.3.5.3 3. Hibadiagnózis

Adott a következő, állítólag már redakált naplósor:

2026-10-20T10:00:00Z INFO user=***@example.com customer_id=CUST-0042

Miért nem tekinthető ez megfelelő adatminimalizálásnak? Nevezd meg a két konkrét hibát, és írd le a javított sort a pszeudonim hivatkozásos mintával.

36.3.5.4 4. Megváltozott feltételű transzfer

A termékcsapat a monitorozó napló megőrzési idejét 30 napról 365 napra emelné, hogy hosszabb trendeket vizsgálhasson. Milyen kockázatot hordoz a nyers napló hosszú megőrzése, és milyen feltételekkel fogadnád el a változtatást? Adj konkrét retention-policy vázlatot legalább három adatfajtára, és írd le, milyen ellenőrzést futtatnál a törlési folyamatra.

36.3.6 Megoldások és indoklás

36.3.6.1 1. megoldás

A .gitignore csak azt akadályozza meg, hogy a .env a Git historyba kerüljön. Ha a futó folyamat a környezeti változóból kiolvasott jelszót a logger üzenetébe illeszti, a titok a naplófájlba, a naplóaggregátorba, a mentésekbe és minden olyan rendszerbe eljut, ahová a naplót továbbítják. A tárolási hiba tehát a .env commitolása lenne; ez most nem történt meg. A naplóredakciós hiba viszont független attól, hogy a titok honnan érkezett: a jelszó értékének egyáltalán nem szabad megjelennie a naplóban. A két hiba külön kezelendő, és a .gitignore megléte nem mentesíti a naplózó hívást.

36.3.6.2 2. megoldás

Az új szabály:

ENV_REF = re.compile(r"\$\{[A-Za-z_][A-Za-z0-9_]*\}")

Az audit_file ciklusában először a környezeti hivatkozást kell vizsgálni. Ha password: ${DB_PASSWORD} szerepel, a ${DB_PASSWORD} illeszkedik az ENV_REF mintára, ezért env-reference találatot adunk. Az inline-password szabály karakterosztálya már kizárja a $ jelet, így ugyanaz a sor nem lesz hibás jelszó-találat is. A sorrend azért nem zavaró, mert a két szabály különböző részt illeszt: az env-reference a ${...} blokkra, az inline-password pedig csak akkor talál, ha a jelszó értéke $ nélkül kezdődik. A bővített ciklus a találatot {"rule": "env-reference", ...} formában írja ki, a konfigurációs fájlban tehát nem hiba, hanem ellenőrzött hivatkozás lesz.

Ellenőrző invariant: a bővített kód a megadott config.yaml-ra pontosan egy env-reference találatot ad, a logs/monitor_sample.log-ra pedig továbbra is négy hibát; a két halmaz diszjunkt, mert egyetlen sor sem kerülhet egyszerre mindkét halmazba a $ kizárása miatt.

36.3.6.3 3. megoldás

A ***@example.com maszk két okból is rossz. Egyrészt a domain megmarad, így a *** hosszával és a környező mezőkkel együtt az email gyakran visszafejthető; másrészt a CUST-0042 nyers azonosító korlátlanul összekapcsolható a rendelési előzménnyel. A megfelelő sor nem tartalmaz emailt vagy nyers ügyfél-azonosítót:

2026-10-20T10:00:00Z INFO user_ref=USER-7F3A event_seen=1

A USER-7F3A pszeudonim hivatkozás leképezése külön, hozzáférés-korlátozott, rövid retentionű táblában él. A diagnózishoz csak az kell, hogy egy ismert felhasználói esemény megtörtént, nem pedig az, hogy ki volt az.

36.3.6.4 4. megoldás

A nyers napló 365 napos megőrzése növeli az expozíciós időt: minden későbbi adatszivárgás több naplósorra terjed ki, és a pszeudonim leképezés is tovább él. A változtatást csak akkor érdemes elfogadni, ha a hosszú megőrzés nem a nyers azonosítókra, hanem az aggregált statisztikára vonatkozik. Lehetséges policy:

Adatfajta Retention
Nyers monitorozó napló 30 nap
Pszeudonim hivatkozásos napló 90 nap
Aggregált napi statisztika 365 nap
Modellartefaktum és manifest 365 nap

A modellartefaktum csak akkor maradhat 365 napig, ha a modell nem tárol közvetlen ügyfél-azonosítót, és a betöltési határt a Streamlit mint ellenőrizhető bemutató modellkártyája rögzíti. A törlési folyamatra naponta futó retention_check.py ellenőrzi, hogy a határidőnél régebbi fájlok eltűntek, és a lemezhasználat a várt mértékben csökkent. A provider boundary felé küldött üzenetbe a hosszú trendhez is csak aggregált értékek kerülnek: modellverzió, nap, predikcióátlag, eseményszám.

36.3.7 Gyakori tévedés

A leggyakoribb tévedés azt hinni, hogy a pszeudonim azonosító automatikus anonimitást ad. A CUST-0042 → USER-7F3A leképezés attól még visszafordítható, ha a leképező kulcs vagy a maradék adatok hozzáférhetők. A modell maga is hordozhat érzékeny információt: ha egy ritka basket_minor és region kombináció egyetlen ügyfélre mutat, akkor a pszeudonim azonosítóval ellátott predikciós sor közvetett azonosításra alkalmas marad. Ez visszavezet az Anomália és ritka esemény felügyelet nélkül anomáliakeresés tanulságához: az emberi vizsgálati lista is csak a feltétlenül szükséges mezőket tartalmazhatja, mert a pontszám-rangsor önmagában nem mentesít a minimalizálás alól. A CI: kódellenőrzés és kis számítás új környezetben rövid artifact retentionje ugyanezt az elvet erősíti: a törlési határidő a védelem része, nem utólagos kényelmi lépés.

Önellenőrzés: futtasd az auditot a saját repositorydra a password, token, secret, api_key, AKIA és email mintázatokra. Ha egy találat a naplóban vagy a konfigurációban van, ne a találati sort töröld először, hanem kérdezd meg, miért volt ott egyáltalán, és rotáld a titkot, ha az érték valaha elhagyta a gépet.

36.3.8 Rövid összefoglaló

A titkok, hozzáférések és személyes adatok határait már a kódolás előtt meg kell jelölni. A környezeti változó a titok hivatkozására való, a .env.example csak a neveket publikálja; a naplóba soha nem kerülhet jelszó, kulcs, email vagy nyers ügyfél-azonosító. A legkisebb jogosultság, a naplóredakció és a megőrzési határidők együtt csökkentik a szivárgási felületet. A pszeudonim azonosító hasznos, de nem anonim, és a modell is hordozhat érzékeny mintázatot. A szolgáltatói határon csak a minimális szerződéses séma mehet át. A következő lépésben a IX. ellenőrző pont ezekből a döntésekből állít össze működő rendszert és bizonyítékokat.