RODO według projektu: wzorce architektoniczne dla usług publicznych
Jak zintegrować ochronę danych osobowych już na etapie projektowania usług cyfrowych PA: wzorce architektoniczne, techniki pseudonimizacji, minimalizacji danych i zarządzania zgodami zgodnie z art. 25 RODO.
Prywatność od samego początku w Pensylwanii: obowiązek regulacyjny i wybór architektoniczny
Ogólne rozporządzenie o ochronie danych (RODO), które weszło w życie 25 maja 2018 r., nie ogranicza się do nakładania obowiązków biurokratyczne dla administracji publicznej: art. 25 stanowi, że ochrona danych musi być zintegrowana już na etapie projektowania systemów informatycznych i procesów przetwarzających dane osobowe. Ta zasada, znany jako Prywatność już w fazie projektowania, zamienia zgodność z przepisami w jedno jakość architektoniczna oprogramowania.
Dla programisty lub architekta pracującego na włoskich systemach PA - rejestr cyfrowy, elektroniczna karta zdrowia, portale dostępu do usług z SPID lub CIE, systemy zarządzania procedurami administracyjnymi - zrozumieć i wdrożyć poprawnie RODO-by-Design nie jest opcjonalne. Sankcje przewidziane przez Gwaranta Organu Ochrony Danych Osobowych mogą osiągnąć 4% światowych rocznych obrotów podmiotów prywatnych; w przypadku agencji płatniczych konsekwencje obejmują blokady dostępu do Internetu leczenia, odszkodowania za szkody i znaczną utratę reputacji.
Czego dowiesz się w tym artykule
- 7 podstawowych zasad Privacy by Design i sposoby przekładania ich na konkretne decyzje architektoniczne
- Wzorce pseudonimizacji i anonimizacji baz danych i rządowych interfejsów API
- Implementacja wzorca minimalizacji danych w mikroserwisach PA
- Zarządzanie zgodami: architektura i wdrożenie systemu zgodnego z RODO
- Automatyczne przechowywanie i prawo do usunięcia danych w relacyjnych bazach danych
- Zgodne rejestrowanie audytu: jak śledzić zabiegi bez naruszania prywatności
- DPIA (Ocena Skutków Ochrony Danych) dla systemów wysokiego ryzyka
7 podstawowych zasad i ich wpływ na architekturę
Ann Cavoukian, była komisarz Ontario ds. informacji i prywatności, sformalizowała 7 zasad prywatności od samego początku, które RODO zostało wdrożone. Każda zasada przekłada się na konkretne wybory architektoniczne:
| Zasada PbD | Artykuł RODO | Wzór architektoniczny | Techniki betonowe |
|---|---|---|---|
| Proaktywne, a nie reaktywne | Artykuł 25 | Prywatność modelowania zagrożeń | Ocena ryzyka dla prywatności w fazie projektowania |
| Prywatność jako domyślna | Artykuł 25 ust. 2 | Domyślnie wyrażaj zgodę | Wyraźna zgoda, domyślnie minimalizacja |
| Zintegrowany z projektem | Artykuł 25 ust. 1 | Architektura oparta na prywatności | Pseudonimizacja, szyfrowanie w stanie spoczynku |
| Pełna funkcjonalność | Artykuł 5 | Unikanie o sumie zerowej | Prywatność + bezpieczeństwo nie są ze sobą sprzeczne |
| Kompleksowe bezpieczeństwo | Artykuł 32 | Głęboka obrona | TLS, szyfrowanie, zarządzanie kluczami |
| Widoczność i przejrzystość | Artykuł 13/14 | Ścieżka audytu + ujawnienie | Anonimowe logowanie, informacja o ochronie prywatności |
| Szacunek dla prywatności użytkowników | Artykuł 7/8/17 | Sterowanie zorientowane na użytkownika | Interfejs użytkownika zgody, prawo do bycia zapomnianym, przenośność |
Wzorzec 1: Minimalizacja danych w mikrousługach PA
Zasada minimalizacji (art. 5 ust. 1 lit. c RODO) wymaga, aby gromadzone dane były „adekwatne, istotne i ograniczone do tego, co jest to niezbędne do celów, w jakich są przetwarzane”. W architekturze mikrousług przekłada się to na wzorzec Minimalizacja danych na granicy: każda usługa musi otrzymać tylko te dane, których potrzebuje do działania jego specyficzną funkcję.
Rozważ skorzystanie z usługi weryfikacji tożsamości, aby uzyskać dostęp do świadczeń zdrowotnych. Usługa nie potrzebuje nazwy pełna informacja obywatela w celu sprawdzenia, czy przysługuje mu świadczenie: wystarczy mu anonimowy identyfikator i status uprawniony. Wzorzec jest implementowany poprzez Selektywne DTO (obiekty przesyłania danych). e zapytania projekcyjne.
# Pattern Data Minimization - Esempio Python/FastAPI
# Scenario: servizio prestazioni sanitarie PA
from pydantic import BaseModel
from typing import Optional
import hashlib
# SBAGLIATO: trasferisce dati non necessari
class CitizenFullDTO(BaseModel):
citizen_id: str
fiscal_code: str
first_name: str # Non necessario per verifica
last_name: str # Non necessario per verifica
birth_date: str # Non necessario per verifica
address: str # Non necessario per verifica
phone: str # Non necessario per verifica
# CORRETTO: minimizza i dati al minimo necessario
class CitizenEligibilityDTO(BaseModel):
# Solo un token opaco, non il codice fiscale reale
pseudonymous_id: str
is_eligible: bool
benefit_category: str
# Nessun dato personale identificativo
# Service layer con minimizzazione
class HealthBenefitService:
def __init__(self, citizen_repo, pseudonym_service):
self.citizen_repo = citizen_repo
self.pseudonym_service = pseudonym_service
def check_eligibility(self, pseudonymous_id: str, benefit_code: str) -> CitizenEligibilityDTO:
# Risolve il pseudonimo solo internamente, non lo espone
real_id = self.pseudonym_service.resolve(pseudonymous_id)
# Query mirata: solo il dato necessario
is_eligible = self.citizen_repo.check_benefit_eligibility(
citizen_id=real_id,
benefit_code=benefit_code
)
return CitizenEligibilityDTO(
pseudonymous_id=pseudonymous_id,
is_eligible=is_eligible,
benefit_category=benefit_code
)
# NON ritorna: nome, CF, indirizzo, telefono, email
# Repository con projection query (minimizzazione lato DB)
class CitizenRepository:
def check_benefit_eligibility(self, citizen_id: str, benefit_code: str) -> bool:
# SELECT solo la colonna necessaria, non SELECT *
query = """
SELECT EXISTS(
SELECT 1 FROM citizen_benefits
WHERE citizen_id = {citizen_id}
AND benefit_code = {benefit_code}
AND valid_until >= CURRENT_DATE
)
"""
return self.db.execute(query, {"citizen_id": citizen_id, "benefit_code": benefit_code}).scalar()
Wzór 2: Pseudonimizacja i tokenizacja
Pseudonimizacja (zdefiniowana w art. 4 ust. 5 RODO) jest jednym ze środków technicznych, o których wyraźnie mowa w art. 25 polubień adekwatne do wykazania zgodności z zasadą Privacy by Design. Różni się od anonimizacji: Dane pseudonimizowane mogą można prześledzić aż do zainteresowanej strony za pomocą dodatkowych informacji przechowywanych oddzielnie, w przeciwieństwie do danych anonimowych mogą (a zatem nie podlegają RODO).
W przypadku systemów PA pseudonimizacja jest często lepsza niż anonimizacja, ponieważ pozwala zachować wewnętrzna identyfikowalność (niezbędna do audytu i zapewnienia zgodności) przy jednoczesnej ochronie tożsamości osób, których dane dotyczą, w systemach z przodu i w logach.
# Pattern Pseudonimizzazione con Vault separato
# Architettura: Pseudonym Vault isolato dal sistema principale
import secrets
import hmac
import hashlib
from datetime import datetime, timedelta
from dataclasses import dataclass
@dataclass
class PseudonymRecord:
pseudonym: str
real_id: str
created_at: datetime
expires_at: datetime
purpose: str # Finalità del trattamento (Art. 5(1)(b))
class PseudonymVault:
"""
Vault isolato che gestisce la mappatura pseudonimo <-> identità reale.
Accesso ristretto: solo servizi autorizzati con chiave vault.
Log di ogni accesso per audit GDPR.
"""
def __init__(self, vault_key: bytes, db_connection):
self._vault_key = vault_key
self._db = db_connection
def create_pseudonym(
self,
real_id: str,
purpose: str,
validity_days: int = 365
) -> str:
"""
Genera pseudonimo crittograficamente sicuro.
Usa HMAC-SHA256 con chiave vault per essere deterministico
(stesso real_id + purpose = stesso pseudonimo) ma non invertibile
senza la chiave vault.
"""
# HMAC deterministico: stesso input = stesso output
# Ma non reversibile senza vault_key
pseudonym_bytes = hmac.new(
key=self._vault_key,
msg=f"{real_id}:{purpose}".encode(),
digestmod=hashlib.sha256
).digest()
# Converti in stringa URL-safe
pseudonym = pseudonym_bytes.hex()[:32] # 128-bit, abbondante
# Registra nel vault (separato dal DB principale)
record = PseudonymRecord(
pseudonym=pseudonym,
real_id=real_id,
created_at=datetime.utcnow(),
expires_at=datetime.utcnow() + timedelta(days=validity_days),
purpose=purpose
)
self._db.insert_pseudonym(record)
return pseudonym
def resolve_pseudonym(self, pseudonym: str, requesting_service: str) -> str:
"""
Risolve pseudonimo -> identità reale.
Richiede autorizzazione esplicita del servizio richiedente.
Logga ogni accesso per audit.
"""
# Audit log obbligatorio
self._log_resolution_access(
pseudonym=pseudonym,
requesting_service=requesting_service,
timestamp=datetime.utcnow()
)
record = self._db.get_pseudonym(pseudonym)
if not record:
raise ValueError("Pseudonym not found")
if datetime.utcnow() > record.expires_at:
raise ValueError("Pseudonym expired")
return record.real_id
def _log_resolution_access(self, pseudonym: str, requesting_service: str, timestamp: datetime):
"""
Log GDPR-compliant: registra chi ha risolto quale pseudonimo e quando.
Il log stesso usa solo lo pseudonimo (non l'identità reale).
"""
self._db.insert_audit_log({
"action": "PSEUDONYM_RESOLVED",
"pseudonym_hash": hashlib.sha256(pseudonym.encode()).hexdigest(),
"requesting_service": requesting_service,
"timestamp": timestamp.isoformat(),
"legal_basis": "GDPR Art. 6(1)(e) - Task public interest"
})
Wzór 3: Zarządzanie zgodami zgodnymi z RODO
Zgoda (art. 7 RODO) musi być bezpłatne, konkretne, świadome i jednoznaczne. W przypadku AP w większości W niektórych przypadkach przetwarzanie nie opiera się na zgodzie, lecz na innych podstawach prawnych (art. 6 ust. 1 lit. e): zadanie interesu publicznego, o Sztuka. 6 ust. 1 lit. c): obowiązek prawny). Jednakże, gdy zgoda jest wybraną podstawą prawną – na przykład w przypadku komunikacji marketing, newslettery czy opcjonalne przetwarzanie – system zarządzania zgodami musi spełniać precyzyjne wymagania.
Un Platforma zarządzania zgodami (CMP) dla AP musi zapamiętać: co zostało przyjęte, kiedy i z czym wersję informacji, z jakiego kanału i musi umożliwiać odwołanie tak proste, jak było to postanowienie.
-- Schema SQL: Consent Management GDPR-compliant
-- Database separato o schema isolato con accesso controllato
CREATE TABLE consent_purposes (
purpose_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(64) UNIQUE NOT NULL,
name_it TEXT NOT NULL,
name_en TEXT,
description_it TEXT NOT NULL,
legal_basis VARCHAR(32) NOT NULL, -- 'consent', 'legal_obligation', 'public_task'
data_categories TEXT[] NOT NULL, -- Categorie di dati trattati
retention_days INTEGER NOT NULL,
third_parties TEXT[], -- Destinatari (trasparenza)
created_at TIMESTAMPTZ DEFAULT NOW(),
version INTEGER NOT NULL DEFAULT 1,
is_active BOOLEAN DEFAULT TRUE
);
CREATE TABLE citizen_consents (
consent_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Pseudonimo, non ID reale
citizen_pseudonym VARCHAR(64) NOT NULL,
purpose_id UUID REFERENCES consent_purposes(purpose_id),
status VARCHAR(16) NOT NULL CHECK (status IN ('granted', 'denied', 'withdrawn')),
granted_at TIMESTAMPTZ,
withdrawn_at TIMESTAMPTZ,
-- Prova del consenso (Art. 7(1): titolare deve dimostrare il consenso)
proof_channel VARCHAR(32) NOT NULL, -- 'web_portal', 'mobile_app', 'paper'
proof_ip_hash VARCHAR(64), -- Hash dell'IP, non IP raw
proof_session_id VARCHAR(128),
privacy_policy_version VARCHAR(16) NOT NULL,
-- Lingua in cui è stata mostrata l'informativa
consent_language VARCHAR(8) NOT NULL DEFAULT 'it',
user_agent_hash VARCHAR(64)
);
-- Indice per query rapide sulla revoca
CREATE INDEX idx_consents_pseudonym ON citizen_consents(citizen_pseudonym, status);
-- Vista per audit: mostra solo dati necessari al DPO
CREATE VIEW consent_audit_view AS
SELECT
c.consent_id,
c.citizen_pseudonym,
p.code AS purpose_code,
p.name_it AS purpose_name,
c.status,
c.granted_at,
c.withdrawn_at,
c.proof_channel,
c.privacy_policy_version
FROM citizen_consents c
JOIN consent_purposes p ON c.purpose_id = p.purpose_id;
-- Funzione per il diritto di revoca (Art. 7(3))
CREATE OR REPLACE FUNCTION withdraw_consent(
p_citizen_pseudonym VARCHAR(64),
p_purpose_code VARCHAR(64)
) RETURNS VOID AS $
BEGIN
UPDATE citizen_consents
SET
status = 'withdrawn',
withdrawn_at = NOW()
WHERE
citizen_pseudonym = p_citizen_pseudonym
AND purpose_id = (
SELECT purpose_id FROM consent_purposes WHERE code = p_purpose_code
)
AND status = 'granted';
-- Logga l'evento per audit
INSERT INTO consent_events (
event_type, citizen_pseudonym, purpose_code, occurred_at
) VALUES (
'CONSENT_WITHDRAWN', p_citizen_pseudonym, p_purpose_code, NOW()
);
END;
$ LANGUAGE plpgsql;
Wzór 4: Automatyczne przechowywanie danych i prawo do ich usunięcia
Zasada „ograniczenia przechowywania” (art. 5 ust. 1 lit. e RODO) wymaga, aby dane osobowe były przechowywane "w formie umożliwiającej identyfikację zainteresowanych na okres nie dłuższy niż osiągnięcie od celów, dla których są przetwarzane„. W praktyce każdy system PA musi wdrożyć politykę retencji automatyczny, który usuwa lub anonimizuje wygasłe dane bez ręcznej interwencji.
Prawo do usunięcia danych (art. 17 RODO), znane jako „prawo do bycia zapomnianym”, dodaje dodatkową warstwę złożoności: system musi mieć możliwość usunięcia danych konkretnej osoby na żądanie, z zastrzeżeniem wszelkich wyjątków (przykładowo dane niezbędne do wywiązania się z obowiązków prawnych).
# Data Retention Manager - Python con scheduling automatico
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from dataclasses import dataclass
from enum import Enum
from datetime import datetime, timedelta
from typing import List
class RetentionAction(Enum):
DELETE = "delete"
ANONYMIZE = "anonymize"
ARCHIVE = "archive"
@dataclass
class RetentionPolicy:
table_name: str
date_column: str
retention_days: int
action: RetentionAction
legal_basis: str # Documentazione dell'obbligo legale
# Registro delle politiche di retention (da configurazione, non hardcoded)
RETENTION_POLICIES: List[RetentionPolicy] = [
RetentionPolicy(
table_name="citizen_session_logs",
date_column="created_at",
retention_days=90, # 3 mesi per log sessione
action=RetentionAction.DELETE,
legal_basis="GDPR Art. 5(1)(e) - Storage limitation"
),
RetentionPolicy(
table_name="service_requests",
date_column="completed_at",
retention_days=2555, # 7 anni per atti amministrativi
action=RetentionAction.ANONYMIZE,
legal_basis="D.Lgs. 82/2005 Art. 40 - Conservazione atti"
),
RetentionPolicy(
table_name="consent_records",
date_column="withdrawn_at",
retention_days=365, # 1 anno dopo revoca per prova
action=RetentionAction.DELETE,
legal_basis="GDPR Art. 7(1) - Prova consenso"
),
]
class DataRetentionManager:
def __init__(self, db, audit_logger):
self.db = db
self.audit_logger = audit_logger
self.scheduler = AsyncIOScheduler()
async def run_retention_policy(self, policy: RetentionPolicy) -> dict:
"""Esegue una politica di retention e ritorna statistiche."""
cutoff_date = datetime.utcnow() - timedelta(days=policy.retention_days)
stats = {"policy": policy.table_name, "action": policy.action.value, "rows_affected": 0}
if policy.action == RetentionAction.DELETE:
result = await self.db.execute(
f"DELETE FROM {policy.table_name} WHERE {policy.date_column} < $1",
cutoff_date
)
stats["rows_affected"] = result.rowcount
elif policy.action == RetentionAction.ANONYMIZE:
# Anonymize: sostituisce dati identificativi con hash o NULL
result = await self.db.execute(
f"""UPDATE {policy.table_name}
SET
fiscal_code = 'ANONYMIZED_' || gen_random_uuid()::text,
first_name = NULL,
last_name = NULL,
email = NULL,
phone = NULL
WHERE {policy.date_column} < $1
AND fiscal_code NOT LIKE 'ANONYMIZED_%'""",
cutoff_date
)
stats["rows_affected"] = result.rowcount
# Audit log obbligatorio per ogni operazione di retention
await self.audit_logger.log({
"event": "RETENTION_EXECUTED",
"policy": policy.table_name,
"action": policy.action.value,
"cutoff_date": cutoff_date.isoformat(),
"rows_affected": stats["rows_affected"],
"legal_basis": policy.legal_basis,
"executed_at": datetime.utcnow().isoformat()
})
return stats
async def handle_erasure_request(self, citizen_pseudonym: str, request_id: str) -> dict:
"""
Gestisce il diritto alla cancellazione (Art. 17 GDPR).
Verifica le eccezioni prima di procedere.
"""
# Verifica eccezioni Art. 17(3) - obblighi legali, interesse pubblico, etc.
exceptions = await self._check_erasure_exceptions(citizen_pseudonym)
if exceptions:
# Non cancella, documenta il motivo del diniego
await self.audit_logger.log({
"event": "ERASURE_REQUEST_DENIED",
"citizen_pseudonym": citizen_pseudonym,
"request_id": request_id,
"reasons": exceptions
})
return {"status": "denied", "reasons": exceptions}
# Procede con la cancellazione
tables_affected = []
for table in ["citizen_session_logs", "consent_records", "service_requests_temp"]:
rows = await self.db.execute(
f"DELETE FROM {table} WHERE citizen_pseudonym = $1",
citizen_pseudonym
)
if rows.rowcount > 0:
tables_affected.append(table)
await self.audit_logger.log({
"event": "ERASURE_REQUEST_EXECUTED",
"citizen_pseudonym": citizen_pseudonym,
"request_id": request_id,
"tables_affected": tables_affected,
"executed_at": datetime.utcnow().isoformat()
})
return {"status": "completed", "tables_affected": tables_affected}
DPIA: kiedy jest obowiązkowa i jak ją zorganizować
La Ocena skutków dla ochrony danych (DPIA, ocena skutków dla ochrony danych) jest obowiązkowa zgodnie z art. 35 RODO, gdy przetwarzanie”może stanowić wysokie ryzyko dla praw i wolności osób osoby fizyczne„. W przypadku włoskiej Agencji Ochrony Prywatności Gwarant Prywatności opublikował listę wymaganych zabiegów DPIA jest obowiązkowa.
Zabiegi PA wymagające obowiązkowej DPIA
- Systematyczne profilowanie obywateli (np. punktacja społeczno-ekonomiczna)
- Leczenie na dużą skalę poszczególnych kategorii danych (zdrowotnych, sądowych)
- Systematyczny nadzór przestrzeni publicznych (monitoring wideo)
- Systemy dopasowywania/łączenia zbiorów danych pochodzących z różnych źródeł
- Dane osób bezbronnych (małoletni, pacjenci, osoby ubiegające się o azyl)
- Innowacyjne wykorzystanie technologii (AI/ML w przypadku decyzji zautomatyzowanych, art. 22)
- Transfer międzynarodowy danych osobowych
Ustrukturyzowana DPIA obejmuje: opis przetwarzania i jego celów, ocenę konieczności i proporcjonalności, identyfikacja i ocena zagrożeń dla praw osób, których dane dotyczą, oraz środki przewidziane w celu zaradzenia tym zagrożeniom (w tym zabezpieczenia i mechanizmy bezpieczeństwa). Zaangażowanie IOD (Inspektora Ochrony Danych) jest obowiązkowe (art. 35 ust. 2) oraz DPIA muszą zostać zaktualizowane w przypadku zmiany sposobu leczenia.
Wzór 5: Rejestrowanie audytu zgodne z RODO
Niedocenianym wymogiem RODO jest odpowiedzialność (odpowiedzialność, art. 5 ust. 2): właściciel leczenia musi być w stanie wykazać przestrzeganie zaleceń. Wymaga to systemu rejestrowania audytu, który śledzi operacje na danych osobowych, ale które – paradoksalnie – same w sobie nie stają się źródłem nadmiernego przetwarzania danych osobowych.
Dziennik audytu zgodny z RODO musi:
- Nagrywać Kto uzyskiwał dostęp do jakich danych i kiedy, w miarę możliwości używając pseudonimów lub identyfikatorów systemowych
- Być niezmienny (tylko do dołączenia), aby zapewnić integralność dowodów
- Posiadaj własną politykę przechowywania (logi nie są przechowywane na zawsze)
- Bądź chroniony przed nieautoryzowanym dostępem (oddzielny od głównego DB)
- Obsługuj wydajne zapytania w celu odpowiedzi na wnioski DPO lub Organu Gwaranta
# Audit Logger immutabile con PostgreSQL - append-only tramite trigger
# Usa una tabella separata con accesso write-only dall'applicazione
-- Schema audit log (database o schema separato)
CREATE TABLE gdpr_audit_log (
log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Identificatori: pseudonimizzati dove possibile
subject_pseudonym VARCHAR(64), -- Chi ha eseguito l'azione
affected_entity_pseudonym VARCHAR(64), -- Su quale entità
-- Cosa è successo
action_type VARCHAR(64) NOT NULL, -- READ, UPDATE, DELETE, EXPORT, etc.
resource_type VARCHAR(64) NOT NULL, -- citizen_record, consent, health_data, etc.
-- Contesto
legal_basis VARCHAR(128), -- Base giuridica del trattamento
purpose VARCHAR(256), -- Finalità del trattamento
-- Metadati tecnici (senza dati personali)
service_name VARCHAR(128) NOT NULL,
request_id VARCHAR(128),
-- Timestamp immutabile
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
-- NON includere: IP raw, user agent completo, payload della request
);
-- Nega UPDATE e DELETE sulla tabella audit (append-only)
CREATE RULE no_update_audit AS ON UPDATE TO gdpr_audit_log DO INSTEAD NOTHING;
CREATE RULE no_delete_audit AS ON DELETE TO gdpr_audit_log DO INSTEAD NOTHING;
-- Funzione trigger per log automatico su tabelle sensibili
CREATE OR REPLACE FUNCTION audit_sensitive_access() RETURNS TRIGGER AS $
BEGIN
INSERT INTO gdpr_audit_log (
action_type,
resource_type,
subject_pseudonym,
affected_entity_pseudonym,
service_name,
legal_basis
) VALUES (
TG_OP, -- INSERT/UPDATE/DELETE
TG_TABLE_NAME,
current_setting('app.current_user_pseudonym', true),
NEW.citizen_pseudonym,
current_setting('app.service_name', true),
current_setting('app.legal_basis', true)
);
RETURN NEW;
END;
$ LANGUAGE plpgsql SECURITY DEFINER;
-- Applica il trigger alle tabelle sensibili
CREATE TRIGGER audit_health_records
AFTER INSERT OR UPDATE OR DELETE ON health_records
FOR EACH ROW EXECUTE FUNCTION audit_sensitive_access();
Ogólna architektura: RODO według projektu w usłudze PA
Łącząc wszystkie opisane wzorce, architektura usługi PA zgodnej z RODO-by-Design obejmuje:
- Brama API: Punkt wejścia weryfikujący uwierzytelnienie (SPID/CIE), stosujący pseudonimizację i propaguje podstawę prawną w kontekście żądania (poprzez nagłówek lub oprogramowanie pośredniczące)
- Pseudonim Skarbiec: wydzielona usługa mapowania pseudonimów i tożsamości, z ograniczonym dostępem i dziennik audytu każdej uchwały
- Mikrousługi z minimalizacją danych: każda usługa otrzymuje tylko niezbędne dane, ujawnia minimalne DTO, użyj zapytań projekcyjnych do bazy danych
- Usługa zarządzania zgodami: zarządza zgodami, weryfikuje podstawy prawne, wspiera cofnięcie i eksport danych (przenośność art. 20)
- Harmonogram przechowywania: zadania okresowe, które stosują zasady przechowywania i zarządzają żądaniami anulowania i sporządzania raportów dla IOD
- Usługa dziennika audytu: tylko do dołączania, oddzielne, z dostępem tylko do zapisu z aplikacji i tylko do odczytu przez IOD/Gwaranta
Przydatne narzędzia i ramy dla RODO-by-Design w PA
- OpenDP: Biblioteka Pythona zapewniająca zróżnicowaną prywatność, przydatna w przypadku anonimowych analiz
- Narzędzie do anonimizacji danych ARX: narzędzie open source do anonimizacji zbiorów danych
- Płaszcz na klucze: Dostawca tożsamości typu open source z wbudowaną obsługą zarządzania zgodami
- Szkic danych: do hashowania i MinHash, przydatne w skalowalnej pseudonimizacji
- PgAudyt: Rozszerzenie PostgreSQL do rejestrowania audytu na poziomie bazy danych
- Projektanci Włochy: oficjalne wytyczne AgID dotyczące prywatności już w fazie projektowania dla PA
- Przewodnik CNIL dotyczący prywatności według projektu: praktyczna metodologia władz francuskich, stosowana we Włoszech
Rola DPO i współpraca z zespołem deweloperskim
Zgodnie z art. 37 RODO wyznaczenie Inspektora Ochrony Danych (IOD) jest obowiązkowe dla wszystkich organów publicznych oraz organy publiczne (z wyjątkiem sądów pełniących funkcje jurysdykcyjne). IOD nie tylko osoba zajmująca się zgodnością: w przypadku zespołów programistycznych reprezentuje wewnętrznego konsultanta ds. ochrony danych, który muszą być zaangażowani od początkowych etapów projektu.
W praktyce zespół programistów powinien:
- Zaangażuj DPO w przegląd architektury podczas przetwarzania danych osobowych
- Dokumentuj wybory projektowe dotyczące prywatności w rekordach decyzji architektonicznych (ADR)
- Uwzględnij kontrole zgodności z RODO w definicjach historii użytkownika
- Przeprowadź ocenę ryzyka dla prywatności dla każdej nowej funkcji wprowadzającej przetwarzanie danych osobowych
- W miarę możliwości aktualizuj rejestr przetwarzania (art. 30) w sposób zautomatyzowany
Wnioski i dalsze kroki
RODO-by-Design nie jest biurokratyczną listą kontrolną, którą należy odhaczyć na koniec prac rozwojowych: jest to podejście architektoniczne które, jeśli zostaną zintegrowane na wczesnych etapach projektu, pozwolą stworzyć bezpieczniejsze, bardziej przejrzyste i solidniejsze systemy. Wzorce opisane w tym artykule — minimalizacja danych, pseudonimizacja, zarządzanie zgodami, retencja automatyczne, rejestrowanie audytowe – dotyczą każdej usługi cyfrowej włoskiej Agencji Ochrony Środowiska, począwszy od prostej strona zbierania zgód na biuletyn instytucjonalny aż po złożone systemy, takie jak karta zdrowia platformy płatności elektronicznych lub cyfrowych.
W kolejnym artykule z tej serii przeanalizujemy, jak zaimplementować dostępne interfejsy użytkownika dla drugiego PA standard WCAG 2.1 AA: kolejny wymóg regulacyjny, który podobnie jak RODO nagradza tych, którzy integrują go już na etapie projektowania.
Powiązane artykuły z tej serii
- GovTech #01: eIDAS 2.0 i portfel EUDI – europejska tożsamość cyfrowa i weryfikowalne dane uwierzytelniające
- GovTech #02: OpenID Connect dla tożsamości rządowej - najlepsze praktyki SPID, CIE i bezpieczeństwa
- GovTech #05: Dostępny interfejs użytkownika dla implementacji PA - WCAG 2.1 AA
- GovTech #06: Integracja API rządowych - SPID, CIE i pagoPA







