Skip to main content

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

Remediation

Using Console

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 & SecurityIdentityUsers.
  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 & SecurityCloud 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 GuardProblems.
  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.
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):
    oci setup config
  2. Ensure the CLI user has policy allowing:
    • inspect users
    • manage customer-secret-keys on users in the tenancy

Example policy:

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:

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

Or for the current CLI user:

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:

USER_OCID="<USER_OCID>"

2.2. List the Customer Secret Keys

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:

#!/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

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:

#!/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):
crontab -e

0 1 * * * /usr/local/bin/oci_rotate_customer_keys.sh >> /var/log/oci_key_rotation.log 2>&1
  1. 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.
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:
    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:
      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.

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.
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.