AWS Security: AVG Compliance Checklist | Forrict Ga naar hoofdinhoud
Security Compliance

AWS Security: AVG Compliance Checklist

Fons Biemans
AWS Security: AVG Compliance Checklist
Uitgebreide gids voor het bereiken van AVG compliance op AWS met praktische implementatie voorbeelden, security controls en compliance automatisering

AWS Security: AVG Compliance Checklist

Een uitgebreide gids voor het implementeren van AVG-compliant AWS infrastructuur voor Nederlandse organisaties

Introductie

De Algemene Verordening Gegevensbescherming (AVG) heeft fundamenteel veranderd hoe organisaties omgaan met persoonsgegevens in de Europese Unie. Voor bedrijven die AWS gebruiken, vereist het bereiken en handhaven van AVG compliance een systematische aanpak die AWS security services, juiste architectuur en operationele processen combineert.

Deze gids biedt een praktische checklist voor het implementeren van AVG compliance op AWS, met code voorbeelden en automatiseringsscripts specifiek afgestemd op Nederlandse organisaties.

AVG Begrijpen op AWS

Het Gedeelde Verantwoordelijkheidsmodel

AWS Verantwoordelijkheid (Security OF de Cloud):

  • Fysieke infrastructuur beveiliging
  • Netwerk infrastructuur
  • Hypervisor en hardware
  • AWS services compliance certificeringen

Jouw Verantwoordelijkheid (Security IN de Cloud):

  • Data encryptie en bescherming
  • Toegangsbeheer
  • Netwerk security configuratie
  • Compliance met AVG vereisten
  • Implementatie van rechten van betrokkenen

Belangrijke AVG Principes voor AWS

  1. Rechtmatigheid, Behoorlijkheid en Transparantie
  2. Doelbinding
  3. Minimale Gegevensverwerking
  4. Juistheid
  5. Opslagbeperking
  6. Integriteit en Vertrouwelijkheid
  7. Verantwoordingsplicht

AVG Compliance Checklist

1. Data Ontdekking en Classificatie

Identificeer Persoonsgegevens:

  • Breng alle dataopslag met persoonsgegevens in kaart
  • Classificeer data gevoeligheidsniveaus
  • Documenteer datastromen en verwerkingsactiviteiten
import boto3
import json

# Gebruik AWS Macie voor geautomatiseerde data ontdekking
macie = boto3.client('macie2', region_name='eu-west-1')

# Creëer classificatie job voor S3 buckets
def creeer_classificatie_job():
    response = macie.create_classification_job(
        jobType='ONE_TIME',
        name='AVG-Data-Ontdekking',
        s3JobDefinition={
            'bucketDefinitions': [
                {
                    'accountId': '123456789012',
                    'buckets': ['klantdata-bucket', 'analytics-bucket']
                }
            ]
        },
        customDataIdentifierIds=[],
        managedDataIdentifierSelector='ALL',
        tags={
            'Doel': 'AVG-Compliance',
            'DataClassificatie': 'Persoonsgegevens'
        }
    )
    return response['jobId']

job_id = creeer_classificatie_job()
print(f"Classificatie job aangemaakt: {job_id}")

Tag Resources met Data Classificatie:

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';

// Creëer bucket met AVG classificatie tags
const klantdataBucket = new s3.Bucket(this, 'KlantData', {
  encryption: s3.BucketEncryption.S3_MANAGED,
  versioned: true,
  lifecycleRules: [
    {
      expiration: cdk.Duration.days(365),
      noncurrentVersionExpiration: cdk.Duration.days(30),
    },
  ],
});

cdk.Tags.of(klantdataBucket).add('DataClassificatie', 'Persoonlijk');
cdk.Tags.of(klantdataBucket).add('AVG', 'Ja');
cdk.Tags.of(klantdataBucket).add('DataLocatie', 'EU');

2. Data Residency en Lokalisatie

Forceer EU-Only Regio’s:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "WeigerNietEURegios",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "eu-west-1",
            "eu-west-2",
            "eu-west-3",
            "eu-central-1",
            "eu-north-1"
          ]
        }
      }
    }
  ]
}

