Skip to main content
HB
Platform & Cloud
Freelance client

GDPR and SOC 2 Compliant Data Pipeline on AWS

AWS Glue · KMS · S3 · IAM · CloudTrail · Macie · Step Functions · PostgreSQL RDS

Hasan Iqbal Butt
By Hasan Iqbal ButtPublished: January 2025
0hInternal erasure SLA (vs. 2-3 weeks before)
0MRecords processed per day
0Exceptions noted in SOC 2 Type II report
0Unencrypted PII objects found and remediated at rollout

Client details are anonymized under NDA. Architecture, metrics, and war stories are from the real production system.

TL;DR
  • A fintech operating in Germany and the Netherlands was handling GDPR erasure requests with a spreadsheet and email chains. It took 2-3 weeks per request, and a spot check showed roughly 30% of requests missed at least one downstream system.
  • I built a centralized pipeline: Glue ETL with field-level KMS encryption, a consent registry in Postgres, and Step Functions orchestrating erasure across all twelve systems with retries and rollback.
  • Erasure now completes inside a self-imposed 72-hour SLA, and the system went through a SOC 2 Type II observation period with no exceptions noted. Compliance infra costs roughly $1,200/month.
01

The Challenge

The client, a European fintech operating in Germany and the Netherlands, had customer data scattered across twelve internal systems: a CRM, two billing platforms, a data warehouse on Redshift, several S3 buckets, a MongoDB analytics cluster, and six microservice databases. When a customer exercised their GDPR right to erasure, the compliance team would manually create a spreadsheet listing every system, email each team lead, and hope that each team actually deleted the data. A spot check revealed that roughly thirty percent of deletion requests had been missed in at least one downstream system. The company was also preparing for a SOC 2 Type II audit. SOC 2 is not pass/fail; the auditor issues a report on whether controls operated effectively over a sustained observation period. The existing infrastructure had no centralized audit logging, no field-level encryption, and no automated PII detection. There was no Airflow footprint, the team had four engineers, and the timeline was five months to the audit start date.

02

Constraints

  • No existing orchestration platform. The client had no Airflow footprint, and the platform team was two people.
  • EU data residency: all customer data had to stay in eu-west-1, enforced technically via SCPs, not by policy document.
  • The twelve source systems were owned by different teams. I could not mandate changes to their internal schemas.
  • Compliance infrastructure budget was soft-capped around $1,500/month.
  • SOC 2 observation window was already scheduled. Roughly five months to be audit-ready.

03

Key Decisions

Erasure orchestrationStep Functions

Considered: Cron-driven Lambda polling an SQS deletion queue / Managed Airflow (MWAA) / Step Functions

Why: The execution history is itself audit evidence. When the auditor asked "prove this request touched all twelve systems," I handed over the state machine execution log instead of reconstructing it from application logs.

Trade-off: Vendor lock-in, and the state machine definition is now roughly 600 lines of ASL JSON. Not pretty, but defensible.

Encryption granularityPer-field-type keys (names, emails, national IDs)

Considered: Bucket-level SSE-KMS / One data key per record / One customer-managed key per PII field type

Why: Bucket-level SSE protects against lost disks, not against a compromised role that can read the bucket. Per-record keys would have been ideal for crypto-shredding but blew past KMS request limits at our volume.

Trade-off: Erasure still requires Parquet partition rewrites for the data lake. The one decision I would revisit.

Consent registry storePostgreSQL RDS

Considered: DynamoDB / PostgreSQL RDS

Why: Consent state is relational by nature: subjects, consent types, state transitions, legal bases. The compliance team also needed ad-hoc SQL access for regulator queries, which DynamoDB makes painful.

Trade-off: One more instance to patch and fail over. Multi-AZ covered the SOC 2 availability criteria.

PII detectionMacie

Considered: Custom regex scanning in a Lambda / AWS Macie

Why: A custom scanner is a forever-maintenance project. Macie's managed identifiers handled the common cases, and "we use the AWS-native service" is an easier conversation with auditors.

