> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# OCI Encryption KMS Keys Should Be Rotated At Least Once

### More Info:

KMS keys should have been rotated at least once (more than one key version). Keys that have never been rotated may use outdated cryptographic parameters.

### Risk Level

High

### Address

Compliance, Security

### Compliance Standards

* APRA CPS 234 (Australia)
* AWS Well Architected Framework
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS AWS
* CIS Critical Security Controls v8
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* Cloudanix Best Practice
* DPDPA
* Digital Operational Resilience Act (EU)
* GDPR
* HIPAA
* HITRUST CSF
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST
* NIST CSF
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* PCI
* Reserve Bank of India (RBI) Cyber Security Framework
* Reserve Bank of India (RBI) Master Direction – Information Technology Framework
* SOC2
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are the concise steps to remediate “OCI Encryption KMS Keys Should Be Rotated At Least Once” using the OCI Console.

        ***

        ## 1. Identify the Non‑Rotated Keys

        1. Sign in to the **OCI Console**.
        2. Go to **Identity & Security** → **Vault**.
        3. Choose the **Compartment** you monitor (top-left compartment selector).
        4. Open each **Vault** and then select **Keys**.
        5. Look for **Keys** with:
           * `Key Status`: *Enabled*
           * **No rotation history** (never rotated) or last rotation is older than your required policy.

        ***

        ## 2. Manually Rotate a Key

        For each key that needs rotation:

        1. In the vault, go to **Keys**.
        2. Click the **Key Name** you want to rotate.
        3. On the key details page, click **Rotate Key** (or **Create New Key Version**).
        4. Confirm the rotation:
           * This creates a new key version; the key’s OCID stays the same.
           * Existing resources using this key will automatically start using the new version (no change needed in resource config).
        5. Verify rotation:
           * On the key details page, you should now see multiple **Key Versions** with the latest marked as **Primary**.

        ***

        ## 3. Configure Automatic Key Rotation (Recommended)

        To avoid future findings for “not rotated at least once”:

        1. In the same **Key** details page, look for **Key Rotation** or **Automatic Rotation** section.
        2. Click **Edit Rotation Policy** or **Enable Rotation**.
        3. Set:
           * **Rotation Interval** (e.g., every 90 days or per your policy).
        4. Save.

        This ensures:

        * The key is rotated at least once (clearing current misconfiguration).
        * Future rotations are automated, preventing recurring findings.

        ***

        ## 4. Confirm Remediation in Your Monitoring Tool

        If you’re using **OCI Cloud Guard / Security Zones / custom monitoring**:

        1. Allow some time for the next evaluation cycle.
        2. Re-run the check (or wait for Cloud Guard detector to rescan).
        3. Verify the finding for “OCI Encryption KMS Keys Should Be Rotated At Least Once” is no longer reported for keys you rotated.

        ***

        If you share which exact monitoring/control (Cloud Guard detector recipe, Security Zone policy, or a third-party scanner), I can tailor the rotation interval and any additional verification steps to match that control’s logic.
      </Accordion>

      <Accordion title="Using CLI">
        Below are CLI-focused steps to rotate OCI KMS keys and (optionally) enforce a rotation schedule so they’re not flagged as “never rotated”.

        Assumptions:

        * You already have `oci` CLI configured with proper tenancy/region.
        * You know the `vault-id` and `key-id` for the keys in question.

        ***

        ## 1. Identify KMS keys that have never been rotated

        1. List keys in a vault:

        ```bash theme={null}
        oci kms management key list \
          --compartment-id <compartment_ocid> \
          --vault-id <vault_ocid> \
          --all
        ```

        2. For each key, list key versions:

        ```bash theme={null}
        oci kms management key-version list \
          --key-id <key_ocid> \
          --all
        ```

        * If only a single version exists (the original), the key has never been rotated.

        ***

        ## 2. Manually rotate a key (create a new key version)

        Manual rotation = creating a new key version.

        ```bash theme={null}
        oci kms management key-version create \
          --key-id <key_ocid>
        ```

        This immediately creates a new key version and makes it the primary version. Any subsequent cryptographic operations will use this new version, while old versions remain available for decrypting existing data (unless explicitly disabled/destroyed).

        You can verify:

        ```bash theme={null}
        oci kms management key-version list \
          --key-id <key_ocid> \
          --all
        ```

        You should now see multiple versions.

        ***

        ## 3. Configure automatic key rotation (so the finding does not reoccur)

        To ensure periodic rotation, you can set a rotation interval (policy) on the key.

        ### 3.1 Prepare a key policy JSON with rotation settings

        Create a file `key-policy.json`:

        ```json theme={null}
        {
          "keyPolicy": {
            "isUseKeyInVaultEnabled": true,
            "isDerivedKeysEnabled": true,
            "rotationInterval": "P90D"
          }
        }
        ```

        * `rotationInterval` uses ISO 8601 duration format:
          * `P90D` = every 90 days
          * Example: `P180D` = every 180 days

        Adjust flags (`isUseKeyInVaultEnabled`, `isDerivedKeysEnabled`) if needed for your environment.

        ### 3.2 Apply the key policy via OCI CLI

        ```bash theme={null}
        oci kms management key update \
          --key-id <key_ocid> \
          --from-json file://key-policy.json
        ```

        Confirm:

        ```bash theme={null}
        oci kms management key get \
          --key-id <key_ocid>
        ```

        Look for the `keyPolicy` and `rotationInterval` details in the output.

        ***

        ## 4. Scriptable remediation (optional)

        To remediate all “never rotated” keys in a compartment:

        High-level bash pseudo-script:

        ```bash theme={null}
        COMPARTMENT_ID="<compartment_ocid>"
        VAULT_ID="<vault_ocid>"

        # List all keys in a vault
        KEYS=$(oci kms management key list \
          --compartment-id "$COMPARTMENT_ID" \
          --vault-id "$VAULT_ID" \
          --query "data[].id" \
          --raw-output)

        for KEY_ID in $KEYS; do
          VERSION_COUNT=$(oci kms management key-version list \
            --key-id "$KEY_ID" \
            --query "length(data)" \
            --raw-output)

          if [ "$VERSION_COUNT" -eq 1 ]; then
            echo "Rotating key: $KEY_ID"
            oci kms management key-version create --key-id "$KEY_ID"
            # Optionally enforce rotation policy
            oci kms management key update \
              --key-id "$KEY_ID" \
              --from-json file://key-policy.json
          fi
        done
        ```

        ***

        ## 5. Tie into “OCI Encryption Monitoring”

        To ensure any future non-rotated or long-unrotated keys are remediated:

        * Use Oracle Cloud Guard / Security Zones or your own governance scripts to:
          * Periodically run a CLI/script similar to section 4 to:
            * Detect keys with a single version or last version older than your threshold.
            * Rotate them and/or enforce `rotationInterval`.
        * Optionally, configure an **Events** rule (e.g., on key creation) that triggers a **Function** which:
          * Immediately sets the `rotationInterval`.
          * Optionally performs an initial rotation.

        ***

        In practice, for each flagged key:

        1. `oci kms management key-version create --key-id <key_ocid>`
        2. `oci kms management key update --key-id <key_ocid> --from-json file://key-policy.json` (with an appropriate `rotationInterval`).
      </Accordion>

      <Accordion title="Using Python">
        Below is how to remediate “OCI Encryption KMS Keys Should Be Rotated At Least Once” with **Python-based monitoring and enforcement** using the OCI Python SDK.

        ***

        ## 1. Prerequisites

        1. Install SDK:

        ```bash theme={null}
        pip install oci
        ```

        2. Configure OCI credentials (one of):

        * `~/.oci/config` with a profile (e.g. `DEFAULT`)
        * Or instance principal / resource principal (for OCI native execution)

        3. Ensure the calling principal has these permissions in the compartment(s) and vault(s) you care about:

        * `manage keys`
        * `read vaults`

        Example policy:

        ```text theme={null}
        Allow group kms-admins to manage keys in compartment <your-compartment-name>
        Allow group kms-admins to read vaults in compartment <your-compartment-name>
        ```

        ***

        ## 2. What you need to check

        For each key:

        * Has at least one **new key version** been created (i.e., rotated) since creation?
        * Is **automatic rotation** enabled with a reasonable interval (e.g., 90 days)?

        Key facts (OCI KMS):

        * Each rotation = **new key version** (`create_key_version`).
        * Automatic rotation is controlled via:
          * `is_auto_key_rotation_enabled`
          * `rotation_interval_in_days` (min 1 day, typical 30–365)

        ***

        ## 3. Python script: monitor and remediate rotation

        This example:

        1. Lists all vaults and keys in a compartment.
        2. For each key, checks:
           * Whether it has more than one version (i.e., rotated at least once).
           * Whether auto-rotation is enabled with an acceptable interval.
        3. Optionally:
           * Enables auto-rotation if not enabled.
           * Immediately rotates keys that have never been rotated.

        > Adjust: compartment OCID, rotation policy (e.g., 90 days), and `DRY_RUN` flag.

        ```python theme={null}
        import oci
        from datetime import datetime, timezone

        # ------------------- CONFIG -------------------
        CONFIG_PROFILE = "DEFAULT"
        COMPARTMENT_OCID = "<your_compartment_ocid>"
        DESIRED_ROTATION_INTERVAL_DAYS = 90  # your policy
        DRY_RUN = False  # set to True to only report, False to remediate
        # ----------------------------------------------

        config = oci.config.from_file("~/.oci/config", CONFIG_PROFILE)

        vault_client = oci.key_management.KmsManagementClient
        kms_vault_client = oci.key_management.KmsVaultClient(config=config)
        identity_client = oci.identity.IdentityClient(config=config)


        def get_vaults_in_compartment(compartment_id):
            vaults = oci.pagination.list_call_get_all_results(
                kms_vault_client.list_vaults,
                compartment_id=compartment_id
            ).data
            return [v for v in vaults if v.lifecycle_state == "ACTIVE"]


        def get_kms_management_client_for_vault(vault):
            crypto_endpoint = vault.management_endpoint
            # Use the same config but override service endpoint
            return vault_client(config=config, service_endpoint=crypto_endpoint)


        def list_keys_in_vault(kms_mgmt_client, compartment_id):
            keys = oci.pagination.list_call_get_all_results(
                kms_mgmt_client.list_keys,
                compartment_id=compartment_id
            ).data
            return [k for k in keys if k.lifecycle_state == "ENABLED"]


        def list_key_versions(kms_mgmt_client, key_id):
            versions = oci.pagination.list_call_get_all_results(
                kms_mgmt_client.list_key_versions,
                key_id=key_id
            ).data
            # Only enabled/primary are typically relevant
            return [v for v in versions if v.lifecycle_state in ("ENABLED", "PRIMARY")]


        def ensure_auto_rotation(kms_mgmt_client, key):
            key_id = key.id
            needs_update = False

            is_auto = key.is_auto_key_rotation_enabled
            interval = key.rotation_interval_in_days

            if not is_auto:
                needs_update = True
                print(f"[AUTO-ROTATION] Key {key.display_name} ({key_id}) has auto-rotation DISABLED")
            elif interval is None or interval > DESIRED_ROTATION_INTERVAL_DAYS:
                needs_update = True
                print(f"[AUTO-ROTATION] Key {key.display_name} ({key_id}) interval is {interval}, "
                      f"needs <= {DESIRED_ROTATION_INTERVAL_DAYS} days")

            if needs_update:
                if DRY_RUN:
                    print(f"[DRY_RUN] Would enable/adjust auto-rotation for key {key.display_name}")
                else:
                    update_details = oci.key_management.models.UpdateKeyDetails(
                        is_auto_key_rotation_enabled=True,
                        rotation_interval_in_days=DESIRED_ROTATION_INTERVAL_DAYS
                    )
                    kms_mgmt_client.update_key(key_id, update_details)
                    print(f"[REMEDIATED] Auto-rotation enabled/set to {DESIRED_ROTATION_INTERVAL_DAYS} days for key {key.display_name}")
            else:
                print(f"[OK] Auto-rotation already enabled and compliant for key {key.display_name}")


        def rotate_if_never_rotated(kms_mgmt_client, key, versions):
            key_id = key.id
            if len(versions) <= 1:
                # One version only (the original) => never rotated
                print(f"[ROTATION] Key {key.display_name} ({key_id}) has NEVER been rotated (only 1 version).")
                if DRY_RUN:
                    print(f"[DRY_RUN] Would create a new key version (rotate) for key {key.display_name}")
                else:
                    kms_mgmt_client.create_key_version(
                        key_id=key_id,
                        create_key_version_details=oci.key_management.models.CreateKeyVersionDetails()
                    )
                    print(f"[REMEDIATED] New key version created (manual rotation) for key {key.display_name}")
            else:
                print(f"[OK] Key {key.display_name} has {len(versions)} versions (rotated at least once).")


        def main():
            print(f"Checking KMS key rotation in compartment: {COMPARTMENT_OCID}")
            vaults = get_vaults_in_compartment(COMPARTMENT_OCID)
            if not vaults:
                print("No active vaults found.")
                return

            for vault in vaults:
                print(f"\nVault: {vault.display_name} ({vault.id})")
                kms_mgmt_client = get_kms_management_client_for_vault(vault)
                keys = list_keys_in_vault(kms_mgmt_client, COMPARTMENT_OCID)

                if not keys:
                    print("  No enabled keys in this vault.")
                    continue

                for key in keys:
                    print(f"\n  Key: {key.display_name} ({key.id})")
                    # Refresh key to get latest metadata
                    key = kms_mgmt_client.get_key(key.id).data

                    # 1. Ensure at least one rotation has happened
                    versions = list_key_versions(kms_mgmt_client, key.id)
                    rotate_if_never_rotated(kms_mgmt_client, key, versions)

                    # 2. Ensure auto-rotation is configured properly
                    ensure_auto_rotation(kms_mgmt_client, key)


        if __name__ == "__main__":
            main()
        ```

        ***

        ## 4. How this addresses the misconfiguration

        * **Monitoring**: Script reports keys that:
          * Have never been rotated (only 1 key version).
          * Do not have compliant auto-rotation settings.
        * **Remediation (if `DRY_RUN = False`)**:
          * Creates a new key version for never-rotated keys.
          * Enables auto-rotation and sets `rotation_interval_in_days` to your policy.

        ***

        ## 5. Operationalizing

        * Run this script on a schedule (e.g., OCI Functions, OCI DevOps, or cron on a compute instance).
        * Send output to:
          * OCI Logging / Object Storage / Email or Slack via webhooks for alerts.
        * Optionally:
          * Restrict to “monitor only” in production (keep `DRY_RUN=True`) and have a change process for enabling actual rotation.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        # KMS vault this key belongs to (replace placeholders with your values)
        resource "oci_kms_vault" "ENCRYPTION_VAULT" {
          compartment_id = "OCID_OF_COMPARTMENT"
          display_name   = "ENCRYPTION_VAULT_NAME"
          vault_type     = "DEFAULT" # or "VIRTUAL_PRIVATE"
        }

        # Existing KMS key which has never been rotated
        resource "oci_kms_key" "ENCRYPTION_KEY" {
          management_endpoint = oci_kms_vault.ENCRYPTION_VAULT.management_endpoint
          compartment_id      = "OCID_OF_COMPARTMENT"
          display_name        = "ENCRYPTION_KEY_NAME"

          key_shape {
            algorithm = "AES"
            length    = 32
          }

          protection_mode = "HSM" # or "SOFTWARE"
        }

        # Rotation: create a new key version for the existing key (at least one rotation)
        resource "oci_kms_key_version" "ENCRYPTION_KEY_ROTATION_1" {
          management_endpoint = oci_kms_vault.ENCRYPTION_VAULT.management_endpoint
          key_id              = oci_kms_key.ENCRYPTION_KEY.id
          # Optionally add lifecycle to prevent accidental destroy of this version
          lifecycle {
            prevent_destroy = true
          }
        }
        ```

        This adds a new key version for the existing OCI KMS key, satisfying the requirement that the key has been rotated at least once; it does not replace the key itself, so no outage is introduced.

        For verification, `terraform plan` should show a single `+ create` action for `oci_kms_key_version.ENCRYPTION_KEY_ROTATION_1` and no changes to `oci_kms_key.ENCRYPTION_KEY`.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