Implementeer met AWS Organizations SCP:

# Creëer Service Control Policy voor data residency
aws organizations create-policy \
  --name "EU-Data-Residency-Policy" \
  --description "Beperk resources tot EU regio's alleen" \
  --type SERVICE_CONTROL_POLICY \
  --content file://eu-regio-policy.json

# Koppel aan organizational unit
aws organizations attach-policy \
  --policy-id p-xxxxxxxx \
  --target-id ou-xxxx-xxxxxxxx

Valideer Regio Compliance:

import boto3

def controleer_niet_eu_resources():
    """Controleer resources buiten EU regio's"""
    eu_regios = [
        'eu-west-1', 'eu-west-2', 'eu-west-3',
        'eu-central-1', 'eu-north-1'
    ]

    ec2 = boto3.client('ec2')
    alle_regios = [regio['RegionName'] for regio in ec2.describe_regions()['Regions']]

    overtredingen = []

    for regio in alle_regios:
        if regio not in eu_regios:
            ec2_regionaal = boto3.client('ec2', region_name=regio)
            instances = ec2_regionaal.describe_instances()

            for reservation in instances['Reservations']:
                for instance in reservation['Instances']:
                    overtredingen.append({
                        'ResourceId': instance['InstanceId'],
                        'Regio': regio,
                        'Type': 'EC2 Instance'
                    })

    return overtredingen

# Voer audit uit
overtredingen = controleer_niet_eu_resources()
if overtredingen:
    print(f"WAARSCHUWING: {len(overtredingen)} resources gevonden buiten EU regio's")
    for overtreding in overtredingen:
        print(f"  - {overtreding['Type']} {overtreding['ResourceId']} in {overtreding['Regio']}")

3. Encryptie in Rust

S3 Bucket Encryptie:

import * as s3 from 'aws-cdk-lib/aws-s3';
import * as kms from 'aws-cdk-lib/aws-kms';

// Creëer KMS key voor data encryptie
const dataEncryptieKey = new kms.Key(this, 'DataEncryptieKey', {
  enableKeyRotation: true,
  description: 'KMS key voor AVG-conforme data encryptie',
  alias: 'avg-data-encryptie',
});

// Creëer versleutelde bucket
const beveiligdeDataBucket = new s3.Bucket(this, 'BeveiligdeData', {
  encryption: s3.BucketEncryption.KMS,
  encryptionKey: dataEncryptieKey,
  bucketKeyEnabled: true,
  versioned: true,
  enforceSSL: true,
});

RDS Database Encryptie:

import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

const database = new rds.DatabaseInstance(this, 'KlantDatabase', {
  engine: rds.DatabaseInstanceEngine.postgres({
    version: rds.PostgresEngineVersion.VER_15_3,
  }),
  instanceType: ec2.InstanceType.of(
    ec2.InstanceClass.T4G,
    ec2.InstanceSize.MEDIUM
  ),
  vpc,
  storageEncrypted: true,
  storageEncryptionKey: dataEncryptieKey,
  backupRetention: cdk.Duration.days(35),
  deletionProtection: true,
  cloudwatchLogsExports: ['postgresql'],
});

Forceer Encryptie met AWS Config:

Resources:
  S3BucketEncryptionRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: s3-bucket-server-side-encryption-enabled
      Source:
        Owner: AWS
        SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
      Scope:
        ComplianceResourceTypes:
          - AWS::S3::Bucket

  RDSEncryptionRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: rds-storage-encrypted
      Source:
        Owner: AWS
        SourceIdentifier: RDS_STORAGE_ENCRYPTED
      Scope:
        ComplianceResourceTypes:
          - AWS::RDS::DBInstance

4. Encryptie tijdens Transport

Forceer HTTPS/TLS:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "WeigerOnveiligTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::klantdata-bucket/*",
        "arn:aws:s3:::klantdata-bucket"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

Application Load Balancer met TLS:

import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as acm from 'aws-cdk-lib/aws-certificatemanager';

// Creëer ACM certificaat
const certificaat = new acm.Certificate(this, 'Certificaat', {
  domainName: 'app.voorbeeld.nl',
  validation: acm.CertificateValidation.fromDns(),
});

