> ## 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 IAM Customer Secret Keys Should Be Rotated Every 90 Days

### More Info:

Customer secret keys should be rotated every 90 days. Regular rotation reduces the risk window if keys are leaked through code repositories, logs, or configuration files

### Risk Level

High

### Address

Compliance, Security

### Compliance Standards

* APRA CPS 234 (Australia)
* 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)
* Essential 8
* 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 SP 800-171
* NYDFS 23 NYCRR 500
* Reserve Bank of India (RBI) Master Direction – Information Technology Framework
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are two parts:

        1. **How to actually rotate a customer secret key (per user) via the console**
        2. **How to monitor/enforce 90‑day rotation using OCI Cloud Guard (OCI IAM Monitoring)**

        ***

        ## 1. Manually rotate OCI IAM Customer Secret Keys (per user)

        You must create a new secret key, update applications to use it, then delete the old one.

        1. Sign in to the **OCI Console**.
        2. Go to: **Identity & Security** → **Identity** → **Users**.
        3. Click the **user** whose customer secret key you want to rotate.
        4. In the user details page, go to the **Customer Secret Keys** tab.
        5. Click **Create Customer Secret Key**.
           * Optionally give it a description (e.g., “app‑xyz‑2024‑07‑rotation”).
           * Click **Create** and **copy** the Access Key / Secret Key values (you won’t be able to see the secret again).
        6. Update all apps/integrations that were using the old customer secret key so they now use the **new** key.
        7. After confirming everything works with the new key, go back to the same **Customer Secret Keys** tab.
        8. Select the **old** key (older than 90 days) and click **Delete**.

        Repeat for all users/integrations that have customer secret keys older than 90 days.

        ***

        ## 2. Monitor/enforce “rotate every 90 days” using Cloud Guard (IAM Monitoring)

        To continuously detect keys older than 90 days and optionally auto-remediate:

        ### 2.1 Enable Cloud Guard

        1. In the console, go to **Identity & Security** → **Cloud Guard**.
        2. If not already enabled, click **Enable Cloud Guard**.
        3. Choose the **compartment** and **region** you want Cloud Guard to monitor, and confirm.

        ### 2.2 Configure the detector recipe for IAM customer secret keys

        1. In **Cloud Guard**, go to **Detector Recipes**.

        2. Open the **OCI-managed detector recipe** you’re using (e.g., *OCI Activity Detector Recipe* or *OCI Configuration Detector Recipe*, naming varies by tenancy/region).

        3. Create a **clone** of the OCI-managed recipe (you can’t edit the managed one directly):
           * Click **Create Custom Detector Recipe** (or **Clone**).
           * Give it a name (e.g., `Custom-IAM-Key-Rotation-Recipe`).

        4. In your **custom detector recipe**, find the rule for customer secret key age. Typical rule name is similar to:
           * **“IAM Customer Secret Keys should be rotated every 90 days”**\
             or
           * **“Customer secret key age exceeds threshold”**.

        5. Edit that rule:
           * Ensure the rule is **Enabled**.
           * Set the age **threshold** to **90 days** (or keep the default if it is already 90).
           * Set the **Risk Level** (e.g., High or Medium) as per your policy.
           * Save changes.

        6. Attach this **custom detector recipe** to your **Cloud Guard target**:
           * Go to **Targets** in Cloud Guard.
           * Edit your existing target (or create a new one).
           * Under **Detector Recipes**, replace the default OCI-managed detector recipe with your **custom** clone that has the 90‑day rule enabled.
           * Save.

        Cloud Guard will now raise **problems** whenever a customer secret key exceeds 90 days.

        ***

        ### 2.3 (Optional) Auto-remediate (delete old keys) via responder recipe

        If you want Cloud Guard to take automatic action (e.g., delete old keys):

        1. In **Cloud Guard**, go to **Responder Recipes**.
        2. Clone the OCI-managed responder recipe into a **custom responder recipe**.
        3. Find a responder rule appropriate for IAM key issues (e.g., “Delete customer secret key” or similar name).
        4. Enable that responder rule and (if needed) associate it with the IAM customer secret key age detector rule:
           * Set its **Action** to something like **Delete Resource** or **Disable Key** (exact wording depends on current OCI capabilities).
        5. Attach this **custom responder recipe** to the same **Cloud Guard target** where your custom detector recipe is attached.
        6. Set the responder mode (per target) to **Auto** if you want automatic remediation; otherwise keep **User-Driven** for manual approving of actions from the Problems page.

        ***

        ### 2.4 Review and act on findings

        1. Go to **Cloud Guard** → **Problems**.
        2. Filter for the rule name (e.g., “IAM Customer Secret Keys should be rotated every 90 days”).
        3. For each problem:
           * If you use **user-driven** mode: click the problem → choose the recommended **Responder** action → run it.
           * If you use **auto** mode and have a delete responder, Cloud Guard will delete or remediate according to your responder rule.

        ***

        This setup gives you:

        * Manual rotation of keys via the **Users → Customer Secret Keys** tab.
        * Continuous **monitoring** (and optionally automated deletion/remediation) via **Cloud Guard** to enforce the 90‑day rotation requirement.
      </Accordion>

      <Accordion title="Using CLI">
        Below is a practical way to **monitor and rotate OCI IAM Customer Secret Keys every 90 days** using the **OCI CLI**.

        ***

        ## 1. Prerequisites

        1. Install and configure OCI CLI (with a user that has IAM permissions):
           ```bash theme={null}
           oci setup config
           ```
        2. Ensure the CLI user has policy allowing:
           * `inspect users`
           * `manage customer-secret-keys` on users in the tenancy

        Example policy:

        ```text theme={null}
        Allow group SecOps to inspect users in tenancy
        Allow group SecOps to manage customer-secret-keys in tenancy
        ```

        ***

        ## 2. Find Customer Secret Keys and Their Age

        ### 2.1. Get the User OCID

        If you know the username:

        ```bash theme={null}
        oci iam user list --all --query "data[?\"name\"=='<USERNAME>'].id | [0]" --raw-output
        ```

        Or for the current CLI user:

        ```bash theme={null}
        oci iam user list --all --query "data[?\"name\"=='$(oci iam user list --all --query 'data[?\"id\"==`'$(oci iam user whoami --query 'data.id' --raw-output )'`].name | [0]' --raw-output)'].id | [0]" --raw-output
        ```

        Simpler if you know your OCID:

        ```bash theme={null}
        USER_OCID="<USER_OCID>"
        ```

        ### 2.2. List the Customer Secret Keys

        ```bash theme={null}
        oci iam customer-secret-key list \
          --user-id "$USER_OCID" \
          --all \
          --query 'data[].{"Id": "id","DisplayName": "display-name","TimeCreated": "time-created","LifecycleState": "lifecycle-state"}' \
          --output table
        ```

        ***

        ## 3. Identify Keys Older Than 90 Days (Monitoring Logic)

        Example Bash script to **detect keys older than 90 days**:

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

        USER_OCID="<USER_OCID>"
        MAX_AGE_DAYS=90

        now_epoch=$(date +%s)

        # Get keys as JSON
        keys_json=$(oci iam customer-secret-key list --user-id "$USER_OCID" --all --output json)

        echo "$keys_json" | jq -c '.data[]' | while read -r key; do
          id=$(echo "$key" | jq -r '.id')
          name=$(echo "$key" | jq -r '."display-name"')
          created=$(echo "$key" | jq -r '."time-created"')
          state=$(echo "$key" | jq -r '."lifecycle-state"')

          # Skip deleted keys
          if [[ "$state" != "ACTIVE" ]]; then
            continue
          fi

          created_epoch=$(date -d "$created" +%s)
          age_days=$(( (now_epoch - created_epoch) / 86400 ))

          if (( age_days > MAX_AGE_DAYS )); then
            echo "OLD KEY: $id ($name) is $age_days days old (created: $created)"
          fi
        done
        ```

        Run this via cron (e.g., daily) and pipe output to email or a log monitoring system.

        ***

        ## 4. Rotate (Create New + Delete Old) Keys via CLI

        **Important:**\
        Before deleting an old key, update any applications using it to the **new key**.

        ### 4.1. Create a New Customer Secret Key

        ```bash theme={null}
        NEW_KEY=$(oci iam customer-secret-key create \
          --user-id "$USER_OCID" \
          --display-name "rotated-$(date +%Y%m%d)" \
          --query 'data' \
          --output json)

        ACCESS_KEY_ID=$(echo "$NEW_KEY" | jq -r '.id')
        SECRET_ACCESS_KEY=$(echo "$NEW_KEY" | jq -r '.secret-key')

        echo "New Access Key ID: $ACCESS_KEY_ID"
        echo "New Secret Access Key: $SECRET_ACCESS_KEY"
        ```

        Update your apps/services with `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY`.

        ### 4.2. Delete Old Keys (Older Than 90 Days)

        Extend the previous script to **delete** old keys:

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

        USER_OCID="<USER_OCID>"
        MAX_AGE_DAYS=90
        DRY_RUN=true    # set to false to actually delete

        now_epoch=$(date +%s)

        keys_json=$(oci iam customer-secret-key list --user-id "$USER_OCID" --all --output json)

        echo "$keys_json" | jq -c '.data[]' | while read -r key; do
          id=$(echo "$key" | jq -r '.id')
          name=$(echo "$key" | jq -r '."display-name"')
          created=$(echo "$key" | jq -r '."time-created"')
          state=$(echo "$key" | jq -r '."lifecycle-state"')

          if [[ "$state" != "ACTIVE" ]]; then
            continue
          fi

          created_epoch=$(date -d "$created" +%s)
          age_days=$(( (now_epoch - created_epoch) / 86400 ))

          if (( age_days > MAX_AGE_DAYS )); then
            echo "[INFO] Key $id ($name) is $age_days days old, marking for deletion."
            if [[ "$DRY_RUN" = false ]]; then
              oci iam customer-secret-key delete --user-id "$USER_OCID" --customer-secret-key-id "$id" --force
              echo "[DELETED] $id"
            else
              echo "[DRY-RUN] Would delete $id"
            fi
          fi
        done
        ```

        Set `DRY_RUN=false` once you have validated behavior.

        ***

        ## 5. Automate Monitoring (and Optional Auto-Rotation)

        1. Save script(s) on a secure host (e.g., bastion, management server).
        2. Configure cron (example: run daily at 01:00):

        ```bash theme={null}
        crontab -e

        0 1 * * * /usr/local/bin/oci_rotate_customer_keys.sh >> /var/log/oci_key_rotation.log 2>&1
        ```

        3. Integrate log output with your monitoring/alerting (e.g., send mail if “OLD KEY” lines appear).

        ***

        If you want, I can provide a single combined script that:

        * checks for keys >90 days,
        * creates a new key if needed, and
        * deletes just the oldest key after a grace period.
      </Accordion>

      <Accordion title="Using Python">
        Below is a practical way to both **detect** and **remediate** “OCI IAM Customer Secret Keys older than 90 days” using Python and the OCI SDK.

        ***

        ## 1. Prerequisites

        1. Install OCI Python SDK:
           ```bash theme={null}
           pip install oci
           ```
        2. Configure your OCI CLI/SDK config (`~/.oci/config`) with a profile that has permissions:
           * `IDENTITY_READ` and `IDENTITY_UPDATE` on users in the tenancy
           * Typically, a policy like:
             ```text theme={null}
             Allow group <group-name> to manage users in tenancy
             ```
        3. Know:
           * Tenancy OCID
           * Compartment/Users whose keys you want to rotate (or all users in tenancy)

        ***

        ## 2. High-Level Rotation Logic

        For each user:

        1. List all **Customer Secret Keys**.
        2. For each key:
           * If `time_created` is older than 90 days:
             1. Create a **new** Customer Secret Key.
             2. Store the new key’s ID/secret somewhere safe (e.g., password manager, vault).
             3. Update any application/config using the old key to use the **new** key.
             4. Delete the **old** Customer Secret Key.

        You cannot safely delete an old key before your apps are updated. In automation, you might:

        * Mark old keys as “stale” and send alerts,
        * Or rotate only keys that are not in current use (if you track usage yourself).

        ***

        ## 3. Example Python Script – Detect And Rotate Keys Older Than 90 Days

        This script:

        * Iterates over all users in tenancy (or filter by name),
        * Checks each user’s customer secret keys,
        * For keys older than 90 days:
          * Creates a new key,
          * Prints the new key secret (you must store it securely),
          * Deletes the old key (this step is optional until you’ve updated the apps).

        > WARNING: This will break any system still using the old secret key.\
        > Test in non‑prod and comment out the delete step at first.

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

        # ------------------------------
        # CONFIG
        # ------------------------------
        PROFILE = "DEFAULT"           # profile in ~/.oci/config
        ROTATION_AGE_DAYS = 90
        DRY_RUN = True                # True = don't actually create/delete; just report

        # Optional: filter only certain users
        USER_NAME_FILTER = None       # e.g., "my-service-user", or None for all users

        # ------------------------------
        # SETUP
        # ------------------------------
        config = oci.config.from_file("~/.oci/config", PROFILE)
        identity_client = oci.identity.IdentityClient(config)
        tenancy_ocid = config["tenancy"]

        rotation_cutoff = datetime.now(timezone.utc) - timedelta(days=ROTATION_AGE_DAYS)

        # ------------------------------
        # HELPER FUNCTIONS
        # ------------------------------
        def list_all_users(tenancy_id):
            users = []
            list_users_response = oci.pagination.list_call_get_all_results(
                identity_client.list_users,
                compartment_id=tenancy_id
            )
            users = list_users_response.data
            if USER_NAME_FILTER:
                users = [u for u in users if u.name == USER_NAME_FILTER]
            return users

        def list_customer_secret_keys(user_ocid):
            return identity_client.list_customer_secret_keys(user_id=user_ocid).data

        def create_customer_secret_key(user_ocid, description=None):
            details = oci.identity.models.CreateCustomerSecretKeyDetails(
                display_name=description
            )
            response = identity_client.create_customer_secret_key(
                user_id=user_ocid,
                create_customer_secret_key_details=details
            )
            # response.data has: id, display_name, time_created, key (secret string)
            return response.data

        def delete_customer_secret_key(user_ocid, key_id):
            identity_client.delete_customer_secret_key(
                user_id=user_ocid,
                customer_secret_key_id=key_id
            )

        # ------------------------------
        # MAIN
        # ------------------------------
        def main():
            users = list_all_users(tenancy_ocid)
            print(f"Found {len(users)} users to process")

            for user in users:
                print(f"\n=== User: {user.name} ({user.id}) ===")
                csk_list = list_customer_secret_keys(user.id)

                if not csk_list:
                    print("  No customer secret keys.")
                    continue

                for csk in csk_list:
                    created = csk.time_created
                    age_days = (datetime.now(timezone.utc) - created).days
                    print(f"  Key: {csk.id}, created: {created}, age: {age_days} days, state: {csk.lifecycle_state}")

                    if created <= rotation_cutoff and csk.lifecycle_state == "ACTIVE":
                        print("    -> Key older than 90 days: ROTATION NEEDED")

                        if DRY_RUN:
                            print("    [DRY RUN] Would create a new key and delete this old one.")
                            continue

                        # 1. Create a new key
                        description = f"Rotated on {datetime.now(timezone.utc).isoformat()}"
                        new_key = create_customer_secret_key(user.id, description=description)

                        print("    Created NEW Customer Secret Key:")
                        print(f"      ID: {new_key.id}")
                        print(f"      Created: {new_key.time_created}")
                        # IMPORTANT: new_key.key is the actual secret value – store it safely!
                        print(f"      SECRET VALUE (store securely!): {new_key.key}")

                        # TODO: Here you must update your apps/services to use new_key.key
                        # This may involve:
                        #  - Updating passwords/secrets in your apps
                        #  - Updating CI/CD or Vault, etc.

                        # 2. Delete the old key AFTER apps are updated
                        # For safety, you may want to delay deletion or require a manual flag.
                        confirm_delete = True  # adjust logic as needed
                        if confirm_delete:
                            delete_customer_secret_key(user.id, csk.id)
                            print(f"    Deleted OLD Customer Secret Key: {csk.id}")

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

        ***

        ## 4. How To Use This For Ongoing Monitoring

        1. Keep `DRY_RUN = True` to use it as a **monitoring/check** script.
        2. Run it periodically via:
           * OCI DevOps pipeline,
           * A scheduled job (cron) on a bastion/automation server,
           * Or an OCI Function triggered via Events (if you wrap this logic into a function).
        3. Parse the output / send results to:
           * Email / Slack / Teams,
           * Logging / monitoring system (Cloud Guard, custom metrics, etc.).

        Once you’re confident, set `DRY_RUN = False` and introduce a safe process around:

        * Storing new secrets securely,
        * Coordinating application updates before deleting old keys.
      </Accordion>

      <Accordion title="Using Terraform">
        Terraform cannot enforce “rotate every 90 days” for OCI IAM customer secret keys; it can only (re)create/delete keys, not schedule or trigger periodic rotation.

        In practice you either:

        * Rotate manually in the Console (Identity & Security → Users → User → Customer Secret Keys → Create / Delete old), or
        * Automate rotation outside Terraform using OCI Events + Functions/CLI/SDK, or an external scheduler (e.g., CI pipeline) that calls `oci iam customer-secret-key` APIs on a 90‑day schedule.

        There is no `oci_identity_*` Terraform resource or argument that can express a 90‑day rotation policy for IAM customer secret keys, so there will be nothing for `terraform plan` to show for this control.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
