Module 3: Technical Implementation

Secure Data Deletion

15 min
+50 XP

Secure Data Deletion

ISO 27018 requires secure, verifiable deletion of PII when it's no longer needed. This lesson covers deletion methods, verification procedures, and implementation strategies for cloud environments.

Why Secure Deletion Matters

ISO 27018 Requirement: "The public cloud PII processor shall securely delete or render unrecoverable PII at the end of the contract or upon customer request."

Key Concerns:

  • Prevent data recovery after deletion
  • Meet retention policy requirements
  • Support "right to be forgotten"
  • Enable contract termination cleanup
  • Reduce data breach exposure

Deletion Methods

1. Logical Deletion (Soft Delete)

Description: Mark data as deleted without physical removal

Use Cases:

  • Temporary deletion with recovery period
  • Compliance with retention policies
  • Audit trail preservation

Implementation:

interface SoftDeleteRecord {
  id: string;
  data: any;
  deleted_at?: Date;
  deleted_by?: string;
  permanent_deletion_date?: Date;
}

class SoftDeleteService {
  async softDelete(recordId: string, userId: string): Promise<void> {
    const permanentDeletionDate = new Date();
    permanentDeletionDate.setDate(permanentDeletionDate.getDate() + 30); // 30-day grace period

    await this.database.update('pii_records', recordId, {
      deleted_at: new Date(),
      deleted_by: userId,
      permanent_deletion_date: permanentDeletionDate
    });

    // Schedule permanent deletion
    await this.scheduler.schedule(permanentDeletionDate, 'permanent_delete', {
      recordId,
      tableName: 'pii_records'
    });

    await this.auditLog.record('SOFT_DELETE', {
      recordId,
      userId,
      scheduledPermanentDeletion: permanentDeletionDate
    });
  }

  // Query filter to exclude soft-deleted records
  async query(conditions: any): Promise<any[]> {
    return await this.database.query({
      ...conditions,
      deleted_at: null // Exclude soft-deleted
    });
  }
}

2. Physical Deletion (Hard Delete)

Description: Permanently remove data from storage

Use Cases:

  • End of retention period
  • Confirmed deletion request
  • Contract termination
  • "Right to be forgotten" compliance

Implementation:

class PhysicalDeleteService {
  async hardDelete(recordId: string): Promise<DeletionCertificate> {
    // 1. Delete from primary database
    const primaryDeleted = await this.deletePrimaryRecord(recordId);

    // 2. Delete from all replicas
    const replicasDel ted = await this.deleteFromReplicas(recordId);

    // 3. Delete from backups (mark for purge on next backup cycle)
    await this.markBackupsForPurge(recordId);

    // 4. Delete from search indexes
    await this.deleteFromSearchIndex(recordId);

    // 5. Delete from caches
    await this.deleteFromCache(recordId);

    // 6. Notify sub-processors
    await this.notifySubProcessorsToDelete(recordId);

    // 7. Generate deletion certificate
    const certificate = await this.generateDeletionCertificate({
      recordId,
      deletionDate: new Date(),
      method: 'physical_deletion',
      locationsDeleted: [
        'primary_database',
        ...replicasDe leted,
        'search_index',
        'cache'
      ],
      verificationHash: this.calculateVerificationHash(recordId)
    });

    // 8. Audit log
    await this.auditLog.record('HARD_DELETE', {
      recordId,
      certificate: certificate.id,
      timestamp: new Date()
    });

    return certificate;
  }

  private async deleteFromReplicas(recordId: string): Promise<string[]> {
    const replicas = await this.getReplicaLocations();
    const deleted: string[] = [];

    for (const replica of replicas) {
      await replica.delete(recordId);
      deleted.push(replica.name);
    }

    return deleted;
  }
}

3. Cryptographic Erasure

Description: Destroy encryption keys, making encrypted data unrecoverable

Use Cases:

  • Cloud storage deletion
  • Large-scale deletions
  • High-security requirements
  • Hardware disposal

Implementation:

