Blog ·
Een export die je kunt narekenen
Een AVG-export als duurzame taak: een tijdelijk bestand dat op zijn plek hernoemd wordt, een sha256 in de bon, een eenmalig token en één map in twee rollen.
Door Provibr
Artikel 20 van de AVG geeft iemand het recht zijn gegevens te ontvangen. Op een hostingplatform is dat geen klein bestandje. Een organisatie-export leest ruwweg zeventig secties, elk begrensd op vijfentwintigduizend rijen, en dat duurt minuten in plaats van milliseconden.
Tot voor kort werd de onze in een server-action gebouwd: een webverzoek stelde het geheel in het geheugen samen en gaf het als één string terug in het antwoord. Dat werkt tot en met het account waar het niet meer werkt, en dat account is precies het account dat de export het hardst nodig heeft.
Het is een taak, en er is maar één weg
Een export is nu een duurzame operatie met vier stadia: in de wachtrij, verzamelen, inpakken, klaar. Een worker in de gateway pakt hem elke dertig seconden op, zet één rij op slot, bouwt de secties, schrijft het bestand en geeft een token terug.
Vier getallen houden het geheel bij elkaar, en elk ervan is een besluit en geen standaardwaarde.
| Grens | Waarde | Waarom juist die |
|---|---|---|
| Rijen per sectie | 25.000 | Alles daarboven is een rapport en geen inzageverzoek, en de afkapping wordt benoemd in plaats van verstopt |
| Downloadlink | 24 uur | Lang genoeg om op te halen, kort genoeg dat een oude link in een mailbox niets waard is |
| Het bestand op schijf | 7 dagen | Het is een volledige kopie van alles wat wij bewaren, en dat hoort geen archief te worden |
| De vastlegging van wat er geleverd is | 90 dagen | Het bewijs dat een recht is uitgeoefend overleeft het bestand dat eruit kwam |
De oude synchrone weg is niet blijven staan als kortere weg voor kleine accounts, en dat was een bewuste keuze en geen luiheid.
Twee wegen zijn twee waarheden. Welke van de twee gelopen wordt zou afhangen van een schatting vooraf, en de schatting die er hier toe doet is is dit account klein, en dat is precies wat je niet kunt weten voordat je de secties geteld hebt. Zit je ernaast, dan valt de export om op de weg waar geen vangnet zit.
Twee wegen zijn ook twee soorten bewijs. De auditrij, de bon met een controlesom erin en de lijst met afgekapte secties bestaan alleen op de takenweg. Een kleine export zou stil zonder dat alles geleverd worden, en de vraag wat hebben we in maart uitgeleverd zou een antwoord krijgen dat afhangt van hoe groot het account destijds was.
De prijs is één klik extra, en die klik zou er toch al zijn: langlopend werk hoort in de takenlade, en daar staat hij nu, met een voortgangsbalk in plaats van een browser die twee minuten niets doet.
Waar de code moest komen te staan
De bouwers zijn uit de webapplicatie verhuisd naar het pakket dat de databasetoegang bezit. Dat was geen opruiming. Het gateway-image kopieert de gateway en de gedeelde pakketten en kopieert de webmap niet, dus een import die naar web/lib reikt compileert lokaal en ontbreekt in productie. Het is een gemeten grens en geen stijlkwestie.
De exportoperatie heeft bovendien resourcesoort account, en het is de eerste soort zonder module. Elke andere duurzame operatie gaat over een server, een agent, een stuk hardware of een automation, en elk daarvan valt onder een rechtenmodule die bepaalt wie hem mag zien. Een accountexport valt onder niemand: de rechtenset van een lid draagt rechten en geen identiteit. Zichtbaarheid wordt beantwoord door te vragen of de kijker degene is die hem aanvroeg, en het live-kanaal geeft voor iedereen anders onwaar terug.
Een tijdelijk bestand, en dan hernoemen
Het bestand wordt geschreven als <naam>.part en daarna op zijn plek hernoemd. Hernoemen binnen één map is atomair, dus een lezer kan nooit een half bestand krijgen, en een half bestand is erger dan geen bestand: het heeft een controlesom die niet klopt en niets dat zegt waarom.
De controlesom is een sha256 van de bytes, en die gaat naast de omvang in de bon. Dat is wat een export narekenbaar maakt in plaats van alleen afgeleverd. Wie het bestand over een jaar nog heeft kan nog steeds aantonen dat het het bestand is dat wij maakten.
De map is een bind mount die in twee containers hangt: lees-schrijf in de gateway, die schrijft, en alleen-lezen in de webapplicatie, die uitlevert. Twee processen, twee rollen, één map.
Die mount is makkelijk te vergeten, en vergeten levert een heel specifiek en heel verwarrend foutbeeld op. De taak zegt klaar. De download geeft 410. Niets in het log zegt verkeerde map, want voor elk van beide processen werkte alles. De code waarschuwt daarom één keer, luidruchtig, als de map niet ingesteld is, en de val-terug is een pad naast de repository en niet de tijdelijke map van het systeem: een bestand in een tijdelijke map verdwijnt bij een herstart, en dan wijst een rij die zegt klaar om te downloaden naar niets.
Het token is eenmalig, en eenmalig is één statement
De downloadlink draagt een token dat vierentwintig uur geldig is, terwijl het bestand zelf zeven dagen blijft staan.
Beide grenzen zijn nodig. Alleen eenmalig zou een token opleveren dat maanden bruikbaar blijft zolang niemand erop klikt. Alleen tijdgebonden zou hem een dag lang herbruikbaar maken voor iedereen die de URL ziet staan: een proxylog, een browsergeschiedenis, een gedeelde mailbox. Wie te laat is vraagt een nieuwe export aan, en dat kost een minuut en levert een verse, correcte kopie op in plaats van een link die een week in een postvak rondslingert.
De grendel die eenmalig werkelijk afdwingt is niet het tijdstip. Het is één voorwaardelijk statement: werk de rij bij, zet het downloadtijdstip, waar het downloadtijdstip nog leeg is. Twee gelijktijdige verzoeken met hetzelfde token raken samen precies één rij en de tweede krijgt er nul terug. Kijken en dan schrijven zou twee statements zijn en dus twee kansen om ertussen te komen.
Het token op zichzelf is ook niet genoeg. De aanroeper geeft de ingelogde gebruiker mee en dat moet degene zijn die de export aanvroeg, en daarom draait die route onder het sessiebeleid en niet onder het tokenbeleid. En de eigendomscontrole gaat vóór elke andere weigering: wie het token niet hoort te hebben mag er niet uit leren of de export verlopen of al opgehaald is.
Zeven dagen voor het bestand is met opzet kort. Het bestand is een volledige kopie van alles wat wij over een persoon of een organisatie bewaren, en zolang het bestaat is het een tweede plek waar dat alles staat. Een backup neemt het mee, en de zorgvuldige allowlist die bepaalt wat er in een export komt deed zijn werk op het moment dat het bestand geschreven werd en beschermt daarna niets meer. Het is nadrukkelijk geen bewaartermijn van de gegevens zelf, die in de database staan met hun eigen regels. Het is de bewaartermijn van een afschrift.
Afkappen is een openstaande check en geen voetnoot
Elke sectie stopt bij vijfentwintigduizend rijen. Een sectie die tegen dat plafond aanliep wordt in de envelop genoemd en verschijnt in de bon als openstaande check: iets waar de lezer geacht wordt iets mee te doen, náást de uitkomst en niet erin begraven. Een export die stil bij het plafond stopte zou een antwoord op een inzageverzoek zijn dat onvolledig is zonder dat te zeggen, en dat is erger dan een weigering.
Gemeten met een account dat vijfentwintigduizend en vijf rijen in één sectie droeg: de sectie kapte af, de openstaande check verscheen, en een tweede poging op dezelfde downloadlink gaf 410.
Eén tabel bewust weggelaten, met de reden erbij
Niet alles gaat mee, en de lijst met wat er buiten blijft draagt een geschreven onderbouwing per tabel in plaats van één beleidszin bovenaan.
Het duidelijkste voorbeeld is het usage-grootboek van de monitoring. Daar staan drie tabellen: de uuremmers, de grenzenrij, en de rij per verstuurde check eronder. De eerste twee gaan mee, want wat een inzageverzoek wil weten is hoeveel er voor mij gemeten is en wat mijn account mocht, en dat staat precies in die twee. De derde is honderdduizenden rijen per maand met dezelfde totalen, en het is administratie van onze verzending in plaats van iets dat de klant invoerde.
Die redenering heeft een datum. Zou dat grootboek ooit een factuurregel gaan dragen, dan hoort de weglating opnieuw gewogen te worden, want de bewijsrij achter een boeking is een ander soort gegeven dan een verzendlog. Dat naast de uitzondering opschrijven is het verschil tussen een besluit en een gewoonte.
Twee andere tabellen blijven om dezelfde reden buiten: de administratie per poging onder een verschuldigde meting, en de planningstikken zelf. Allebei zeggen ze iets over hoe wij het uitvoerden en niets over de persoon die het vraagt.
Hoe het er van buitenaf uitziet
Iemand vraagt zijn gegevens op. Er verschijnt een kaart in de takenlade met een voortgangsbalk. Een paar minuten later is er een melding, een downloadlink die één keer werkt, en een bon die de omvang, de controlesom en alles wat afgekapt werd benoemt. Zeven dagen later is het bestand weg en de administratie van wat er geleverd is blijft negentig dagen staan.
Niets daarvan is opmerkelijk, en dat is de bedoeling. Het opmerkelijke is wat er ontbreekt: geen weg waarlangs dezelfde aanvraag een ander soort bewijs oplevert, geen bestand dat gelezen kan worden terwijl het half geschreven is, en geen link die blijft werken nadat hij gebruikt is.
Uit het platformwerk van Provibr. Waarom het operatieoverzicht bestaande rijen leest en nooit terugschrijft staat in projecteren, nooit vervangen, en waarom een voortgangsbalk hier weigert een eindtijd te voorspellen staat in een voortgangsbalk die weigert te gokken.