// Creëer ALB met HTTPS listener
const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
  vpc,
  internetFacing: true,
});

const httpsListener = alb.addListener('HttpsListener', {
  port: 443,
  certificates: [certificaat],
  sslPolicy: elbv2.SslPolicy.TLS13_RES,
});

// Redirect HTTP naar HTTPS
const httpListener = alb.addListener('HttpListener', {
  port: 80,
  defaultAction: elbv2.ListenerAction.redirect({
    protocol: 'HTTPS',
    port: '443',
    permanent: true,
  }),
});

5. Toegangscontrole en Authenticatie

Implementeer Least Privilege IAM:

import * as iam from 'aws-cdk-lib/aws-iam';

// Creëer role met minimale permissies
const dataVerwerkerRole = new iam.Role(this, 'DataVerwerkerRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
  description: 'Role voor AVG-conforme dataverwerking',
});

// Voeg specifieke permissies toe
dataVerwerkerRole.addToPolicy(new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: [
    's3:GetObject',
    's3:PutObject',
  ],
  resources: ['arn:aws:s3:::klantdata-bucket/verwerkt/*'],
  conditions: {
    'StringEquals': {
      's3:x-amz-server-side-encryption': 'aws:kms',
    },
  },
}));

Schakel MFA in voor Gevoelige Operaties:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VereistMFAVoorDataVerwijdering",
      "Effect": "Deny",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteBucket",
        "rds:DeleteDBInstance"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

Implementeer SSO met SAML:

import * as iam from 'aws-cdk-lib/aws-iam';

// Creëer SAML provider voor Azure AD integratie
const samlProvider = new iam.SamlProvider(this, 'AzureADProvider', {
  metadataDocument: iam.SamlMetadataDocument.fromFile('./azure-ad-metadata.xml'),
  name: 'AzureAD',
});

// Creëer role voor gefedereerde gebruikers
const gefedereerdeRole = new iam.Role(this, 'GefedereerdeGebruikerRole', {
  assumedBy: new iam.SamlConsolePrincipal(samlProvider),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess'),
  ],
});

6. Audit Logging en Monitoring

Schakel Uitgebreide Logging in:

import * as cloudtrail from 'aws-cdk-lib/aws-cloudtrail';
import * as s3 from 'aws-cdk-lib/aws-s3';

// Creëer logging bucket
const logBucket = new s3.Bucket(this, 'AuditLogBucket', {
  encryption: s3.BucketEncryption.S3_MANAGED,
  versioned: true,
  lifecycleRules: [
    {
      transitions: [
        {
          storageClass: s3.StorageClass.GLACIER,
          transitionAfter: cdk.Duration.days(90),
        },
      ],
      expiration: cdk.Duration.days(2555), // 7 jaar voor compliance
    },
  ],
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});

// Schakel CloudTrail in
const trail = new cloudtrail.Trail(this, 'AVGAuditTrail', {
  bucket: logBucket,
  enableFileValidation: true,
  includeGlobalServiceEvents: true,
  isMultiRegionTrail: true,
  managementEvents: cloudtrail.ReadWriteType.ALL,
});

// Log data events voor gevoelige buckets
trail.addS3EventSelector([{
  bucket: klantdataBucket,
  objectPrefix: '',
}], {
  readWriteType: cloudtrail.ReadWriteType.ALL,
  includeManagementEvents: true,
});

Geautomatiseerde Compliance Monitoring:

import boto3
from datetime import datetime, timedelta

def monitor_data_toegang():
    """Monitor toegang tot persoonsgegevens"""
    cloudtrail = boto3.client('cloudtrail', region_name='eu-west-1')

    # Query CloudTrail voor data toegang events
    response = cloudtrail.lookup_events(
        LookupAttributes=[
            {
                'AttributeKey': 'ResourceType',
                'AttributeValue': 'AWS::S3::Object'
            }
        ],
        StartTime=datetime.now() - timedelta(hours=24),
        MaxResults=50
    )

    verdachte_toegang = []

    for event in response['Events']:
        event_naam = event['EventName']
        gebruikersnaam = event.get('Username', 'Onbekend')

        # Markeer ongebruikelijke toegangspatronen
        if event_naam in ['DeleteObject', 'GetObject'] and 'klantdata' in str(event):
            verdachte_toegang.append({
                'Tijd': event['EventTime'],
                'Gebruiker': gebruikersnaam,
                'Actie': event_naam,
                'Resource': event.get('Resources', [{}])[0].get('ResourceName')
            })

    return verdachte_toegang

