Tuesday, November 3, 2026

Oracle TDE Key Rotation & Compliance Automation | AI DBA Hub
Oracle TDE Key Rotation Compliance
🔄 Oracle Security Series

Oracle TDE Key Rotation
& Compliance Automation

Master TDE Master Encryption Key rotation, automate compliance schedules for PCI-DSS, SOX, GDPR and HIPAA, and build audit-ready key management pipelines — with every command covered.

👤 AI DBA Hub 🏷 Oracle TDE · Compliance · Automation ⏱ ~16 min read 🎯 Intermediate–Advanced DBAs

Why Key Rotation Matters — The Compliance Imperative

Transparent Data Encryption protects your data at rest, but encryption is only as strong as your key management discipline. Regulatory frameworks don't just require you to encrypt — they require you to rotate encryption keys regularly, maintain an audit trail of every rotation event, and prove that compromised keys were replaced.

PCI-DSS

Req 3.6.x: Cryptographic key rotation annually or when compromised. Full key lifecycle documentation required.

SOX

Section 404: Key management controls must be documented and tested. Rotation events require audit records.

GDPR

Art. 32: Appropriate technical measures including key rotation. Data breach scope reduced with recent key rotation.

HIPAA

§164.312(a)(2)(iv): Encryption key management. PHI must be encrypted with regularly rotated keys.

ISO 27001

A.10.1: Cryptographic key policies requiring rotation schedules, management procedures and lifecycle controls.

FIPS 140-2

AES-256 required for new rotations. Key lifecycle including creation, distribution, storage and destruction.

⭐
Oracle TDE Key Rotation — What Changed in 26ai Oracle 26ai introduced online key rotation for both individual tablespaces and CDB-wide operations. Rotation now happens without taking tablespaces offline, and the redo stream propagates key changes automatically to Data Guard standbys — turning a multi-hour maintenance window into a background operation.

Understanding TDE Key Hierarchy

Before rotating keys, you must understand the two-level key hierarchy Oracle TDE uses. Confusing the two types leads to incorrect rotation procedures and compliance gaps.

Key TypeAbbreviationPurposeRotation CommandScope
Master Encryption KeyMEKEncrypts all Tablespace Encryption Keys. Stored in wallet/OKV.ADMINISTER KEY MANAGEMENT SET KEYCDB / PDB
Tablespace Encryption KeyTEKEncrypts actual data blocks. Wrapped by the MEK.ALTER TABLESPACE … REKEYPer tablespace
💡
MEK vs TEK Rotation — Know the Difference MEK rotation (most common) replaces the top-level master key without touching data blocks. Fast, non-disruptive. TEK rotation (REKEY) re-encrypts every data block in the tablespace with a new key — resource-intensive but required for highest-security compliance postures or post-breach scenarios. Most rotation schedules require MEK rotation; TEK rotation is the nuclear option.

Types of Key Rotation Operations

🔑 Scheduled MEK Rotation

Routine compliance-driven rotation of the Master Encryption Key. Required by PCI-DSS annually. Fast, runs online, no tablespace downtime. Most common operation.

⚡ Emergency MEK Rotation

Triggered when a key is suspected compromised. Must be executed immediately regardless of maintenance windows. Requires immediate Standby sync and audit documentation.

🔄 Tablespace REKEY (TEK)

Full re-encryption of all data blocks with a new Tablespace Encryption Key. Used post-breach or for algorithm upgrades (3DES → AES256). Resource-intensive — plan I/O carefully.

🗄️ CDB-Wide Rotation

Rotates MEK for the CDB root and all open PDBs in a single operation using CONTAINER=ALL. Ensures consistent rotation timestamps across all pluggable databases.

MEK Rotation — Step by Step

⚠️
Pre-Rotation Checklist (1) Verify keystore is OPEN on Primary AND all Standbys. (2) Take OS backup of WALLET_ROOT. (3) Record current MEK ID from V$ENCRYPTION_KEYS for audit trail. (4) Confirm no other keystore operation is in progress.

Step 1: Pre-Rotation Audit Snapshot

SQL — Pre-Rotation State Capture
-- Capture current MEK details BEFORE rotation (for audit log)
SELECT
    key_id,
    creation_time,
    activation_time,
    retired_time,
    keystoretype,
    creator,
    con_id
FROM   v$encryption_keys
ORDER BY activation_time DESC;

-- Verify keystore status on Primary
SELECT wrl_type, status, wallet_type, fully_backed_up
FROM   v$encryption_wallet;