Trade-off: Cost scales with scanned volume, and the false-positive tuning took real effort.


04

The Approach

The hardest design call was orchestration. I considered three options: a cron-driven Lambda that polls a deletion queue (too opaque when something fails), Airflow via MWAA (no team experience, overkill for one workflow), and Step Functions. I chose Step Functions for one specific reason: the execution history is itself audit evidence. When the SOC 2 auditor asked "prove this deletion request touched all twelve systems," I handed over the execution log instead of reconstructing it from application logs. The trade-off is vendor lock-in and a ~600-line JSON state machine definition. The pipeline runs on AWS Glue with PySpark. Each source has a dedicated crawler and ETL job that validates, deduplicates, and applies field-level envelope encryption before writing to S3. Each PII field type has its own KMS key. This is crypto-shredding: revoking a key renders every instance of that field unreadable across the entire data lake without modifying any files. The consent registry is a PostgreSQL RDS instance gating every processing job. When a deletion request arrives, Step Functions fans out to twelve parallel branches, each with its own deletion method and retry logic. Macie runs daily PII scans, quarantining violations. CloudTrail logs ship to a dedicated audit account for tamper resistance.

05

GDPR Pipeline Architecture

GDPR Compliance Pipeline Architecture

Field-level encryption, right-to-erasure orchestration, PII detection, and tamper-resistant audit logging. Click any node to view implementation details.

DATA INGESTIONCOMPLIANCE CONTROLSERASURE ORCHESTRATIONExtractEncryptStoreCheckQueueFan-outDeleteScanQuarantineShipLogValidate12 Source SystemsCRM, Billing, Redshift, S3, Mongo, 6 DBsAWS Glue ETLPySpark + Schema ValidationAWS KMSPer-field Data KeysS3 Data LakeEncrypted ParquetPostgreSQL RDSConsent RegistryErasure RequestData Subject / ComplianceStep FunctionsParallel Fan-out12 Delete BranchesREST + SQL + Parquet RewriteAWS MacieDaily PII ScanQuarantine BucketRestricted AccessCloudTrailAudit LogsAudit AWS AccountTamper-Resistant
Select a node to view infrastructure details
Primary data flow
Validation / audit path
06

Interactive Demo

Walk through the system design and data flow for this project step by step.

One data subject requests deletion. Step Functions fans out to 12 systems in parallel with retry on transient failures.
CRM
REST API
PENDING
Billing (EU)
REST API
PENDING
Billing (NL)
REST API
PENDING
Redshift DWH
SQL DELETE
PENDING
S3 Data Lake
Parquet Rewrite
PENDING
Mongo Analytics
Lambda
PENDING
Auth Service
SQL DELETE
PENDING
Notifications
SQL DELETE
PENDING
Payment Svc
REST API
PENDING
Orders DB
SQL DELETE
PENDING
Support Tickets
REST API
PENDING
S3 Documents
Object Delete
PENDING
Step Functions Parallel Fan-outComplianceArchitecture

The state machine uses a Map state with MaxConcurrency=12 to execute all branches simultaneously. Each branch is an independent task with its own error handler. The execution ARN becomes the audit trail. When the SOC 2 auditor asks "prove request #4821 touched all twelve systems," the execution history answers that question directly.

Benefit
Average completion time is 14 seconds. The slowest branch (Parquet rewrite on the data lake) determines the total time. All other branches finish in under 2 seconds.
Risk Without This
Without parallel orchestration, sequential deletion across 12 systems took 45+ seconds and had no built-in retry. A single failure in the chain silently skipped downstream systems.

07

Overview