# Voer monitoring uit
alerts = monitor_data_toegang()
if alerts:
    print(f"ALERT: {len(alerts)} verdachte data toegang events gedetecteerd")
    for alert in alerts:
        print(f"  {alert['Tijd']}: {alert['Gebruiker']} voerde {alert['Actie']} uit")

7. Implementatie van Rechten van Betrokkenen

Recht op Inzage (Artikel 15):

import boto3
import json
from datetime import datetime

def exporteer_gebruikersdata(gebruiker_email):
    """Exporteer alle data voor een specifieke gebruiker"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')
    s3 = boto3.client('s3', region_name='eu-west-1')

    # Query gebruikersdata uit DynamoDB
    tabel = dynamodb.Table('GebruikersData')
    response = tabel.query(
        KeyConditionExpression='email = :email',
        ExpressionAttributeValues={
            ':email': gebruiker_email
        }
    )

    gebruikersdata = {
        'persoonlijke_informatie': response['Items'],
        'export_datum': datetime.now().isoformat(),
        'verzoek_type': 'AVG Artikel 15 - Recht op Inzage'
    }

    # Upload naar beveiligde export bucket
    export_key = f"avg-exports/{gebruiker_email}/{datetime.now().date()}.json"
    s3.put_object(
        Bucket='avg-export-bucket',
        Key=export_key,
        Body=json.dumps(gebruikersdata, indent=2),
        ServerSideEncryption='aws:kms'
    )

    # Genereer presigned URL geldig voor 7 dagen
    url = s3.generate_presigned_url(
        'get_object',
        Params={'Bucket': 'avg-export-bucket', 'Key': export_key},
        ExpiresIn=604800
    )

    return url

Recht op Vergetelheid (Artikel 17):

import uuid

def verwijder_gebruikersdata(gebruiker_email):
    """Verwijder alle persoonsgegevens van een gebruiker"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')
    s3 = boto3.client('s3', region_name='eu-west-1')

    # Log verwijderingsverzoek voor audit
    log_verwijderingsverzoek(gebruiker_email)

    # Verwijder uit DynamoDB
    tabel = dynamodb.Table('GebruikersData')
    response = tabel.query(
        KeyConditionExpression='email = :email',
        ExpressionAttributeValues={':email': gebruiker_email}
    )

    with tabel.batch_writer() as batch:
        for item in response['Items']:
            batch.delete_item(Key={'email': gebruiker_email, 'timestamp': item['timestamp']})

    # Verwijder S3 objecten
    prefix = f"gebruikers/{gebruiker_email}/"
    objecten = s3.list_objects_v2(Bucket='klantdata-bucket', Prefix=prefix)

    if 'Contents' in objecten:
        delete_keys = [{'Key': obj['Key']} for obj in objecten['Contents']]
        s3.delete_objects(
            Bucket='klantdata-bucket',
            Delete={'Objects': delete_keys}
        )

    return {
        'status': 'voltooid',
        'gebruiker': gebruiker_email,
        'verwijderdatum': datetime.now().isoformat()
    }

def log_verwijderingsverzoek(gebruiker_email):
    """Log verwijderingsverzoek voor audit trail"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')
    audit_tabel = dynamodb.Table('AVGAuditLog')

    audit_tabel.put_item(Item={
        'verzoek_id': str(uuid.uuid4()),
        'gebruiker_email': gebruiker_email,
        'verzoek_type': 'RECHT_OP_VERGETELHEID',
        'timestamp': datetime.now().isoformat(),
        'status': 'IN_BEHANDELING'
    })

Recht op Dataportabiliteit (Artikel 20):

def exporteer_portabele_data(gebruiker_email):
    """Exporteer gebruikersdata in machine-leesbaar formaat"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')

    tabel = dynamodb.Table('GebruikersData')
    response = tabel.query(
        KeyConditionExpression='email = :email',
        ExpressionAttributeValues={':email': gebruiker_email}
    )

    # Converteer naar portabel JSON formaat
    portabele_data = {
        'betrokkene': gebruiker_email,
        'export_formaat': 'JSON',
        'export_datum': datetime.now().isoformat(),
        'data': response['Items']
    }

    return json.dumps(portabele_data, indent=2)