-- Backup wallet (OS command — run before proceeding)
-- cp -rp $WALLET_ROOT/tde /backup/tde_pre_rotation_$(date +%Y%m%d_%H%M%S)

Step 2: Rotate the Master Encryption Key

SQL — MEK Rotation Commands
-- ═══════════════════════════════════════════════════════
-- OPTION A: Non-CDB / Single PDB Rotation
-- ═══════════════════════════════════════════════════════
ADMINISTER KEY MANAGEMENT
    SET KEY
    USING TAG 'PCI_ROTATION_2024Q4'     -- Audit tag for compliance
    IDENTIFIED BY "WalletPassword@2024"
    WITH BACKUP USING 'pre_rotation_2024Q4'  -- Keystore backup
    FORCE KEYSTORE;

-- ═══════════════════════════════════════════════════════
-- OPTION B: CDB-Wide Rotation (Root + All Open PDBs)
-- ═══════════════════════════════════════════════════════
ALTER SESSION SET container = CDB$ROOT;

ADMINISTER KEY MANAGEMENT
    SET KEY
    USING TAG 'SOX_ROTATION_2024Q4_CDB'
    IDENTIFIED BY "WalletPassword@2024"
    WITH BACKUP USING 'cdb_rotation_2024Q4'
    FORCE KEYSTORE
    CONTAINER=ALL;                          -- Rotates in CDB + all PDBs

-- ═══════════════════════════════════════════════════════
-- OPTION C: OKV (Oracle Key Vault) — No Password Needed
-- ═══════════════════════════════════════════════════════
ADMINISTER KEY MANAGEMENT
    SET KEY
    USING TAG 'GDPR_ROTATION_2024Q4'
    IDENTIFIED EXTERNALLY
    WITH BACKUP
    FORCE KEYSTORE
    CONTAINER=ALL;

Step 3: Post-Rotation Verification

SQL — Post-Rotation Audit Verification
-- Verify new MEK is active (activation_time should be NOW)
SELECT
    key_id,
    creator,
    creation_time,
    activation_time,
    tag                   -- Shows your USING TAG value — key audit link
FROM   v$encryption_keys
WHERE  activation_time = (SELECT MAX(activation_time) FROM v$encryption_keys);

-- Verify previous MEK is now RETIRED (not ACTIVE)
SELECT key_id, activation_time, retired_time, tag
FROM   v$encryption_keys
ORDER BY activation_time DESC;

-- Confirm fully_backed_up = YES after rotation
SELECT status, wallet_type, fully_backed_up
FROM   v$encryption_wallet;

-- Check all tablespaces still encrypted (no regressions)
SELECT tablespace_name, encrypted, encryption_algorithm
FROM   v$encrypted_tablespaces;

Tablespace REKEY (TEK Rotation)

TEK rotation re-encrypts every data block. Use for post-breach remediation, algorithm upgrades, or ultra-strict compliance postures. Oracle 26ai makes this online.

SQL — Online Tablespace REKEY (Oracle 26ai)
-- Online REKEY — tablespace stays accessible during operation
ALTER TABLESPACE USERS
    ENCRYPTION ONLINE
    USING 'AES256'
    REKEY;

-- Monitor REKEY progress
SELECT
    tablespace_name,
    encryption_algorithm,
    rekey_status,       -- IN_PROGRESS / COMPLETED / FAILED
    pct_rekeyed,        -- Percentage complete
    last_rekey_time
FROM   v$encrypted_tablespaces
WHERE  rekey_status IS NOT NULL;

-- Using DBMS_SPACE_ADMIN for programmatic REKEY with DG propagation
EXEC DBMS_SPACE_ADMIN.TABLESPACE_REKEY(
    tablespace_name => 'USERS',
    encrypt_algo    => DBMS_SPACE_ADMIN.ENCRYPT_AES256,
    online_mode     => TRUE,
    dg_propagate    => TRUE    -- Auto-propagate to Standbys
);

Compliance Automation — Scripting Key Rotation

Manual key rotation is error-prone and audit-risky. The gold standard is an automated rotation pipeline triggered by a scheduler (DBMS_SCHEDULER, cron, or OEM) with built-in pre/post checks and audit logging.

🔄 Automated Key Rotation Pipeline
1. Trigger
DBMS_SCHEDULER / cron
Scheduled
→
2. Pre-Check
Keystore OPEN? DG sync OK?
→
3. Backup
OS wallet backup
→
4. Rotate MEK
SET KEY with TAG
8. Notify
Email / Slack / ITSM
Compliance
←
7. Audit Log
Write to audit table
←
6. DG Sync
Standby verification
←
5. Verify
New key active? Keys intact?

