> ## 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 Annually

### More Info:

Customer-managed KMS keys should be rotated at least once per year (365 days). Annual rotation ensures cryptographic material is refreshed and limits long-term exposure from key compromise

### 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 step‑by‑step console instructions to remediate the **“OCI Encryption KMS Keys Should Be Rotated Annually”** issue for **OCI Encryption Monitoring** (Cloud Guard) and your KMS keys.

        ***

        ## 1. Find the non‑compliant KMS keys (Cloud Guard)

        1. Sign in to the **OCI Console**.
        2. Open the navigation menu → **Security & Identity** → **Cloud Guard**.
        3. In the left pane, click **Problems**.
        4. Use filters:
           * **Detector type**: *OCI Encryption Monitoring*
           * **Problem description / name** contains: `KMS Keys Should Be Rotated Annually`
           * (Optional) Filter by **Compartment** to narrow scope.
        5. For each listed problem, open it and note:
           * **Key OCID** (or name).
           * **Compartment** where the key’s vault resides.
           * **Region**.

        You now know which keys must be rotated.

        ***

        ## 2. Rotate the KMS key in Vault (Console)

        You must create a **new key version** for each flagged key.

        1. From the console, open the navigation menu → **Security & Identity** → **Vault**.
        2. At the top-right, confirm you are in the **same region** where the problem key exists.
        3. In the left pane, click **Vaults** and select the **vault** that contains the problem key.
        4. In the vault, click the **Keys** tab.
        5. Find the **Key** (by name or OCID noted from Cloud Guard) and click it.
        6. On the key details page, click **Rotate Key** (or **Create New Key Version**, depending on UI wording).
        7. Confirm the rotation:
           * This creates a **new key version**; the key OCID stays the same.
           * Existing resources that reference the key **by key OCID** continue to work automatically.
        8. Wait until the key status shows the new version as **Current** (refresh if needed).

        Repeat for all keys reported by Cloud Guard.

        > Note: OCI does not provide a built‑in “automatic schedule” for rotation in the console; rotation is via manual action (as above) or automation (CLI/SDK/scheduled functions).

        ***

        ## 3. Validate and close the Cloud Guard problem

        Cloud Guard periodically re‑evaluates; once it detects a newer key version within the last year, the problem status will change.

        1. Return to **Cloud Guard → Problems**.
        2. Open the problem you remediated.
        3. After evaluation (may take several minutes), the problem should move to **Resolved** automatically.
        4. If using workflows, you can:
           * Add a **comment** describing the rotation performed.
           * Optionally mark it as **Resolved** manually if your org’s process requires that.

        ***

        ## 4. (Optional) Reduce future findings – policy / process

        Since rotation is annual, set up a process so the key doesn’t age beyond one year:

        * Use **Cloud Guard** detector “OCI Encryption KMS Keys Should Be Rotated Annually” as your control and:
          * Ensure it’s enabled in your **Detector Recipe** for OCI Encryption Monitoring.
          * Attach the recipe to all relevant **targets / compartments**.
        * Optionally configure **Notifications**:
          1. Go to **Application Integration → Notifications** → **Topics**.
          2. Create a **topic** (e.g., `kms-rotation-alerts`).
          3. Subscribe email/Slack/HTTPS endpoint.
          4. In **Cloud Guard → Responders** or in your ticketing/automation layer, tie the “key older than 1 year” problem to send alerts to this topic.

        This ensures future keys nearing 1 year will be detected and acted upon via the console‑driven process above.
      </Accordion>

      <Accordion title="Using CLI">
        Below are step‑by‑step instructions to **identify** and **rotate OCI KMS keys older than 1 year** using the **OCI CLI**, suitable for putting into a monitoring/automation workflow.

        ***

        ## 1. Prerequisites

        1. Install and configure OCI CLI:
           ```bash theme={null}
           oci setup config
           ```

        2. Ensure your user has these IAM permissions (or equivalent via group/policy):

           ```text theme={null}
           allow group <group-name> to manage keys in compartment <compartment-ocid>
           allow group <group-name> to use key-family in compartment <compartment-ocid>
           ```

        3. Have the following values ready:
           * `TENANCY_OCID`
           * `COMPARTMENT_OCID` where your keys live
           * `VAULT_OCID` (optional filter if you want per vault)
           * `REGION`

        Set them as environment variables for convenience:

        ```bash theme={null}
        export OCI_REGION="<region-identifier>"          # e.g. eu-frankfurt-1
        export COMPARTMENT_OCID="<your-compartment-ocid>"
        export VAULT_OCID="<optional-vault-ocid>"
        ```

        ***

        ## 2. List All KMS Keys in a Compartment (Optionally Per Vault)

        ```bash theme={null}
        oci kms management key list \
          --compartment-id "$COMPARTMENT_OCID" \
          --vault-id "$VAULT_OCID" \
          --region "$OCI_REGION" \
          --all \
          --output table
        ```

        To get JSON instead (for scripting):

        ```bash theme={null}
        oci kms management key list \
          --compartment-id "$COMPARTMENT_OCID" \
          --vault-id "$VAULT_OCID" \
          --region "$OCI_REGION" \
          --all
        ```

        Each key will have an `id` (Key OCID).

        ***

        ## 3. Find Keys Whose Current Version is Older Than 1 Year

        Each KMS key has versions; rotation = creating a *new version*. We need to:

        1. Get the **current key version**.
        2. Get its `time-created`.
        3. Compare to “now − 365 days”.

        Here is a Bash script that:

        * Iterates over keys in a compartment (optionally per vault),
        * Checks the current version age,
        * Prints keys older than 365 days.

        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        COMPARTMENT_OCID="${COMPARTMENT_OCID:?COMPARTMENT_OCID not set}"
        REGION="${OCI_REGION:?OCI_REGION not set}"
        VAULT_OCID="${VAULT_OCID:-}"

        ONE_YEAR_SECONDS=$((365 * 24 * 60 * 60))
        NOW_EPOCH=$(date -u +%s)

        # Build base list command
        LIST_CMD=(oci kms management key list
          --compartment-id "$COMPARTMENT_OCID"
          --region "$REGION"
          --all
        )

        if [[ -n "$VAULT_OCID" ]]; then
          LIST_CMD+=(--vault-id "$VAULT_OCID")
        fi

        KEYS_JSON="$("${LIST_CMD[@]}")"

        echo "Checking keys in compartment $COMPARTMENT_OCID (region $REGION)..."

        echo "$KEYS_JSON" | jq -r '.data[].id' | while read -r KEY_OCID; do
          # Get key metadata
          KEY_JSON=$(oci kms management key get --key-id "$KEY_OCID" --region "$REGION")
          CURRENT_VERSION_ID=$(echo "$KEY_JSON" | jq -r '.data."current-key-version"')

          if [[ "$CURRENT_VERSION_ID" == "null" || -z "$CURRENT_VERSION_ID" ]]; then
            echo "Key $KEY_OCID has no current version; skipping"
            continue
          fi

          # Get the current key version details
          VERSION_JSON=$(oci kms management key-version get \
            --key-id "$KEY_OCID" \
            --key-version-id "$CURRENT_VERSION_ID" \
            --region "$REGION")

          CREATED_ISO=$(echo "$VERSION_JSON" | jq -r '.data."time-created"')
          CREATED_EPOCH=$(date -d "$CREATED_ISO" +%s)

          AGE_SECONDS=$((NOW_EPOCH - CREATED_EPOCH))

          if (( AGE_SECONDS > ONE_YEAR_SECONDS )); then
            AGE_DAYS=$((AGE_SECONDS / 86400))
            echo "Key $KEY_OCID current version $CURRENT_VERSION_ID is $AGE_DAYS days old -> needs rotation"
          else
            AGE_DAYS=$((AGE_SECONDS / 86400))
            echo "Key $KEY_OCID current version $CURRENT_VERSION_ID is $AGE_DAYS days old -> OK"
          fi
        done
        ```

        Use this for **monitoring** (e.g., run via cron, OCI DevOps build, or scheduled job) and alert when keys exceed 365 days.

        ***

        ## 4. Rotate a Specific KMS Key via OCI CLI

        Rotation = `rotate-key` API/CLI, which creates a new key version and makes it current.

        ```bash theme={null}
        oci kms management key rotate-key \
          --key-id "<key-ocid>" \
          --region "$OCI_REGION"
        ```

        Example:

        ```bash theme={null}
        KEY_OCID="ocid1.key.oc1..exampleuniqueID"
        oci kms management key rotate-key \
          --key-id "$KEY_OCID" \
          --region "$OCI_REGION"
        ```

        ***

        ## 5. Automate Rotation for Keys Older Than 1 Year

        Here is a script that **rotates all KMS keys** in a compartment (optionally per vault) whose current version is older than 365 days:

        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        COMPARTMENT_OCID="${COMPARTMENT_OCID:?COMPARTMENT_OCID not set}"
        REGION="${OCI_REGION:?OCI_REGION not set}"
        VAULT_OCID="${VAULT_OCID:-}"

        ONE_YEAR_SECONDS=$((365 * 24 * 60 * 60))
        NOW_EPOCH=$(date -u +%s)

        LIST_CMD=(oci kms management key list
          --compartment-id "$COMPARTMENT_OCID"
          --region "$REGION"
          --all
        )

        if [[ -n "$VAULT_OCID" ]]; then
          LIST_CMD+=(--vault-id "$VAULT_OCID")
        fi

        KEYS_JSON="$("${LIST_CMD[@]}")"

        echo "Rotating KMS keys older than 1 year in compartment $COMPARTMENT_OCID (region $REGION)..."

        echo "$KEYS_JSON" | jq -r '.data[].id' | while read -r KEY_OCID; do
          KEY_JSON=$(oci kms management key get --key-id "$KEY_OCID" --region "$REGION")
          CURRENT_VERSION_ID=$(echo "$KEY_JSON" | jq -r '.data."current-key-version"')

          if [[ "$CURRENT_VERSION_ID" == "null" || -z "$CURRENT_VERSION_ID" ]]; then
            echo "Key $KEY_OCID has no current version; skipping"
            continue
          fi

          VERSION_JSON=$(oci kms management key-version get \
            --key-id "$KEY_OCID" \
            --key-version-id "$CURRENT_VERSION_ID" \
            --region "$REGION")

          CREATED_ISO=$(echo "$VERSION_JSON" | jq -r '.data."time-created"')
          CREATED_EPOCH=$(date -d "$CREATED_ISO" +%s)

          AGE_SECONDS=$((NOW_EPOCH - CREATED_EPOCH))

          if (( AGE_SECONDS > ONE_YEAR_SECONDS )); then
            AGE_DAYS=$((AGE_SECONDS / 86400))
            echo "Rotating key $KEY_OCID (current version $CURRENT_VERSION_ID is $AGE_DAYS days old)..."

            oci kms management key rotate-key \
              --key-id "$KEY_OCID" \
              --region "$REGION"

            echo "Rotation triggered for key $KEY_OCID"
          else
            AGE_DAYS=$((AGE_SECONDS / 86400))
            echo "Key $KEY_OCID is $AGE_DAYS days old -> no rotation needed"
          fi
        done
        ```

        You can run this script monthly/weekly as part of your **OCI Encryption Monitoring**/compliance pipeline.

        ***

        ## 6. Optional: Wire into OCI Monitoring/Events

        To fully “monitor” via OCI:

        1. Use an **OCI Logging** or **Monitoring**–backed job (e.g., OCI DevOps Build, or a compute instance cron) that runs the **check script**.
        2. When the script finds aged keys, write results to:
           * `stdout` + agent -> OCI Logging, and
           * A **custom metric** using `oci monitoring metric-data post` for “kms.key.rotation\_needed = 1”.
        3. Create an **Alarm** on that metric to notify when rotation is needed.
        4. Optionally trigger an **OCI Function** from an **Event** or Alarm that calls the **rotation script** logic (via Python SDK or CLI containers).

        ***

        If you share whether you prefer a pure CLI solution or CLI + Python SDK, I can give you a ready‑to‑run monitoring + rotation job for your environment.
      </Accordion>

      <Accordion title="Using Python">
        Below is how to remediate “OCI Encryption KMS Keys Should Be Rotated Annually” using Python, by:

        1. Detecting KMS keys older than 365 days (or whose last key version is older than 365 days).
        2. Automatically rotating them by creating a new key version.
        3. Optionally, enforcing a rotation policy interval.

        ***

        ## 1. Prerequisites

        1. **Install OCI Python SDK**
           ```bash theme={null}
           pip install oci
           ```

        2. **Configure OCI CLI/SDK credentials** (user, tenancy, region, key pair, etc.)\
           Create/verify `~/.oci/config` with at least:
           ```ini theme={null}
           [DEFAULT]
           user=ocid1.user.oc1..aaaa...
           fingerprint=aa:bb:cc:...
           key_file=/path/to/oci_api_key.pem
           tenancy=ocid1.tenancy.oc1..aaaa...
           region=us-ashburn-1
           ```

        3. The user/principal running this must have IAM permissions similar to:
           ```text theme={null}
           Allow group <group-name> to manage keys in compartment <compartment-ocid>
           Allow group <group-name> to manage vaults in compartment <compartment-ocid>
           ```

        ***

        ## 2. Strategy

        * For each key in your vault(s) / compartment(s):
          * Check the most recent key version’s `time_created`.
          * If older than 365 days, call `create_key_version` (this rotates the key).
        * Optionally, set a rotation policy using `update_key` `key_shape` and `key_lifecycle_details` or the dedicated rotation policy (if available in your region/tenancy; for older APIs, you do it via monitoring + `create_key_version`).

        ***

        ## 3. Python Script: Monitor & Rotate Keys Annually

        Below is a basic example:

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

        # ----- CONFIG -----
        PROFILE = "DEFAULT"
        COMPARTMENT_OCID = "ocid1.compartment.oc1..xxxx"  # change to your compartment
        ROTATION_THRESHOLD_DAYS = 365
        # -------------------

        def main():
            config = oci.config.from_file("~/.oci/config", PROFILE)
            kms_mgmt_client = oci.key_management.KmsManagementClient(config)

            # If you have multiple vaults/keys, you may want to list them via KMS management / vault management APIs.
            # For simplicity, assume you already know the vault and key OCIDs or you list keys in a vault.

            # EXAMPLE: list keys via KmsManagementClient (requires a specific endpoint)
            # Get management endpoint for your vault first via KmsVaultClient or hard-code it.
            # Usually looks like: "https://<vault-id>-management.kms.<region>.oraclecloud.com"

            # If you know the vault / management endpoint:
            kms_mgmt_client.base_client.set_region(config["region"])
            # OR set endpoint directly:
            # kms_mgmt_client.base_client.set_endpoint("https://<vault-id>-management.kms.<region>.oraclecloud.com")

            # List keys in the vault (example; you must know vaultId)
            vault_id = "ocid1.vault.oc1..xxxx"  # change to your vault OCID
            response = kms_mgmt_client.list_keys(
                compartment_id=COMPARTMENT_OCID,
                limit=100  # adjust as needed
            )
            keys = response.data

            now = datetime.now(timezone.utc)
            threshold = now - timedelta(days=ROTATION_THRESHOLD_DAYS)

            for key in keys:
                key_id = key.id

                # Get key versions
                versions = kms_mgmt_client.list_key_versions(key_id=key_id, limit=100).data
                if not versions:
                    continue

                # Find latest version by time_created
                latest_version = max(versions, key=lambda v: v.time_created)
                latest_created = latest_version.time_created

                if latest_created < threshold:
                    print(f"Key {key_id} needs rotation. Latest version from {latest_created}")

                    # Rotate key by creating a new version
                    rotate_resp = kms_mgmt_client.create_key_version(
                        key_id=key_id,
                        create_key_version_details=oci.key_management.models.CreateKeyVersionDetails()
                    )
                    print(f"Rotated key {key_id}. New version OCID: {rotate_resp.data.id}")
                else:
                    print(f"Key {key_id} is within rotation window. Latest version: {latest_created}")

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

        **Notes:**

        * You must set the **KMS management endpoint** correctly. Often you:
          1. Use `oci.key_management.KmsVaultClient` to get the management endpoint for a given vault.
          2. Then initialize `KmsManagementClient` with that endpoint.

        Example to get endpoint:

        ```python theme={null}
        vault_client = oci.key_management.KmsVaultClient(config)
        vault = vault_client.get_vault(vault_id).data
        kms_mgmt_client = oci.key_management.KmsManagementClient(config)
        kms_mgmt_client.base_client.set_endpoint(vault.management_endpoint)
        ```

        ***

        ## 4. Automate as “Monitoring”

        * Run this Python script on a schedule:
          * OCI Functions + OCI Events/Scheduled Jobs.
          * Or an external scheduler like cron / CI pipeline.
        * Log or send alerts (e.g., to OCI Logging, email, Slack) whenever a key is rotated or close to threshold.

        ***

        ## 5. (Optional) Enforce a Rotation Policy

        If your tenancy/region supports **key rotation policies**, you can set a policy to 365 days so you don’t have to run your own rotation logic. Pseudocode:

        ```python theme={null}
        update_details = oci.key_management.models.UpdateKeyDetails(
            # check exact field names in your SDK version, e.g.:
            # key_lifecycle_details=oci.key_management.models.KeyLifecycleDetails(
            #     time_of_next_rotation=some_datetime,
            #     duration="P365D"
            # )
        )

        kms_mgmt_client.update_key(key_id=key_id, update_key_details=update_details)
        ```

        Check the specific fields for rotation policy in the SDK version you’re using (`help(oci.key_management.models.UpdateKeyDetails)`).

        ***

        If you tell me how you’re currently deploying/monitoring (OCI Functions, VM, external runner), I can tailor the script and IAM policy exactly for that setup.
      </Accordion>

      <Accordion title="Using Terraform">
        Terraform cannot configure rotation for `oci_kms_key` because OCI KMS key rotation is an operational action, not a persisted property on the key, and the `oci` provider exposes no argument for a rotation interval or schedule.

        To meet the “rotate annually” requirement you must rotate keys outside Terraform (e.g., via Console, OCI CLI, or an automated script/Function scheduled by Events/Alarms), and keep Terraform managing only the key’s lifecycle (creation, tags, etc.).

        Console path (as of now):\
        KMS → Vaults → select VAULT → Keys → select KEY → Rotate → confirm, or configure any available automatic rotation option there.

        `terraform plan` will not show any change related to rotation, because it is not a Terraform-managed setting.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