8. Data Retentie en Lifecycle Management

Geautomatiseerde Data Retentie:

import * as s3 from 'aws-cdk-lib/aws-s3';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

// S3 lifecycle voor geautomatiseerde verwijdering
const avgBucket = new s3.Bucket(this, 'AVGDataBucket', {
  lifecycleRules: [
    {
      id: 'VerwijderOudeKlantdata',
      enabled: true,
      prefix: 'klantdata/',
      expiration: cdk.Duration.days(365), // 1 jaar retentie
      noncurrentVersionExpiration: cdk.Duration.days(30),
    },
    {
      id: 'ArchiveerAnalytics',
      enabled: true,
      prefix: 'analytics/',
      transitions: [
        {
          storageClass: s3.StorageClass.GLACIER,
          transitionAfter: cdk.Duration.days(90),
        },
      ],
      expiration: cdk.Duration.days(730), // 2 jaar
    },
  ],
});

// DynamoDB met TTL voor automatische vervaldatum
const gebruikersData = new dynamodb.Table(this, 'GebruikersData', {
  partitionKey: { name: 'email', type: dynamodb.AttributeType.STRING },
  sortKey: { name: 'timestamp', type: dynamodb.AttributeType.NUMBER },
  timeToLiveAttribute: 'ttl',
  pointInTimeRecovery: true,
  encryption: dynamodb.TableEncryption.AWS_MANAGED,
});

Retentiebeleid Enforcement:

import boto3
from datetime import datetime, timedelta