Automated Rotation Procedure — PL/SQL

PL/SQL — Complete Automated Rotation Procedure
-- ═══════════════════════════════════════════════════════════
-- CREATE AUDIT TABLE (run once)
-- ═══════════════════════════════════════════════════════════
CREATE TABLE dba_tde_rotation_log (
    log_id          NUMBER       GENERATED ALWAYS AS IDENTITY,
    rotation_date   DATE         DEFAULT SYSDATE,
    rotation_type   VARCHAR2(20),  -- MEK / TEK / CDB_MEK
    compliance_tag  VARCHAR2(100),
    old_key_id      VARCHAR2(100),
    new_key_id      VARCHAR2(100),
    rotated_by      VARCHAR2(50) DEFAULT SYS_CONTEXT('USERENV','OS_USER'),
    status          VARCHAR2(20),  -- SUCCESS / FAILED
    error_msg       VARCHAR2(4000),
    CONSTRAINT pk_tde_log PRIMARY KEY (log_id)
);

-- ═══════════════════════════════════════════════════════════
-- AUTOMATED ROTATION PROCEDURE
-- ═══════════════════════════════════════════════════════════
CREATE OR REPLACE PROCEDURE sp_tde_rotate_mek (
    p_wallet_pwd    IN VARCHAR2,
    p_compliance_tag IN VARCHAR2 DEFAULT 'SCHEDULED_ROTATION',
    p_cdb_wide      IN BOOLEAN  DEFAULT FALSE
) AS
    v_old_key_id  VARCHAR2(100);
    v_new_key_id  VARCHAR2(100);
    v_wallet_open VARCHAR2(10);
    v_sql         VARCHAR2(4000);
