GDPR별 설계: 공공 서비스를 위한 아키텍처 패턴
PA 디지털 서비스 설계부터 개인 데이터 보호를 통합하는 방법: 아키텍처 패턴, GDPR 제25조를 준수하는 가명화, 데이터 최소화 및 동의 관리 기술.
PA의 개인정보 보호 설계: 규제 의무 및 아키텍처 선택
2018년 5월 25일 발효된 일반 데이터 보호 규정(GDPR)은 의무 부과에만 국한되지 않습니다. 관료적부터 공공행정까지: 제25조는 데이터 보호가 통합되어야 함을 규정합니다. 디자인 단계부터 바로 개인 데이터를 처리하는 정보 시스템 및 프로세스. 이 원칙은, 으로 알려진 개인정보 보호 설계, 규제 준수를 하나로 전환 건축적 품질 소프트웨어의.
이탈리아 PA 시스템(디지털 등록, 전자 건강 기록, SPID 또는 CIE가 포함된 서비스 액세스 포털, 행정 절차 관리 시스템 - 이해 및 구현 올바른 GDPR-by-Design은 선택 사항이 아닙니다. 개인정보 보호를 위해 보증기관이 규정하는 제재조치 민간 기업의 글로벌 연간 매출액의 4%에 도달할 수 있습니다. PA의 경우 그 의미에는 다음 사항에 대한 봉쇄가 포함됩니다. 처리, 손해배상 및 중대한 명예훼손을 초래합니다.
이 기사에서 배울 내용
- 개인정보 보호 설계의 7가지 기본 원칙과 이를 구체적인 아키텍처 결정에 매핑하는 방법
- 데이터베이스 및 정부 API의 가명화 및 익명화 패턴
- PA 마이크로서비스에서 데이터 최소화 패턴 구현
- 동의 관리: GDPR 준수 시스템의 아키텍처 및 구현
- 관계형 데이터베이스의 자동 데이터 보존 및 삭제 권한
- 규정 준수 감사 로깅: 개인정보를 침해하지 않고 치료를 추적하는 방법
- 고위험 시스템에 대한 DPIA(데이터 보호 영향 평가)
7가지 기본 원칙과 건축에 미치는 영향
전 온타리오주 정보 및 개인정보 보호 위원인 Ann Cavoukian은 개인정보 보호 설계의 7가지 원칙을 공식화했습니다. GDPR이 시행되었습니다. 각 원칙은 특정 아키텍처 선택으로 해석됩니다.
| PbD 원리 | 조항 GDPR | 아키텍처 패턴 | 구체적인 기술 |
|---|---|---|---|
| 사후 대응이 아닌 사전 대응 | 제25조 | 위협 모델링 개인정보 보호 | 설계 단계의 개인정보 위험 평가 |
| 개인정보 보호를 기본값으로 | 제25조(2) | 기본적으로 선택 | 명시적 동의, 기본적으로 최소화 |
| 디자인에 통합됨 | 제25조(1) | 개인 정보 보호 내장 아키텍처 | 가명화, 미사용 암호화 |
| 전체 기능 | 제5조 | 제로섬 회피 | 개인정보 보호와 보안은 충돌하지 않습니다. |
| 엔드투엔드 보안 | 제32조 | 심층 방어 | TLS, 암호화, 키 관리 |
| 가시성과 투명성 | 제13/14조 | 감사 추적 + 공개 | 익명 로깅, 개인정보 보호정책 |
| 사용자 개인정보 존중 | 기사 7/8/17 | 사용자 중심 컨트롤 | 동의 UI, 잊혀질 권리, 이식성 |
패턴 1: PA 마이크로서비스의 데이터 최소화
최소화 원칙(GDPR 제5조(1)(c))은 수집된 데이터가 "적절하고 관련성이 높으며 다음과 같이 제한되어야 함"을 요구합니다. 처리 목적과 관련하여 필요한 경우." 마이크로서비스 아키텍처에서 이는 패턴으로 변환됩니다. 경계에서의 데이터 최소화: 각 서비스는 수행하는 데 필요한 데이터만 수신해야 합니다. 그 특정 기능.
의료 혜택을 이용하려면 신원 확인 서비스를 고려해 보세요. 서비스에는 이름이 필요하지 않습니다. 시민이 혜택을 받을 자격이 있는지 확인하기 위한 완전한 정보: 익명의 식별자로 충분하며 자격이 있는 상태. 패턴은 다음을 통해 구현됩니다. 선택적 DTO(데이터 전송 개체). e 프로젝션 쿼리.
# 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()
패턴 2: 가명화 및 토큰화
가명화(GDPR 제4(5)조에 정의됨)는 해당 기술에서 명시적으로 언급된 기술적 조치 중 하나입니다. 좋아요 25개 개인정보 보호 설계 준수를 입증하기에 적합합니다. 익명화와 다름: 가명화된 데이터는 별도로 보관되는 추가 정보를 통해 이해관계자를 추적할 수 있으며, 익명의 데이터는 공개되지 않습니다. 될 수 있습니다(따라서 GDPR의 적용을 받지 않습니다).
PA 시스템의 경우 익명화보다 가명화가 선호되는 경우가 많습니다. 시스템 내 데이터 주체의 신원을 보호하는 동시에 내부 추적성(감사 및 규정 준수에 필요함) 프런트 엔드 및 로그에 있습니다.
# 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"
})
패턴 3: GDPR 준수 동의 관리
동의(GDPR 제7조)는 다음과 같아야 합니다. 자유롭고, 구체적이고, 정보가 풍부하고, 모호하지 않습니다.. PA의 경우 대부분의 경우 어떤 경우에는 처리가 동의가 아닌 다른 법적 근거에 근거하여 이루어지는 경우도 있습니다(6(1)(e)조: 공익을 위한 업무, 오 예술. 6(1)(c): 법적 의무). 그러나 동의가 법적 근거로 선택된 경우(예: 통신의 경우) 마케팅, 뉴스레터 또는 선택적 처리 - 동의 관리 시스템은 정확한 요구 사항을 충족해야 합니다.
Un 동의 관리 플랫폼(CMP) PA의 경우 다음을 기억해야 합니다. 무엇이 승인되었는지, 언제, 무엇을 승인했는지 어떤 채널에서 정보 버전을 제공하고, 조항만큼 쉽게 철회를 허용해야 합니다.
-- 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;
패턴 4: 자동 데이터 보존 및 삭제 권한
"저장 제한" 원칙(GDPR 제5조(1)(e))에 따라 개인 데이터를 저장해야 합니다. "성과를 초과하지 않는 기간 동안 이해관계자를 식별할 수 있는 형태로 처리 목적". 실제로 모든 PA 시스템은 보존 정책을 구현해야 합니다. 수동 개입 없이 만료된 데이터를 삭제하거나 익명화하는 자동입니다.
"잊혀질 권리"로 알려진 삭제 권리(GDPR 제17조)는 복잡성을 한층 더 가중시킵니다. 시스템은 요청 시 특정 개인의 데이터를 삭제할 수 있어야 하며 예외를 존중해야 합니다. (예: 법적 의무를 준수하는 데 필요한 데이터)
# 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: 필수 사항 및 구성 방법
La 데이터 보호 영향 평가 (DPIA, 데이터 보호 영향 평가)은 필수입니다. 예술에 따라. 35 GDPR 처리 시 "개인의 권리와 자유에 큰 위험을 초래할 수 있습니다. 자연인". 이탈리아 PA의 경우 개인 정보 보호 보증인이 필요한 처리 목록을 게시했습니다. DPIA는 필수입니다.
필수 DPIA가 필요한 PA 치료
- 체계적인 프로파일링 시민 수(예: 사회경제적 점수)
- 대규모 치료 특정 데이터 범주(건강, 사법)
- 체계적인 감시 공공장소(비디오 감시)
- 매칭/링크 시스템 다양한 소스의 데이터 세트
- 취약계층 데이터 (미성년자, 환자, 망명 신청자)
- 혁신적인 기술 사용 (자동화된 의사결정을 위한 AI/ML 제22조)
- 국제 송금 개인 데이터
구조화된 DPIA에는 처리 및 목적에 대한 설명, 필요성 및 비례성에 대한 평가, 정보주체의 권리에 대한 위험의 식별 및 평가, 그리고 위험을 해결하기 위해 구상된 조치 (보호 장치 및 보안 메커니즘 포함) DPO(데이터 보호 책임자)의 참여가 필수입니다. (35(2)조) 및 DPIA는 치료가 변경되면 업데이트되어야 합니다.
패턴 5: GDPR 준수 감사 로깅
GDPR의 과소평가된 요구 사항은 책임 (책임성, 조항 5(2)): 소유자 치료의 순응성을 입증할 수 있어야 합니다. 이를 위해서는 다음과 같은 감사 로깅 시스템이 필요합니다. 개인 데이터에 대한 작업을 추적하지만 역설적으로 그 자체가 소스가 되지는 않습니다. 과도한 개인정보 처리.
GDPR 준수 감사 로그는 다음을 충족해야 합니다.
- 기록 WHO 가능한 경우 가명이나 시스템 ID를 사용하여 언제 어떤 데이터에 액세스했는지
- 장차 ~ 가 되는 불변 (추가 전용) 증거의 무결성을 보장하기 위해
- 자체 보존 정책 보유(로그는 영원히 보관되지 않음)
- 무단 접근으로부터 보호 (메인 DB와는 별도)
- DPO 또는 보증기관의 요청에 응답하기 위한 효율적인 쿼리 지원
# 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();
전체 아키텍처: PA 서비스의 GDPR 설계
설명된 모든 패턴을 종합하면 GDPR-by-Design 준수 PA 서비스의 아키텍처에는 다음이 포함됩니다.
- API 게이트웨이: 인증(SPID/CIE)을 검증하고 가명처리를 적용하는 진입점 요청의 맥락에서 법적 근거를 전파합니다(헤더 또는 미들웨어를 통해).
- 가명 금고: 가명-신원 매핑을 위한 격리된 서비스(액세스가 제한됨) 결의별 감사 로그
- 데이터 최소화를 갖춘 마이크로서비스: 각 서비스는 필요한 데이터만 수신하고 최소한의 DTO를 노출합니다. DB에 프로젝션 쿼리 사용
- 동의관리 서비스: 동의 관리, 법적 근거 확인, 철회 지원 및 데이터 내보내기(이식성 조항 20)
- 보존 스케줄러: 보존 정책을 적용하고 요청을 관리하는 정기 작업 취소 및 DPO에 대한 보고서 생성
- 감사 로그 서비스: 추가 전용, 별도, 애플리케이션에서 쓰기 전용 액세스 및 읽기 전용 DPO/보증인
PA의 GDPR-by-Design을 위한 유용한 도구 및 프레임워크
- 오픈DP: 익명화된 분석에 유용한 차등 개인 정보 보호를 위한 Python 라이브러리
- ARX 데이터 익명화 도구: 데이터 세트 익명화를 위한 오픈 소스 도구
- 열쇠망토: 동의 관리 지원이 내장된 오픈 소스 ID 제공자
- 데이터 스케치: 해싱 및 MinHash용, 확장 가능한 가명화에 유용
- Pg감사: 데이터베이스 수준 감사 로깅을 위한 PostgreSQL 확장
- 디자이너 이탈리아: PA를 위한 설계에 의한 개인 정보 보호에 대한 공식 AgID 지침
- CNIL 개인정보 보호 설계 가이드: 이탈리아에 적용 가능한 프랑스 당국의 실제 방법론
DPO의 역할과 개발팀과의 협업
예술에 따라. 37 GDPR, 데이터 보호 책임자(DPO) 임명은 모든 공공 기관에 의무적입니다. 공공 기관(관할 기능을 수행하는 법원 제외). DPO는 그렇지 않습니다. 규정 준수 수치일 뿐입니다. 개발 팀의 경우 그는 내부 데이터 보호 컨설턴트를 대표합니다. 프로젝트의 초기 단계부터 참여해야 합니다.
실제로 개발팀은 다음을 수행해야 합니다.
- 개인 데이터를 처리할 때 아키텍처 검토에 DPO를 참여시킵니다.
- ADR(Architecture Decision Records)의 문서 개인정보 보호 설계 선택
- 완료의 사용자 스토리 정의에 GDPR 규정 준수 검사를 포함합니다.
- 개인 데이터 처리를 도입하는 각각의 새로운 기능에 대해 개인정보 위험 평가를 수행합니다.
- 가능한 경우 자동화된 방식으로 처리 기록부(제30조)를 업데이트하십시오.
결론 및 다음 단계
GDPR-by-Design은 개발이 끝날 때 확인해야 하는 관료적 체크리스트가 아니라 아키텍처적 접근 방식입니다. 프로젝트 초기 단계부터 통합하면 더욱 안전하고 투명하며 견고한 시스템을 생산할 수 있습니다. 이 문서에 설명된 패턴 — 데이터 최소화, 가명화, 동의 관리, 보존 자동 감사 로깅 — 간단한 서비스부터 이탈리아 PA의 모든 디지털 서비스에 적용됩니다. 건강 기록과 같은 복잡한 시스템까지 기관 뉴스레터에 대한 동의 수집 페이지 전자 또는 디지털 결제 플랫폼.
이 시리즈의 다음 기사에서는 두 번째 PA에 대해 액세스 가능한 사용자 인터페이스를 구현하는 방법을 분석하겠습니다. WCAG 2.1 AA 표준: GDPR과 마찬가지로 설계 단계부터 이를 통합하는 사람들에게 보상을 주는 또 다른 규제 요구 사항입니다.
이 시리즈의 관련 기사
- GovTech #01: eIDAS 2.0 및 EUDI Wallet - 유럽 디지털 신원 및 검증 가능한 자격 증명
- GovTech #02: 정부 ID용 OpenID Connect - SPID, CIE 및 보안 모범 사례
- 고브테크 #05: PA용 액세스 가능한 UI - WCAG 2.1 AA 구현
- 고브테크 #06: 정부 API 통합 - SPID, CIE 및 pagoPA