def forceer_retentiebeleid():
    """Forceer data retentie beleid"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')
    tabel = dynamodb.Table('GebruikersData')

    # Bereken TTL (1 jaar vanaf nu)
    ttl = int((datetime.now() + timedelta(days=365)).timestamp())

    # Update items met TTL
    response = tabel.scan()

    with tabel.batch_writer() as batch:
        for item in response['Items']:
            if 'ttl' not in item:
                item['ttl'] = ttl
                batch.put_item(Item=item)

    print(f"{len(response['Items'])} items bijgewerkt met retentiebeleid")

9. Datalek Detectie en Respons

Geautomatiseerde Datalek Detectie:

import * as guardduty from 'aws-cdk-lib/aws-guardduty';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';

// Schakel GuardDuty in
const detector = new guardduty.CfnDetector(this, 'AVGThreatDetector', {
  enable: true,
  dataSources: {
    s3Logs: { enable: true },
    kubernetes: { auditLogs: { enable: true } },
  },
});

// Creëer SNS topic voor datalek alerts
const datalekAlertTopic = new sns.Topic(this, 'DatalekAlertTopic', {
  displayName: 'AVG Datalek Alerts',
});

// EventBridge rule voor hoge severity bevindingen
const datalekRule = new events.Rule(this, 'DatalekDetectieRule', {
  eventPattern: {
    source: ['aws.guardduty'],
    detailType: ['GuardDuty Finding'],
    detail: {
      severity: [7, 8, 9], // Alleen High en Critical
    },
  },
});

datalekRule.addTarget(new targets.SnsTopic(datalekAlertTopic));

Datalek Respons Lambda:

import boto3
import os
from datetime import datetime

def lambda_handler(event, context):
    """Geautomatiseerde AVG datalek respons"""

    # Parse GuardDuty bevinding
    bevinding = event['detail']
    ernst = bevinding['severity']
    bevinding_type = bevinding['type']

    # Log incident
    log_security_incident(bevinding)

    # Informeer FG (Functionaris Gegevensbescherming) bij hoge ernst
    if ernst >= 7:
        informeer_fg(bevinding)

        # Start 72-uur meldingsproces
        start_datalek_meldings_proces(bevinding)

    # Neem geautomatiseerde herstelactie
    if 'UnauthorizedAccess' in bevinding_type:
        isoleer_gecompromitteerde_resource(bevinding)

    return {
        'statusCode': 200,
        'incident_id': bevinding['id'],
        'ernst': ernst
    }

def informeer_fg(bevinding):
    """Informeer Functionaris Gegevensbescherming"""
    sns = boto3.client('sns', region_name='eu-west-1')

    bericht = f"""
    URGENT: Mogelijk AVG Datalek Gedetecteerd

    Bevinding Type: {bevinding['type']}
    Ernst: {bevinding['severity']}
    Resource: {bevinding['resource']['resourceType']}
    Tijd: {bevinding['createdAt']}

    Actie Vereist: Beoordeel of dit een datalek is dat melding vereist
    aan de Autoriteit Persoonsgegevens binnen 72 uur (AVG Artikel 33).
    """

    sns.publish(
        TopicArn=os.environ['FG_TOPIC_ARN'],
        Subject='AVG Datalek Alert - Onmiddellijke Actie Vereist',
        Message=bericht
    )

10. Privacy by Design en Default

Infrastructure as Code met Privacy Controls:

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as kms from 'aws-cdk-lib/aws-kms';

export class AVGCompliantStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Privacy by default: encryptie key
    const encryptieKey = new kms.Key(this, 'StandaardEncryptieKey', {
      enableKeyRotation: true,
      description: 'Standaard encryptie voor alle data in rust',
    });

    // Privacy by default: beveiligde bucket sjabloon
    const maakBeveiligdeBucket = (naam: string) => {
      return new s3.Bucket(this, naam, {
        encryption: s3.BucketEncryption.KMS,
        encryptionKey: encryptieKey,
        bucketKeyEnabled: true,
        versioned: true,
        enforceSSL: true,
        blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
        lifecycleRules: [
          {
            expiration: cdk.Duration.days(365),
          },
        ],
      });
    };

    // Alle buckets zijn standaard beveiligd
    const dataBucket = maakBeveiligdeBucket('KlantDataBucket');

    // Tag voor AVG compliance
    cdk.Tags.of(this).add('AVG-Compliant', 'ja');
    cdk.Tags.of(this).add('DataLocatie', 'EU');
  }
}

AVG Compliance Automatisering

Geautomatiseerd Compliance Dashboard

import boto3
from datetime import datetime

def genereer_avg_compliance_rapport():
    """Genereer geautomatiseerd AVG compliance rapport"""

    rapport = {
        'gegenereerd_op': datetime.now().isoformat(),
        'controles': []
    }

    # Controle 1: Data residency
    rapport['controles'].append({
        'beheersmaatregel': 'Data Residency',
        'status': controleer_data_residency(),
        'vereiste': 'Alle resources in EU regio\'s'
    })

    # Controle 2: Encryptie in rust
    rapport['controles'].append({
        'beheersmaatregel': 'Encryptie in Rust',
        'status': controleer_encryptie_in_rust(),
        'vereiste': 'Alle S3 buckets en RDS databases versleuteld'
    })

    # Controle 3: Encryptie tijdens transport
    rapport['controles'].append({
        'beheersmaatregel': 'Encryptie tijdens Transport',
        'status': controleer_encryptie_tijdens_transport(),
        'vereiste': 'HTTPS/TLS geforceerd'
    })

    # Controle 4: Toegang logging
    rapport['controles'].append({
        'beheersmaatregel': 'Toegang Logging',
        'status': controleer_cloudtrail_ingeschakeld(),
        'vereiste': 'CloudTrail ingeschakeld in alle regio\'s'
    })

    # Controle 5: Data retentie
    rapport['controles'].append({
        'beheersmaatregel': 'Data Retentie',
        'status': controleer_lifecycle_policies(),
        'vereiste': 'Lifecycle policies geconfigureerd'
    })

    # Bereken compliance score
    geslaagd = sum(1 for controle in rapport['controles'] if controle['status'] == 'COMPLIANT')
    totaal = len(rapport['controles'])
    rapport['compliance_score'] = f"{(geslaagd/totaal)*100:.1f}%"

    return rapport

def controleer_encryptie_in_rust():
    """Controleer of alle S3 buckets encryptie hebben ingeschakeld"""
    s3 = boto3.client('s3', region_name='eu-west-1')

    buckets = s3.list_buckets()['Buckets']
    niet_compliant = []

    for bucket in buckets:
        try:
            encryptie = s3.get_bucket_encryption(Bucket=bucket['Name'])
        except s3.exceptions.ClientError:
            niet_compliant.append(bucket['Name'])

    return 'COMPLIANT' if not niet_compliant else f'NIET_COMPLIANT: {len(niet_compliant)} buckets'

Nederlandse Specifieke AVG Overwegingen

Autoriteit Persoonsgegevens (AP) Meldingen

72-Uur Meldingsplicht:

def start_datalek_meldings_proces(bevinding):
    """Start proces voor datalek melding aan AP binnen 72 uur"""
    dynamodb = boto3.resource('dynamodb', region_name='eu-west-1')
    tabel = dynamodb.Table('DatalekMeldingen')

    melding_deadline = datetime.now() + timedelta(hours=72)

    tabel.put_item(Item={
        'melding_id': str(uuid.uuid4()),
        'bevinding_id': bevinding['id'],
        'detectie_tijd': datetime.now().isoformat(),
        'melding_deadline': melding_deadline.isoformat(),
        'status': 'BEOORDELING',
        'ernst': bevinding['severity'],
        'autoriteit': 'Autoriteit Persoonsgegevens',
        'melding_vereist': 'TE_BEPALEN'
    })

NEN 7510 voor Zorginstellingen

Voor Nederlandse zorginstellingen die met medische data werken:

// Extra beveiligingslagen voor NEN 7510 compliance
const medischeDataBucket = new s3.Bucket(this, 'MedischeData', {
  encryption: s3.BucketEncryption.KMS,
  encryptionKey: dataEncryptieKey,
  versioned: true,
  enforceSSL: true,
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
  objectLockEnabled: true, // Extra bescherming voor medische data
  lifecycleRules: [
    {
      expiration: cdk.Duration.days(5475), // 15 jaar bewaarplicht
    },
  ],
});

cdk.Tags.of(medischeDataBucket).add('NEN7510', 'Ja');
cdk.Tags.of(medischeDataBucket).add('DataType', 'Medisch');

Conclusie

Het bereiken van AVG compliance op AWS vereist een uitgebreide aanpak die technologie, processen en governance combineert. Door deze beheersmaatregelen en automatiseringsscripts te implementeren, kunnen Nederlandse organisaties:

  • Gegevensbescherming by design en default waarborgen
  • Continue compliance monitoring handhaven
  • Efficiënt reageren op verzoeken van betrokkenen
  • Datalekken detecteren en binnen AVG-termijnen reageren
  • Verantwoording afleggen aan toezichthoudende autoriteiten

Belangrijkste Punten:

  • Gebruik AWS services ontworpen voor compliance (KMS, CloudTrail, Config, GuardDuty)
  • Forceer EU data residency via SCPs en regio controles
  • Implementeer uitgebreide encryptie voor data in rust en tijdens transport
  • Automatiseer compliance monitoring en rapportage
  • Bereid je voor op verzoeken van betrokkenen met geautomatiseerde workflows
  • Onderhoud gedetailleerde audit trails voor 7+ jaar

Klaar om je AWS infrastructuur AVG-compliant te maken? Neem contact op met Forrict voor expert begeleiding afgestemd op Nederlandse organisaties.

Resources

F

Fons Biemans

AWS expert en consultant bij Forrict, gespecialiseerd in cloud architectuur en AWS best practices voor Nederlandse bedrijven.

Tags

AWS Security AVG GDPR Compliance Databescherming Privacy

Gerelateerde Artikelen

Klaar om je AWS Infrastructuur te Transformeren?

Laten we bespreken hoe we je cloud journey kunnen optimaliseren