class CryptographicErasure {
  async cryptoErase(customerId: string): Promise<void> {
    // 1. Identify all encryption keys for customer
    const keys = await this.keyManagement.getCustomerKeys(customerId);

    // 2. Verify no other customers use these keys
    const exclusive = await this.verifyExclusiveKeyUsage(keys, customerId);
    if (!exclusive) {
      throw new Error('Keys shared with other customers - cannot crypto-erase');
    }

    // 3. Delete encryption keys from key management system
    for (const key of keys) {
      await this.keyManagement.deleteKey(key.id);
      await this.auditLog.record('KEY_DELETED', {
        keyId: key.id,
        customerId,
        method: 'cryptographic_erasure'
      });
    }

    // 4. Mark encrypted data for cleanup
    // (Optional: data now unrecoverable but can be cleaned up for storage)
    await this.markEncryptedDataForCleanup(customerId);

    // 5. Certificate
    await this.generateErasureCertificate(customerId, keys);
  }

  // Key-per-customer architecture for crypto-erasure
  async encryptWithCustomerKey(
    customerId: string,
    data: Buffer
  ): Promise<EncryptedData> {
    const customerKey = await this.keyManagement.getOrCreateCustomerKey(
      customerId
    );

    return await this.encrypt(data, customerKey);
  }
}

4. Secure Overwrite

Description: Overwrite data multiple times with random data

Use Cases:

  • Physical media disposal
  • VM/container cleanup
  • High-security requirements
  • Regulatory compliance (DOD 5220.22-M)

Implementation:

class SecureOverwriteService {
  async secureOverwrite(
    filePath: string,
    passes: number = 3
  ): Promise<OverwriteResult> {
    const fileSize = await this.getFileSize(filePath);
    const blockSize = 4096; // 4KB blocks

    for (let pass = 0; pass < passes; pass++) {
      const pattern = this.getOverwritePattern(pass);

      for (let offset = 0; offset < fileSize; offset += blockSize) {
        const data = this.generatePattern(pattern, blockSize);
        await this.writeBlock(filePath, offset, data);
      }

      // Verify overwrite
      await this.verifyOverwrite(filePath, pattern);
    }

    // Final pass: random data
    await this.overwriteWithRandom(filePath);

    // Delete file
    await fs.unlink(filePath);

    return {
      filePath,
      passes,
      verified: true,
      timestamp: new Date()
    };
  }

  private getOverwritePattern(pass: number): OverwritePattern {
    // DOD 5220.22-M pattern
    const patterns = [
      'zeros',    // Pass 1: All zeros
      'ones',     // Pass 2: All ones
      'random'    // Pass 3: Random
    ];
    return patterns[pass % 3];
  }
}

Cloud-Specific Deletion

AWS Deletion

class AWSDeletionService {
  async deleteS3Objects(bucket: string, prefix: string): Promise<void> {
    const s3 = new AWS.S3();

    // List all objects
    const objects = await this.listAllObjects(bucket, prefix);

    // Delete in batches
    for (let i = 0; i < objects.length; i += 1000) {
      const batch = objects.slice(i, i + 1000);
      await s3.deleteObjects({
        Bucket: bucket,
        Delete: {
          Objects: batch.map(obj => ({ Key: obj.Key }))
        }
      }).promise();
    }

    // Verify deletion
    const remaining = await this.listAllObjects(bucket, prefix);
    if (remaining.length > 0) {
      throw new Error('Deletion verification failed');
    }
  }

  async deleteRDSSnapshots(dbInstanceId: string): Promise<void> {
    const rds = new AWS.RDS();
    const snapshots = await rds.describeDBSnapshots({
      DBInstanceIdentifier: dbInstanceId
    }).promise();

    for (const snapshot of snapshots.DBSnapshots) {
      await rds.deleteDBSnapshot({
        DBSnapshotIdentifier: snapshot.DBSnapshotIdentifier
      }).promise();
    }
  }

  async deleteEBSVolumes(volumeIds: string[]): Promise<void> {
    const ec2 = new AWS.EC2();

    for (const volumeId of volumeIds) {
      // Detach if attached
      await this.detachVolume(volumeId);

      // Delete volume
      await ec2.deleteVolume({ VolumeId: volumeId }).promise();
    }
  }
}

Azure Deletion

class AzureDeletionService {
  async deleteBlobStorage(
    containerName: string,
    blobPrefix: string
  ): Promise<void> {
    const blobService = azure.createBlobService();

    // List blobs
    const blobs = await this.listAllBlobs(containerName, blobPrefix);

    // Delete blobs
    for (const blob of blobs) {
      await blobService.deleteBlob(containerName, blob.name);
    }

    // Delete container if empty
    const isEmpty = await this.isContainerEmpty(containerName);
    if (isEmpty) {
      await blobService.deleteContainer(containerName);
    }
  }

  async deleteSQLDatabase(serverName: string, dbName: string): Promise<void> {
    // Delete database
    await this.sqlClient.databases.delete(resourceGroup, serverName, dbName);

    // Delete backups
    await this.deleteBackups(serverName, dbName);
  }
}

Google Cloud Deletion

class GCPDeletionService {
  async deleteGCSObjects(bucketName: string, prefix: string): Promise<void> {
    const storage = new Storage();
    const bucket = storage.bucket(bucketName);

    // Delete objects with prefix
    await bucket.deleteFiles({ prefix });

    // Verify deletion
    const [files] = await bucket.getFiles({ prefix });
    if (files.length > 0) {
      throw new Error('Deletion verification failed');
    }
  }

  async deleteCloudSQLInstance(instanceId: string): Promise<void> {
    const sqladmin = google.sqladmin('v1beta4');

    // Delete instance (includes all data and backups)
    await sqladmin.instances.delete({
      project: projectId,
      instance: instanceId
    });
  }
}

Backup and Archive Deletion

Backup Purge Strategy

class BackupPurgeService {
  async purgeFromBackups(recordId: string): Promise<void> {
    // 1. Identify backups containing the record
    const backups = await this.findBackupsContainingRecord(recordId);

    // 2. For each backup
    for (const backup of backups) {
      if (this.canModifyBackup(backup)) {
        // Remove specific record from backup
        await this.removeRecordFromBackup(backup, recordId);
      } else {
        // Mark backup for deletion at next cycle
        await this.markBackupForFullDeletion(backup);
      }
    }

    // 3. Verify purge
    await this.verifyRecordNotInBackups(recordId);
  }

  private async removeRecordFromBackup(
    backup: Backup,
    recordId: string
  ): Promise<void> {
    // Restore backup to temporary location
    const tempLocation = await this.restoreBackup(backup);

    // Delete specific record
    await this.deleteRecordFromTemp(tempLocation, recordId);

    // Create new backup without the record
    await this.createModifiedBackup(tempLocation, backup);

    // Delete old backup
    await this.deleteBackup(backup);

    // Cleanup temp
    await this.cleanupTemp(tempLocation);
  }
}

Deletion Verification

Verification Process

interface DeletionVerification {
  recordId: string;
  verificationType: 'primary' | 'replicas' | 'backups' | 'caches' | 'sub-processors';
  verified: boolean;
  timestamp: Date;
  verifiedBy: string;
  method: string;
}

class DeletionVerificationService {
  async verifyDeletion(recordId: string): Promise<DeletionReport> {
    const verifications: DeletionVerification[] = [];

    // 1. Verify primary database
    verifications.push(await this.verifyPrimaryDatabase(recordId));

    // 2. Verify replicas
    verifications.push(await this.verifyReplicas(recordId));

    // 3. Verify backups
    verifications.push(await this.verifyBackups(recordId));

    // 4. Verify caches
    verifications.push(await this.verifyCaches(recordId));

    // 5. Verify search indexes
    verifications.push(await this.verifySearchIndexes(recordId));

    // 6. Verify sub-processors
    verifications.push(await this.verifySubProcessors(recordId));

    const allVerified = verifications.every(v => v.verified);

    return {
      recordId,
      verifications,
      fullyDeleted: allVerified,
      timestamp: new Date()
    };
  }

  private async verifyPrimaryDatabase(recordId: string): Promise<DeletionVerification> {
    const exists = await this.database.exists('pii_records', { id: recordId });

    return {
      recordId,
      verificationType: 'primary',
      verified: !exists,
      timestamp: new Date(),
      verifiedBy: 'automated_verification',
      method: 'database_query'
    };
  }
}

Deletion Certificate

Generating Certificates

interface DeletionCertificate {
  certificateId: string;
  customerId: string;
  recordIds: string[];
  deletionMethod: 'physical' | 'cryptographic' | 'overwrite';
  deletionDate: Date;
  locationsDeleted: string[];
  verificationResults: DeletionVerification[];
  certificateHash: string;
  signedBy: string;
  digitalSignature: string;
}