Built a data processing pipeline on AWS for a European fintech that had to satisfy both GDPR Article 17 right-to-erasure obligations and SOC 2 Type II audit requirements. The core problem was straightforward but hard in practice: customer data lived in twelve different systems, and when someone asked for their data to be deleted, the previous process involved a spreadsheet and a prayer. I designed the pipeline around crypto-shredding with AWS KMS so erasure does not require rewriting Parquet files, an orchestration layer in Step Functions that fans out to all twelve systems in parallel, and a consent registry in PostgreSQL RDS that gates every processing job. We set an internal 72-hour right-to-erasure SLA, well inside the one-month window that GDPR Article 12 allows. The system received a clean SOC 2 Type II report with no exceptions noted across the in-scope Trust Service Criteria.

08

Business Impact

The pipeline processes roughly four million records per day across twelve source systems. Right-to-erasure requests complete within 72 hours, down from a previous manual process that took two to three weeks. The SOC 2 Type II audit covered a six-month observation period and the report came back with no exceptions noted. Macie detected 847 instances of unencrypted PII in legacy S3 buckets during the initial rollout, though about a third turned out to be false positives on UUIDs that pattern-matched as national IDs. Monthly AWS spend for the compliance infrastructure is roughly $1,200. Client details anonymized under NDA. Metrics are from the production system.

09

What Went Wrong

Macie's first full scan was a flood. It flagged thousands of "national ID" matches that were actually internal UUIDs with an unlucky digit pattern. The first week was spent building suppression rules and a custom allow-list before the signal-to-noise ratio was usable. The 847 genuine findings were buried in roughly 12,000 raw alerts. If I had turned on auto-quarantine before tuning, I would have broken half the analytics team's jobs on day one.

KMS throttling nearly sank the encryption design. Calling GenerateDataKey per field per record at 4M records/day exceeded the default request quota within minutes of the first production run. The fix was caching data keys at the Spark-partition level. This slightly enlarges the blast radius of a single data key and that trade-off is documented in the threat model.

The MongoDB deletion branch taught me why idempotency was worth the effort. An early version deleted by a query that, on retry after a partial failure, matched documents belonging to a different customer with a colliding legacy identifier. It was caught in staging by a test I had almost not written.

10

Lessons Learned

If I built this again, the data lake erasure branch would use crypto-shredding from day one: encrypt with per-subject data keys so that erasure means deleting a key, not rewriting Parquet partitions. The partition rewrites work and they are auditable, but they are the slowest and most fragile branch of the twelve, and they are the reason the SLA is 72 hours instead of 24.

I also underestimated the documentation half of SOC 2 by roughly a factor of two. The controls were the easy part; producing evidence that the controls had operated continuously across the observation window was its own workstream. Both low-severity observations in the final report were documentation gaps, not technical ones.

11

Technical Highlights

  • Crypto-shredding via per-field KMS data keys: revoking a key renders that PII field unreadable across the entire data lake without rewriting files
  • Consent management registry in PostgreSQL RDS tracking opt-in, opt-out, and withdrawal with timestamps and legal basis per data subject
  • Right-to-erasure orchestration via Step Functions fanning out to 12 systems with retry, backoff, and partial-failure alerting
  • Macie daily scans with custom data identifiers tuned to reduce UUID false positives from 30% to under 2%
  • CloudTrail logs shipped to a separate audit AWS account that engineering cannot access, with integrity validation enabled
  • Data residency enforcement via SCP policies blocking cross-region replication for EU citizen data in eu-west-1
  • SOC 2 Type II controls mapped to CC6 (logical access), CC7 (system operations), CC8 (change management)
  • Glue ETL jobs with PySpark doing schema validation, deduplication via deterministic hash, and field-level envelope encryption
  • Data retention at the S3 lifecycle level: transition to Glacier after 90 days, deletion after 7 years
  • Quarterly IAM access reviews automated via Lambda comparing role assignments against the HR system active employee list
  • KMS data key caching per Glue partition to stay under the 10,000 requests/second API throttling limit
  • MongoDB deletion branch required special idempotency handling because the analytics cluster had no unique delete endpoint

Want results like this for your infrastructure?

I specialize in taking complex AI pipelines and cloud setups from concept to high-availability production. Let's discuss how to optimize your workloads, secure your environment, and reduce cloud costs.