BEGIN
    -- Pre-check: verify keystore is open
    SELECT status INTO v_wallet_open
    FROM   v$encryption_wallet WHERE ROWNUM = 1;

    IF v_wallet_open NOT IN ('OPEN','OPEN_NO_MASTER_KEY') THEN
        RAISE_APPLICATION_ERROR(-20001, 'Keystore not open. Status: ' || v_wallet_open);
    END IF;

    -- Capture current (old) key ID
    SELECT key_id INTO v_old_key_id
    FROM   v$encryption_keys
    WHERE  activation_time = (SELECT MAX(activation_time) FROM v$encryption_keys)
    AND    ROWNUM = 1;

    -- Build rotation SQL with compliance tag
    IF p_cdb_wide THEN
        v_sql := 'ADMINISTER KEY MANAGEMENT SET KEY '
               || 'USING TAG ''' || p_compliance_tag || ''' '
               || 'IDENTIFIED BY "' || p_wallet_pwd || '" '
               || 'WITH BACKUP FORCE KEYSTORE CONTAINER=ALL';
    ELSE
        v_sql := 'ADMINISTER KEY MANAGEMENT SET KEY '
               || 'USING TAG ''' || p_compliance_tag || ''' '
               || 'IDENTIFIED BY "' || p_wallet_pwd || '" '
               || 'WITH BACKUP FORCE KEYSTORE';
    END IF;

    -- Execute the rotation
    EXECUTE IMMEDIATE v_sql;

    -- Capture new key ID
    SELECT key_id INTO v_new_key_id
    FROM   v$encryption_keys
    WHERE  activation_time = (SELECT MAX(activation_time) FROM v$encryption_keys)
    AND    ROWNUM = 1;

    -- Write audit log entry
    INSERT INTO dba_tde_rotation_log
        (rotation_type, compliance_tag, old_key_id, new_key_id, status)
    VALUES
        (CASE WHEN p_cdb_wide THEN 'CDB_MEK' ELSE 'MEK' END,
         p_compliance_tag, v_old_key_id, v_new_key_id, 'SUCCESS');
    COMMIT;

EXCEPTION
    WHEN OTHERS THEN
        INSERT INTO dba_tde_rotation_log
            (rotation_type, compliance_tag, old_key_id, status, error_msg)
        VALUES
            ('MEK', p_compliance_tag, v_old_key_id, 'FAILED', SQLERRM);
        COMMIT;
        RAISE;
END sp_tde_rotate_mek;
/

DBMS_SCHEDULER — Scheduling Automated Rotation

SQL — Schedule Annual Rotation Job (PCI-DSS)
-- Schedule annual MEK rotation — PCI-DSS requirement (rotate at least yearly)
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'TDE_MEK_ANNUAL_ROTATION',
        job_type        => 'STORED_PROCEDURE',
        job_action      => 'sp_tde_rotate_mek',
        number_of_arguments => 3,
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=15;BYHOUR=2;BYMINUTE=0',
        enabled         => FALSE,
        comments        => 'Annual TDE MEK rotation — PCI-DSS Req 3.6.x compliance'
    );

    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
        job_name   => 'TDE_MEK_ANNUAL_ROTATION',
        argument_position => 1,
        argument_value    => 'WalletPassword@2024'    -- Use OKV to avoid plaintext!
    );

    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
        job_name          => 'TDE_MEK_ANNUAL_ROTATION',
        argument_position => 2,
        argument_value    => 'PCI_DSS_ANNUAL_ROTATION'
    );

    DBMS_SCHEDULER.ENABLE('TDE_MEK_ANNUAL_ROTATION');
END;
/

-- Verify job scheduled correctly
SELECT job_name, state, next_run_date, repeat_interval, comments
FROM   dba_scheduler_jobs
WHERE  job_name LIKE 'TDE%';

Data Guard — Key Rotation Propagation

SQL — Post-Rotation Standby Verification
-- After MEK rotation on Primary — verify Standby keystore sync
-- Run on PRIMARY:
SELECT
    dest_id,
    db_unique_name,
    tde_keystore_status,    -- OPEN = Standby can decrypt new redo
    status,
    gap_status
FROM   v$archive_dest_status
WHERE  status = 'VALID';

-- Run on STANDBY — confirm same MEK is active
SELECT key_id, activation_time, tag
FROM   v$encryption_keys
WHERE  activation_time = (SELECT MAX(activation_time) FROM v$encryption_keys);

-- For Software Keystore: copy updated wallet to Standby after rotation
-- scp $WALLET_ROOT/tde/ewallet.p12 oracle@standby:$WALLET_ROOT/tde/
-- scp $WALLET_ROOT/tde/cwallet.sso  oracle@standby:$WALLET_ROOT/tde/
-- Then on Standby: ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY "pwd";

Audit Queries — Compliance Reporting

SQL — Compliance Audit Report Queries
-- Complete key rotation history with age calculation
SELECT
    key_id,
    tag                                         compliance_tag,
    creation_time,
    activation_time,
    COALESCE(retired_time, SYSDATE)             retired_or_now,
    ROUND(COALESCE(retired_time,SYSDATE)
          - activation_time)                     days_active,
    CASE WHEN retired_time IS NULL THEN 'ACTIVE'
         ELSE 'RETIRED' END                       key_state,
    -- Flag keys exceeding PCI 365-day limit
    CASE WHEN retired_time IS NULL
          AND SYSDATE - activation_time > 365
         THEN '⚠ OVERDUE' ELSE 'OK' END           pci_compliance
FROM   v$encryption_keys
ORDER BY activation_time DESC;

-- Rotation log for last 12 months (from audit table)
SELECT
    rotation_date,
    rotation_type,
    compliance_tag,
    old_key_id,
    new_key_id,
    rotated_by,
    status
FROM   dba_tde_rotation_log
WHERE  rotation_date >= ADD_MONTHS(SYSDATE,-12)
ORDER BY rotation_date DESC;

Best Practices Summary

#Best PracticeCompliance DriverPriority
1Tag every rotation with USING TAG for audit trailPCI-DSS, SOX, GDPRCritical
2Use WITH BACKUP on every rotation — creates keystore snapshotAll frameworksCritical
3Automate via DBMS_SCHEDULER — eliminate manual rotation riskSOX, ISO 27001High
4Use OKV for enterprise — no plaintext passwords in schedulerAll frameworksHigh
5Rotate MEK at least annually; consider quarterly for PCIPCI-DSS Req 3.6High
6Sync wallet to ALL Standbys immediately after rotationAvailability SLAMedium
7Monitor V$ENCRYPTION_KEYS with alerting for overdue keysAll frameworksMedium
8Separate rotation privilege — use SYSKM, not SYSDBASOX, ISO 27001Medium
🔄 Oracle TDE 🔑 Key Rotation 📋 PCI-DSS 📊 SOX 🔒 GDPR ⚙️ DBMS_SCHEDULER 🛡 Data Guard 🏦 Oracle Key Vault 📝 Audit Trail
AI DBA Hub — Expert Oracle & PostgreSQL Content for Database Administrators
Oracle TDE · Key Rotation · Compliance Automation · Data Guard

Post a Comment: