# Key rotation

In 2026, Zero-Downtime Key Rotation is no longer just "nice to have"—it is a strict requirement for financial hubs under DORA (Digital Operational Resilience Act).

To do this right, we use a "Lazy Re-wrap" or "Envelope Rotation" strategy. Instead of decrypting and re-encrypting $$ $500,000$ $$ records in one massive, database-locking transaction, we rotate the Key Encryption Key (KEK) and then re-wrap the Data Encryption Keys (DEKs) in the background.

***

#### 1. The 2026 "Zero-Downtime" Strategy

Your Hub uses Envelope Encryption. Every user record is encrypted with a unique DEK, which is itself encrypted (wrapped) by your KEK stored in HashiCorp Vault or AWS KMS.

* Step A (The KEK Rotation): You instruct Vault to generate a new version of the KEK. All *new* data uses this version.
* Step B (The Re-wrap): A background script iterates through your DB, takes the "Old Wrapped DEK," sends it to Vault's `/rewrap` endpoint, and receives a "New Wrapped DEK."
* Result: The actual PII data in your database never changes and is never decrypted during rotation.

***

#### 2. Implementation: The `KeyRotationService` (AdonisJS)

This script uses a Batch-and-Sleep approach to ensure zero impact on your production database performance.

TypeScript

```
// app/Services/KeyRotationService.ts
import { VaultProvider } from '@hub/data-vault'
import Database from '@ioc:Adonis/Lucid/Database'

export default class KeyRotationService {
  public async rotateKek(kekName: string) {
    console.log(`[${new Date().toISOString()}] Starting rotation for KEK: ${kekName}`)

    // 1. Tell Vault to rotate the Master KEK
    // This makes all future encryptions use the new version automatically
    await VaultProvider.rotateKey(kekName)

    // 2. Fetch all entries still using the old KEK version
    // We assume your 'vault_entries' table has a 'kek_version' column
    const entries = await Database.from('vault_entries')
      .where('kek_name', kekName)
      .whereNot('kek_version', 'latest') // Custom logic to find old versions
      .select('id', 'wrapped_dek')

    console.log(`Found ${entries.length} entries to re-wrap.`)

    // 3. Re-wrap in batches
    const BATCH_SIZE = 100
    for (let i = 0; i < entries.length; i += BATCH_SIZE) {
      const batch = entries.slice(i, i + BATCH_SIZE)
      
      await Promise.all(batch.map(async (entry) => {
        // Vault handles the crypto: Unwraps with Old KEK -> Wraps with New KEK
        const newWrappedDek = await VaultProvider.rewrap(kekName, entry.wrapped_dek)
        
        await Database.from('vault_entries')
          .where('id', entry.id)
          .update({ 
            wrapped_dek: newWrappedDek,
            kek_version: 'v2', // Mark as updated
            rotated_at: Database.fn.now()
          })
      }))

      console.log(`Re-wrapped ${i + batch.length}/${entries.length}...`)
      // Sleep for 100ms to allow other DB operations to breathe
      await new Promise(r => setTimeout(r, 100))
    }

    console.log("KEK Rotation Complete.")
  }
}
```

***

#### 3. The "vLEI Auth" Layer for Rotation

Since rotating a master key is a high-privilege action, your Hub must gate the `rotateKek` method.

* Authorization: The request must be signed by two vLEI Role Credentials (e.g., the CTO and the Security Officer).
* Audit Log: The rotation event is logged as a vLEI-signed ACDC, proving to auditors exactly who authorized the key change and when.

***

#### 4. 2026 Regulatory Checklist (DORA/NIST)

| **Requirement**   | **Implementation in your Hub**                                                 |
| ----------------- | ------------------------------------------------------------------------------ |
| Cryptoperiod      | 90 days (Automated via AdonisJS task scheduler).                               |
| No Plaintext Leak | Data is re-wrapped inside the KMS Enclave, never in your app memory.           |
| Availability      | Zero-Downtime. Old and new KEK versions are both active during the transition. |
| Auditability      | Full vLEI-signed audit trail for the rotation command.                         |

***

#### 🛡️ Why "Rewrapping" is your Moat

If you had to re-encrypt 500k records, you'd face massive gas costs (if on-chain) or CPU spikes (if off-chain). By re-wrapping the DEK (a tiny string), you can rotate millions of records in minutes for nearly zero cost.

####