class DeletionCertificateService {
  async generateCertificate(
    customerId: string,
    deletionReport: DeletionReport
  ): Promise<DeletionCertificate> {
    const certificate: DeletionCertificate = {
      certificateId: generateId(),
      customerId,
      recordIds: deletionReport.recordIds,
      deletionMethod: deletionReport.method,
      deletionDate: new Date(),
      locationsDeleted: deletionReport.locations,
      verificationResults: deletionReport.verifications,
      certificateHash: '',
      signedBy: 'Cloud Service Provider',
      digitalSignature: ''
    };

    // Calculate hash
    certificate.certificateHash = this.calculateHash(certificate);

    // Digital signature
    certificate.digitalSignature = await this.signCertificate(
      certificate.certificateHash
    );

    // Store certificate
    await this.storeCertificate(certificate);

    // Send to customer
    await this.sendCertificateToCustomer(customerId, certificate);

    return certificate;
  }

  async verifyCertificate(certificateId: string): Promise<boolean> {
    const certificate = await this.getCertificate(certificateId);
    const calculatedHash = this.calculateHash(certificate);

    return calculatedHash === certificate.certificateHash &&
           await this.verifySignature(certificate.digitalSignature, calculatedHash);
  }
}

Sub-processor Deletion

Ensuring Complete Deletion Chain

class SubProcessorDeletionService {
  async notifySubProcessorsToDelete(recordId: string): Promise<void> {
    const subProcessors = await this.getSubProcessorsWithAccess(recordId);

    const deletionRequests: Promise<void>[] = [];

    for (const sp of subProcessors) {
      deletionRequests.push(
        this.sendDeletionRequest(sp, recordId)
      );
    }

    await Promise.all(deletionRequests);

    // Verify deletion with sub-processors
    await this.verifySubProcessorDeletion(recordId, subProcessors);
  }

  private async sendDeletionRequest(
    subProcessor: SubProcessor,
    recordId: string
  ): Promise<void> {
    const response = await axios.post(
      `${subProcessor.apiUrl}/data-deletion`,
      {
        requestId: generateId(),
        recordId,
        deletionDeadline: addDays(new Date(), 30)
      },
      {
        headers: {
          'Authorization': `Bearer ${subProcessor.apiKey}`
        }
      }
    );

    await this.trackDeletionRequest(subProcessor.id, recordId, response.data);
  }
}

Automated Deletion Workflows

Retention-Based Auto-Deletion

class AutomatedDeletionService {
  async runDeletionJob(): Promise<DeletionJobResult> {
    const deletionDate = new Date();
    const results: DeletionJobResult = {
      jobId: generateId(),
      startTime: deletionDate,
      recordsProcessed: 0,
      recordsDeleted: 0,
      errors: []
    };

    // 1. Find records past retention period
    const recordsToDelete = await this.findExpiredRecords();

    // 2. Process deletions
    for (const record of recordsToDelete) {
      try {
        await this.deleteRecord(record.id);
        results.recordsDeleted++;
      } catch (error) {
        results.errors.push({
          recordId: record.id,
          error: error.message
        });
      }
      results.recordsProcessed++;
    }

    // 3. Log job results
    await this.logDeletionJob(results);

    return results;
  }

  private async findExpiredRecords(): Promise<any[]> {
    return await this.database.query(`
      SELECT id, retention_period, created_at
      FROM pii_records
      WHERE deleted_at IS NULL
      AND created_at + INTERVAL retention_period DAY < NOW()
    `);
  }
}

// Schedule daily
cron.schedule('0 2 * * *', async () => {
  await automatedDeletionService.runDeletionJob();
});

Compliance Checklist

Deletion Implementation:

  • Multiple deletion methods available (soft, hard, crypto-erasure)
  • Deletion covers all data locations (primary, replicas, backups, caches)
  • Sub-processor deletion notifications implemented
  • Deletion verification process in place
  • Deletion certificates generated and provided
  • Automated deletion based on retention policies
  • Backup purge procedures documented
  • "Right to be forgotten" requests supported
  • Deletion audit trail comprehensive
  • Deletion SLAs defined and monitored

Documentation:

  • Deletion procedures documented
  • Data flow diagrams show all storage locations
  • Verification procedures documented
  • Certificate generation process documented
  • Sub-processor agreements include deletion obligations

Next Lesson: Sub-processor management - selecting, monitoring, and controlling third-party PII processors.

Complete this lesson

Earn +50 XP and progress to the next lesson