Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/ infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk (fra første ## seksjon), advisor urørt (0 endringer). To applier-fixes oppdaget under kjøring (TDD, RED→GREEN): - insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer 500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor scan-vinduet, applierens post-write-assertion fanget + restaurerte). - normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i 500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent utvidelse av carve-out; kun stray metadata-linjer, aldri prosa. test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet (fila bærer nå Source). Suite 728/728 grønn.
580 lines
21 KiB
Markdown
580 lines
21 KiB
Markdown
# Data Anonymization and Privacy Compliance
|
|
|
|
**Last updated:** 2026-06-24
|
|
**Status:** GA
|
|
**Category:** Data Engineering for AI
|
|
**Type:** reference
|
|
**Source:** https://learn.microsoft.com/azure/machine-learning/concept-responsible-ai
|
|
|
|
---
|
|
|
|
## Innhold
|
|
|
|
- [Introduksjon](#introduksjon)
|
|
- [Differential Privacy Techniques](#differential-privacy-techniques)
|
|
- [K-Anonymity and L-Diversity](#k-anonymity-and-l-diversity)
|
|
- [PII Detection and Masking](#pii-detection-and-masking)
|
|
- [Right-to-Be-Forgotten Implementation](#right-to-be-forgotten-implementation)
|
|
- [Privacy Impact Assessments](#privacy-impact-assessments)
|
|
- [Referanser](#referanser)
|
|
- [For Cosmo](#for-cosmo)
|
|
|
|
## Introduksjon
|
|
|
|
Personvern og databeskyttelse er fundamentale krav for enhver AI-losning som behandler personopplysninger. GDPR (og den norske Personopplysningsloven) stiller strenge krav til hvordan persondata samles inn, behandles og beskyttes. For AI-systemer er dette spesielt utfordrende: ML-modeller kan utilsiktet memorere persondata fra treningsdatasettet, og RAG-systemer kan eksponere sensitiv informasjon i svar.
|
|
|
|
Microsoft tilbyr flere verktoy for personvernbeskyttelse: Azure Language PII-deteksjon for a identifisere og maskere personopplysninger, Microsoft Purview for dataklassifisering og governance, og SmartNoise for differensiell personvern. Disse verktoyene kan integreres i datapipelines i Fabric for a sikre at AI-modeller trenes pa korrekt anonymiserte data.
|
|
|
|
For norsk offentlig sektor, som er underlagt bade GDPR, Personopplysningsloven og sektorspesifikke krav (f.eks. Helseregisterloven, Politiregisterloven), er systematisk anonymisering og personvernbeskyttelse ikke bare god praksis -- det er lovpalagt.
|
|
|
|
---
|
|
|
|
## Differential Privacy Techniques
|
|
|
|
### Hva er differensiell personvern?
|
|
|
|
Differensiell personvern (DP) garanterer matematisk at ingen enkeltperson kan identifiseres fra resultatet av en dataanalyse. Prinsippet: tilforing av kontrollert stoy gjor det umulig a avgjore om en spesifikk person er i datasettet.
|
|
|
|
```
|
|
Formell definisjon:
|
|
For alle datasett D1 og D2 som skiller seg med maks 1 rad,
|
|
og alle mulige resultater S:
|
|
|
|
Pr[M(D1) i S] <= e^epsilon * Pr[M(D2) i S]
|
|
|
|
epsilon (privacy budget): Lavere = sterkere personvern, mer stoy
|
|
```
|
|
|
|
### Privacy Budget (epsilon)
|
|
|
|
| Epsilon | Personvernniva | Bruksomrade |
|
|
|---------|---------------|-------------|
|
|
| 0.1 | Svart sterkt | Helsedata, sensitiv forskning |
|
|
| 1.0 | Sterkt | Generell offentlig statistikk |
|
|
| 3.0 | Moderat | Intern analyse, dashboards |
|
|
| 10.0 | Svakt | Testing, lav-risiko data |
|
|
|
|
### SmartNoise-implementering
|
|
|
|
```python
|
|
# SmartNoise - Microsoft/OpenDP-prosjektet for differensiell personvern
|
|
# pip install opendp smartnoise-sql
|
|
|
|
from opendp.measurements import make_laplace
|
|
from opendp.domains import atom_domain
|
|
from opendp.metrics import absolute_distance
|
|
|
|
def dp_count(true_count: int, epsilon: float = 1.0) -> float:
|
|
"""
|
|
Legg til Laplace-stoy for differensielt privat telling.
|
|
"""
|
|
sensitivity = 1 # En person kan endre tellingen med maks 1
|
|
scale = sensitivity / epsilon
|
|
|
|
import numpy as np
|
|
noise = np.random.laplace(0, scale)
|
|
return max(0, true_count + noise) # Aldri negativ telling
|
|
|
|
def dp_mean(values, epsilon: float = 1.0, lower_bound: float = 0, upper_bound: float = 100):
|
|
"""
|
|
Beregn differensielt privat gjennomsnitt.
|
|
"""
|
|
import numpy as np
|
|
n = len(values)
|
|
true_mean = np.mean(values)
|
|
|
|
sensitivity = (upper_bound - lower_bound) / n
|
|
scale = sensitivity / epsilon
|
|
|
|
noise = np.random.laplace(0, scale)
|
|
return true_mean + noise
|
|
|
|
# Eksempel: Privat gjennomsnitt av inntektsdata
|
|
incomes = [450000, 520000, 380000, 620000, 490000]
|
|
private_mean = dp_mean(incomes, epsilon=1.0, lower_bound=0, upper_bound=2000000)
|
|
print(f"Differensielt privat gjennomsnitt: {private_mean:,.0f} NOK")
|
|
```
|
|
|
|
### Differensiell personvern i ML-trening
|
|
|
|
```python
|
|
# DP-SGD (Differentially Private Stochastic Gradient Descent)
|
|
# For trening av modeller med personverngarantier
|
|
|
|
# Med opacus (PyTorch)
|
|
# pip install opacus
|
|
|
|
"""
|
|
from opacus import PrivacyEngine
|
|
|
|
model = YourModel()
|
|
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
|
|
|
|
privacy_engine = PrivacyEngine()
|
|
model, optimizer, dataloader = privacy_engine.make_private_with_epsilon(
|
|
module=model,
|
|
optimizer=optimizer,
|
|
data_loader=dataloader,
|
|
epochs=10,
|
|
target_epsilon=3.0, # Privacy budget
|
|
target_delta=1e-5,
|
|
max_grad_norm=1.0
|
|
)
|
|
|
|
# Tren som vanlig - opacus handterer stoy-tilforing automatisk
|
|
for epoch in range(10):
|
|
for batch in dataloader:
|
|
optimizer.zero_grad()
|
|
loss = criterion(model(batch), labels)
|
|
loss.backward()
|
|
optimizer.step()
|
|
|
|
# Sjekk faktisk privacy-forbruk
|
|
epsilon = privacy_engine.get_epsilon(delta=1e-5)
|
|
print(f"Faktisk epsilon: {epsilon:.2f}")
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
## K-Anonymity and L-Diversity
|
|
|
|
### K-Anonymitet
|
|
|
|
K-anonymitet sikrer at hver kombinasjon av quasi-identifikatorer forekommer i minst k rader:
|
|
|
|
```python
|
|
def check_k_anonymity(df, quasi_identifiers: list, k: int = 5) -> dict:
|
|
"""
|
|
Sjekk om et datasett oppfyller k-anonymitet.
|
|
|
|
Args:
|
|
df: DataFrame
|
|
quasi_identifiers: Kolonner som kan brukes til re-identifisering
|
|
k: Minimum gruppestorrelse
|
|
"""
|
|
# Grupper etter quasi-identifikatorer
|
|
groups = df.groupBy(quasi_identifiers).count()
|
|
|
|
# Finn grupper med faerre enn k elementer
|
|
violating = groups.filter(F.col("count") < k)
|
|
total_groups = groups.count()
|
|
violating_groups = violating.count()
|
|
|
|
min_group_size = groups.agg(F.min("count")).collect()[0][0]
|
|
|
|
return {
|
|
"k_anonymous": violating_groups == 0,
|
|
"k_value": k,
|
|
"total_groups": total_groups,
|
|
"violating_groups": violating_groups,
|
|
"min_group_size": min_group_size,
|
|
"recommendation": f"Oek generalisering" if min_group_size < k else "OK"
|
|
}
|
|
|
|
# Sjekk k-anonymitet for helsedatasett
|
|
result = check_k_anonymity(
|
|
df_health_data,
|
|
quasi_identifiers=["age_group", "postal_area", "gender"],
|
|
k=5
|
|
)
|
|
```
|
|
|
|
### Generaliseringsstrategier for k-anonymitet
|
|
|
|
```python
|
|
def generalize_for_k_anonymity(df, generalizations: dict):
|
|
"""
|
|
Generaliser quasi-identifikatorer for a oppna k-anonymitet.
|
|
|
|
Args:
|
|
generalizations: {kolonne: generaliseringsfunksjon}
|
|
"""
|
|
result = df
|
|
for col_name, gen_func in generalizations.items():
|
|
result = result.withColumn(col_name, gen_func(F.col(col_name)))
|
|
return result
|
|
|
|
# Generaliseringsfunksjoner
|
|
generalizations = {
|
|
# Alder -> aldersgruppe (5-aarsintervaller)
|
|
"age": lambda c: (F.floor(c / 5) * 5).cast("int"),
|
|
|
|
# Postnummer -> postomrade (forste 2 siffer)
|
|
"postal_code": lambda c: F.substring(c, 1, 2),
|
|
|
|
# Fodselsdato -> fodeselsar
|
|
"birth_date": lambda c: F.year(c),
|
|
|
|
# Kommune -> fylke
|
|
"municipality": lambda c: F.substring(c, 1, 2) # Forste 2 siffer = fylke
|
|
}
|
|
|
|
df_generalized = generalize_for_k_anonymity(df_sensitive, generalizations)
|
|
|
|
# Verifiser
|
|
result = check_k_anonymity(df_generalized, ["age", "postal_code", "gender"], k=5)
|
|
print(f"K-anonym: {result['k_anonymous']}, Min gruppestorrelse: {result['min_group_size']}")
|
|
```
|
|
|
|
### L-Diversitet
|
|
|
|
L-diversitet utvider k-anonymitet ved a kreve at sensitive attributter har minst l forskjellige verdier i hver gruppe:
|
|
|
|
```python
|
|
def check_l_diversity(df, quasi_identifiers: list, sensitive_column: str, l: int = 3):
|
|
"""
|
|
Sjekk om et datasett oppfyller l-diversitet.
|
|
"""
|
|
# Tell unike verdier av sensitiv attributt per gruppe
|
|
diversity = df.groupBy(quasi_identifiers).agg(
|
|
F.countDistinct(sensitive_column).alias("distinct_sensitive"),
|
|
F.count("*").alias("group_size")
|
|
)
|
|
|
|
violating = diversity.filter(F.col("distinct_sensitive") < l)
|
|
min_diversity = diversity.agg(F.min("distinct_sensitive")).collect()[0][0]
|
|
|
|
return {
|
|
"l_diverse": violating.count() == 0,
|
|
"l_value": l,
|
|
"min_diversity": min_diversity,
|
|
"violating_groups": violating.count()
|
|
}
|
|
|
|
# Sjekk l-diversitet for diagnosekoder
|
|
result = check_l_diversity(
|
|
df_health_data,
|
|
quasi_identifiers=["age_group", "postal_area"],
|
|
sensitive_column="diagnosis_code",
|
|
l=3
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## PII Detection and Masking
|
|
|
|
### Azure Language PII Detection
|
|
|
|
Azure Language tilbyr avansert PII-deteksjon med stotte for 50+ kategorier:
|
|
|
|
```python
|
|
from azure.ai.textanalytics import TextAnalyticsClient
|
|
from azure.core.credentials import AzureKeyCredential
|
|
|
|
def detect_and_redact_pii(text: str, endpoint: str, key: str,
|
|
categories_to_redact: list = None) -> dict:
|
|
"""
|
|
Detekter og masker PII i tekst med Azure Language.
|
|
|
|
Args:
|
|
text: Tekst a analysere
|
|
categories_to_redact: Spesifikke PII-kategorier a maskere
|
|
"""
|
|
client = TextAnalyticsClient(
|
|
endpoint=endpoint,
|
|
credential=AzureKeyCredential(key)
|
|
)
|
|
|
|
response = client.recognize_pii_entities(
|
|
documents=[text],
|
|
categories_filter=categories_to_redact,
|
|
language="no" # Norsk
|
|
)
|
|
|
|
result = response[0]
|
|
|
|
return {
|
|
"original_text": text,
|
|
"redacted_text": result.redacted_text,
|
|
"entities": [
|
|
{
|
|
"text": entity.text,
|
|
"category": entity.category,
|
|
"subcategory": entity.subcategory,
|
|
"confidence": entity.confidence_score,
|
|
"offset": entity.offset,
|
|
"length": entity.length
|
|
}
|
|
for entity in result.entities
|
|
]
|
|
}
|
|
|
|
# Eksempel
|
|
result = detect_and_redact_pii(
|
|
text="Ola Nordmann bor i Storgata 15, 0184 Oslo. Hans personnummer er 01019012345.",
|
|
endpoint="https://myservice.cognitiveservices.azure.com/",
|
|
key="your-api-key",
|
|
categories_to_redact=["Person", "Address", "NorwayIdentityNumber"]
|
|
)
|
|
# Output: "***** bor i *****, ***** Oslo. Hans personnummer er *****."
|
|
```
|
|
|
|
### PII-deteksjon i Fabric-pipelines
|
|
|
|
```python
|
|
# Batch PII-deteksjon i PySpark
|
|
from pyspark.sql import functions as F
|
|
from pyspark.sql.types import ArrayType, StructType, StructField, StringType, DoubleType
|
|
|
|
def batch_pii_detection(df, text_column: str, endpoint: str, key: str):
|
|
"""
|
|
Kjor PII-deteksjon pa en hel DataFrame-kolonne.
|
|
"""
|
|
@F.udf(returnType=StringType())
|
|
def redact_pii_udf(text):
|
|
if not text:
|
|
return text
|
|
|
|
from azure.ai.textanalytics import TextAnalyticsClient
|
|
from azure.core.credentials import AzureKeyCredential
|
|
|
|
client = TextAnalyticsClient(
|
|
endpoint=endpoint,
|
|
credential=AzureKeyCredential(key)
|
|
)
|
|
|
|
try:
|
|
response = client.recognize_pii_entities(
|
|
documents=[text], language="no"
|
|
)
|
|
return response[0].redacted_text
|
|
except Exception:
|
|
return text # Returner original ved feil
|
|
|
|
return df.withColumn(f"{text_column}_redacted", redact_pii_udf(F.col(text_column)))
|
|
|
|
# Bruk pa treningsdata for RAG
|
|
df_documents = spark.table("lakehouse.default.raw_documents")
|
|
df_redacted = batch_pii_detection(
|
|
df_documents,
|
|
text_column="content",
|
|
endpoint=endpoint,
|
|
key=api_key
|
|
)
|
|
|
|
# Lagre redaktert versjon for AI-trening
|
|
df_redacted.select("doc_id", "content_redacted", "metadata") \
|
|
.write.format("delta").mode("overwrite") \
|
|
.saveAsTable("lakehouse.default.training_documents_anonymized")
|
|
```
|
|
|
|
### PII-kategorier relevant for norsk offentlig sektor
|
|
|
|
| Kategori | Azure-kode | Eksempler |
|
|
|----------|-----------|----------|
|
|
| Personnummer | NorwayIdentityNumber | 01019012345 |
|
|
| Personnavn | Person | Ola Nordmann |
|
|
| Adresse | Address | Storgata 15, 0184 Oslo |
|
|
| Telefonnummer | PhoneNumber | +47 90000000 |
|
|
| E-post | Email | ola@firma.no |
|
|
| Bankkonto | InternationalBankingAccountNumber | NO9386011117947 |
|
|
| Organisasjonsnummer | Organization | 123 456 789 |
|
|
| Helseinfo (PHI) | HealthcareEntities | Diagnose, medisin |
|
|
|
|
---
|
|
|
|
## Right-to-Be-Forgotten Implementation
|
|
|
|
### GDPR Artikkel 17: Retten til sletting
|
|
|
|
```python
|
|
from delta.tables import DeltaTable
|
|
|
|
class GDPRDeletionService:
|
|
"""
|
|
Implementer rett til sletting (GDPR Art. 17) i Delta Lake.
|
|
"""
|
|
|
|
def __init__(self, tables_with_personal_data: list):
|
|
self.tables = tables_with_personal_data
|
|
self.deletion_log_table = "lakehouse.default.gdpr_deletion_log"
|
|
|
|
def process_deletion_request(self, person_id: str, request_id: str):
|
|
"""
|
|
Slett alle personopplysninger for en person pa tvers av tabeller.
|
|
"""
|
|
results = {}
|
|
|
|
for table_config in self.tables:
|
|
table_name = table_config["table"]
|
|
id_column = table_config["id_column"]
|
|
strategy = table_config.get("strategy", "hard_delete")
|
|
|
|
try:
|
|
delta_table = DeltaTable.forName(spark, table_name)
|
|
|
|
if strategy == "hard_delete":
|
|
# Slett raden helt
|
|
delta_table.delete(f"{id_column} = '{person_id}'")
|
|
|
|
elif strategy == "anonymize":
|
|
# Anonymiser i stedet for a slette
|
|
anon_columns = table_config.get("anonymize_columns", [])
|
|
update_set = {col: F.lit("SLETTET") for col in anon_columns}
|
|
update_set["is_anonymized"] = F.lit(True)
|
|
update_set["anonymized_date"] = F.current_timestamp()
|
|
|
|
delta_table.update(
|
|
condition=f"{id_column} = '{person_id}'",
|
|
set=update_set
|
|
)
|
|
|
|
elif strategy == "pseudonymize":
|
|
# Erstatt med pseudonym
|
|
import hashlib
|
|
pseudonym = hashlib.sha256(
|
|
f"{person_id}_{request_id}".encode()
|
|
).hexdigest()[:12]
|
|
|
|
delta_table.update(
|
|
condition=f"{id_column} = '{person_id}'",
|
|
set={id_column: F.lit(f"PSEUDO_{pseudonym}")}
|
|
)
|
|
|
|
results[table_name] = {"status": "OK", "strategy": strategy}
|
|
|
|
except Exception as e:
|
|
results[table_name] = {"status": "ERROR", "error": str(e)}
|
|
|
|
# Logg slettingen
|
|
self._log_deletion(request_id, person_id, results)
|
|
|
|
return results
|
|
|
|
def _log_deletion(self, request_id, person_id, results):
|
|
"""Logg slettingsforesporselen for compliance-formaal."""
|
|
log_entry = spark.createDataFrame([{
|
|
"request_id": request_id,
|
|
"person_id_hash": hashlib.sha256(person_id.encode()).hexdigest(),
|
|
"timestamp": datetime.now().isoformat(),
|
|
"tables_processed": len(results),
|
|
"all_successful": all(r["status"] == "OK" for r in results.values()),
|
|
"details": json.dumps(results)
|
|
}])
|
|
log_entry.write.format("delta").mode("append") \
|
|
.saveAsTable(self.deletion_log_table)
|
|
|
|
def vacuum_after_deletion(self, retention_hours: int = 0):
|
|
"""
|
|
Kjor VACUUM for a fysisk fjerne slettede data.
|
|
ADVARSEL: Setter retensjon til 0 timer = ingen tidsreise mulig.
|
|
"""
|
|
spark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "false")
|
|
|
|
for table_config in self.tables:
|
|
spark.sql(f"VACUUM {table_config['table']} RETAIN {retention_hours} HOURS")
|
|
|
|
spark.conf.set("spark.databricks.delta.retentionDurationCheck.enabled", "true")
|
|
|
|
# Konfigurasjon
|
|
tables_config = [
|
|
{"table": "lakehouse.default.customers", "id_column": "person_id", "strategy": "hard_delete"},
|
|
{"table": "lakehouse.default.transactions", "id_column": "customer_id", "strategy": "anonymize",
|
|
"anonymize_columns": ["customer_name", "email", "phone"]},
|
|
{"table": "lakehouse.default.ml_features", "id_column": "entity_id", "strategy": "pseudonymize"},
|
|
{"table": "lakehouse.default.embeddings", "id_column": "source_person_id", "strategy": "hard_delete"}
|
|
]
|
|
|
|
gdpr_service = GDPRDeletionService(tables_config)
|
|
result = gdpr_service.process_deletion_request("12345678901", "REQ-2026-001")
|
|
```
|
|
|
|
### TTL (Time-to-Live) for automatisk sletting
|
|
|
|
```python
|
|
# Implementer TTL for partisjonerte Delta-tabeller
|
|
def enforce_ttl(table_name: str, partition_column: str, retention_days: int):
|
|
"""
|
|
Slett partisjoner eldre enn retention_days.
|
|
Nyttig for a overholde GDPR-krav om minimering av lagringstid.
|
|
"""
|
|
cutoff_date = (datetime.now() - timedelta(days=retention_days)).strftime("%Y-%m-%d")
|
|
|
|
delta_table = DeltaTable.forName(spark, table_name)
|
|
delta_table.delete(f"{partition_column} < '{cutoff_date}'")
|
|
|
|
# VACUUM for a fysisk fjerne filene
|
|
spark.sql(f"VACUUM {table_name}")
|
|
|
|
print(f"Slettet data eldre enn {cutoff_date} fra {table_name}")
|
|
|
|
# Kjor daglig: Slett persondata eldre enn 13 maaneder
|
|
enforce_ttl("lakehouse.default.customer_interactions", "interaction_date", retention_days=395)
|
|
```
|
|
|
|
---
|
|
|
|
## Privacy Impact Assessments
|
|
|
|
### DPIA-rammeverk for AI-systemer
|
|
|
|
| Fase | Aktivitet | Verktoy |
|
|
|------|----------|---------|
|
|
| **1. Kartlegging** | Identifiser persondata i AI-systemet | Microsoft Purview Data Map |
|
|
| **2. Vurdering** | Vurder noodvendighet og proporsjonalitet | DPIA-mal fra Datatilsynet |
|
|
| **3. Risikoanalyse** | Identifiser risiko for de registrerte | Risk Assessment Framework |
|
|
| **4. Tiltak** | Implementer tekniske og organisatoriske tiltak | Anonymisering, tilgangsstyring |
|
|
| **5. Dokumentasjon** | Dokumenter vurderingen | Protokoll, behandlingsregister |
|
|
| **6. Konsultasjon** | Konsulter personvernombud / Datatilsynet | Ved hoy risiko |
|
|
|
|
### Automatisert personvern-sjekk i CI/CD
|
|
|
|
```python
|
|
def privacy_check_before_deployment(model_artifacts_path: str) -> dict:
|
|
"""
|
|
Automatisert personvernsjekk for ML-modeller.
|
|
Kjores som del av CI/CD-pipeline.
|
|
"""
|
|
checks = {}
|
|
|
|
# 1. Sjekk at treningsdata er anonymisert
|
|
training_data_path = f"{model_artifacts_path}/training_data_manifest.json"
|
|
manifest = json.load(open(training_data_path))
|
|
|
|
checks["anonymized_training_data"] = manifest.get("anonymization_applied", False)
|
|
|
|
# 2. Sjekk at modellen ikke memorerer PII
|
|
# (Sample inference med kjente PII-verdier)
|
|
checks["pii_leakage_test"] = run_pii_leakage_test(model_artifacts_path)
|
|
|
|
# 3. Sjekk at DPIA er utfylt
|
|
checks["dpia_completed"] = os.path.exists(f"{model_artifacts_path}/dpia_signed.pdf")
|
|
|
|
# 4. Sjekk at personvernombud er konsultert
|
|
checks["dpo_approved"] = manifest.get("dpo_approval_date") is not None
|
|
|
|
# 5. Sjekk retensjonspolicy
|
|
checks["retention_policy_defined"] = manifest.get("data_retention_days") is not None
|
|
|
|
all_passed = all(checks.values())
|
|
|
|
return {
|
|
"passed": all_passed,
|
|
"checks": checks,
|
|
"recommendation": "DEPLOY" if all_passed else "BLOKKER - Personvernkrav ikke oppfylt"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Referanser
|
|
|
|
- [What is Azure Language PII detection?](https://learn.microsoft.com/en-us/azure/ai-services/language-service/personally-identifiable-information/overview) -- PII-deteksjon og maskering
|
|
- [PII filter in Microsoft Foundry](https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/content-filter-personal-information) -- PII-filtrering for LLM-er
|
|
- [Responsible AI - Privacy and security](https://learn.microsoft.com/en-us/azure/machine-learning/concept-responsible-ai) -- SmartNoise og Counterfit
|
|
- [Data privacy for cloud-scale analytics](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/cloud-scale-analytics/secure-data-privacy) -- Dataklassifisering og konfidensialitetsskjema
|
|
- [PII entity categories](https://learn.microsoft.com/en-us/azure/ai-services/language-service/personally-identifiable-information/concepts/entity-categories) -- Alle stottede PII-kategorier
|
|
- [Transparency note for PII](https://learn.microsoft.com/en-us/azure/foundry/responsible-ai/language-service/transparency-note-personally-identifiable-information) -- Bruksomrader og begrensninger
|
|
- [Data governance with Microsoft Purview](https://learn.microsoft.com/en-us/purview/data-governance-master-data-management) -- Purview for dataklassifisering
|
|
|
|
---
|
|
|
|
## For Cosmo
|
|
|
|
- **Bruk denne referansen** naar kunder behandler personopplysninger i AI-systemer og trenger anonymiserings- og personvernstrategier.
|
|
- **Azure Language PII-deteksjon er forstevalget** for a identifisere og maskere personopplysninger i tekst -- bade for treningsdata og RAG-dokumenter. Stotter norsk sprak.
|
|
- **GDPR-sletting i Delta Lake krever VACUUM**: Delta Lake sin tidsreise betyr at slettede data forblir tilgjengelige i transaksjonsloggen til VACUUM kjores. Planlegg VACUUM i trad med slettekrav.
|
|
- **K-anonymitet er minimum for publisering**: For datasett som deles utenfor organisasjonen, krev minimum k=5 anonymitet. For helsedata, bruk l-diversitet i tillegg.
|
|
- **For norsk offentlig sektor**: Datatilsynets DPIA-mal er obligatorisk for AI-systemer med hoy risiko. Integrer personvernsjekk i CI/CD-pipeline for a sikre at ingen modell deployes uten godkjent DPIA.
|