Home / OCI

OCIChecklistIntermediate

Rotating OCI API signing keys for automation users without downtime - a checklist

A planned, overlap-based rotation of OCI API signing keys for CI pipelines and scripts. Inventory every caller, add the new key, cut over, prove the old key is idle, then delete it.

Deepak Bhardwaj6 min read

Applies toOCI IAM (identity domains), OCI CLI 3.x, OCI SDKs and Terraform provider using API key auth

Goal

Replace the API signing key used by a service or automation user (CI runner, Terraform, backup scripts) on a schedule, without a window where jobs fail with 401 NotAuthenticated.

This is the planned version. If a key has leaked, follow the incident runbook instead: revoke first, investigate second.

The approach is overlap: a user can hold up to three API signing keys at once, so you add the new key, move every caller to it, prove the old key is unused, then delete it.

Before you start

  • You have permission to manage the user's API keys (manage users in the domain, or the user managing their own keys).
  • The user has at most two keys today. A third slot is needed for the new key.
  • You know every place the current key is installed. If you don't, do the inventory below first.
  • Someone who owns each consuming system is available during cutover.
export USER_OCID=ocid1.user.oc1..aaaa...
oci iam user api-key list --user-id "$USER_OCID" \
  --query 'data[].{fingerprint:fingerprint, state:"lifecycle-state", created:"time-created"}' \
  --output table

Warning

If the user already has three keys, you must delete one before uploading. Delete only a key you have proven idle (see "Prove the old key is idle"). Deleting the wrong one is an outage for whatever uses it.

Inventory the callers

Every caller identifies its key by fingerprint. Find where the current fingerprint is configured.

Where What to look for
OCI CLI / SDK hosts ~/.oci/config fingerprint= and key_file= per profile
Terraform provider "oci" block, TF_VAR_fingerprint, TF_VAR_private_key_path, or a CLI profile
CI/CD secrets Pipeline variables or secret stores holding the PEM and fingerprint
Containers / Kubernetes Secrets mounted as config and key files
Third-party tools Backup, monitoring or cost tools configured with a user OCID + key

On a Linux host, a quick search:

grep -RIl "aa:bb:cc:dd" /etc /opt /home ~/.oci 2>/dev/null

Confirm a private key file matches a fingerprint:

openssl rsa -pubout -outform DER -in ~/.oci/oci_api_key.pem 2>/dev/null | openssl md5 -c

The output (after (stdin)=) is the fingerprint OCI shows for the uploaded public key.

Check what the key is actually doing

Audit records the credential used on each request; the key's fingerprint appears in the event's identity credentials. Pull a recent window and filter with jq (Audit events are stored per compartment; repeat for the compartments the automation works in, or use Logging Search on the _Audit log with subcompartments included):

FP="aa:bb:cc:dd:..."
oci audit event list --compartment-id "$COMPARTMENT_OCID" \
  --start-time 2026-11-11T00:00:00Z --end-time 2026-11-12T00:00:00Z --all \
  | jq -r --arg fp "$FP" '.data[] | select(tostring | contains($fp))
      | [.["event-time"], .data.identity.ipAddress // "", .data.eventName // ""] | @tsv' \
  | sort | uniq -c | sort -rn | head -20

Field names inside the event can differ in case between CLI versions; check one raw event if a column comes back empty. Source IPs here are your real inventory: any IP you can't map to a known system is a caller you'll break.

Create and upload the new key

  • Generate a new 2048-bit (or larger) RSA key pair on a trusted host:
umask 077
openssl genrsa -out ~/.oci/svc-ci-2026-11.pem 2048
openssl rsa -pubout -in ~/.oci/svc-ci-2026-11.pem -out ~/.oci/svc-ci-2026-11_public.pem
  • Upload the public key:
oci iam user api-key upload --user-id "$USER_OCID" \
  --key-file ~/.oci/svc-ci-2026-11_public.pem \
  --query 'data.fingerprint' --raw-output
  • Record the new fingerprint, the date and the owner in your secrets inventory.
  • Store the private key in your secret manager (OCI Vault secret, CI secret store). Don't leave copies on laptops.

Tip

Name key files with the date. When three fingerprints are listed on a user, the file name is often the only way to tell them apart quickly.

Cut over the callers

Do one system at a time and test after each.

  • Add a temporary CLI profile with the new key and test it before touching the real profile:
[NEWKEY]
user=ocid1.user.oc1..aaaa...
fingerprint=11:22:33:...
key_file=~/.oci/svc-ci-2026-11.pem
tenancy=ocid1.tenancy.oc1..aaaa...
region=eu-frankfurt-1
oci os ns get --profile NEWKEY
oci iam region-subscription list --profile NEWKEY --query 'data[].{"region":"region-name"}' --output table
  • Update the real profile (fingerprint and key_file together) or the CI secret.
  • Trigger one real job per system (a terraform plan, a backup run) and confirm it succeeds.
  • For containers, roll the pods or restart the service so the new secret is read.
Symptom after cutover Likely cause Fix
401 NotAuthenticated Fingerprint and key file don't match Recompute the fingerprint from the private key
401 only on some runners Old secret cached on some agents Restart agents, check secret versioning
Works in CLI, fails in Terraform Provider uses env vars, not the profile Check TF_VAR_* and provider block
401 everywhere, keys correct Host clock skew Fix NTP; signed requests are time-bound

Prove the old key is idle

  • Re-run the Audit query for the old fingerprint over a window that covers every schedule (daily jobs: 24-48 hours; monthly jobs: plan for them or run them manually).
  • Zero hits for the old fingerprint, steady hits for the new one.

Delete the old key

oci iam user api-key delete --user-id "$USER_OCID" --fingerprint "aa:bb:cc:dd:..." --force
oci iam user api-key list --user-id "$USER_OCID" --query 'data[].fingerprint'

Caution

Deletion takes effect immediately and can't be undone. If a forgotten caller appears, you would have to upload a new key and reconfigure it. That's why the idle check comes first.

  • Securely delete the old private key from hosts and secret stores (keep the secret version history if your policy requires it).
  • Update the inventory: fingerprint removed, date, who did it.

Prevent it next time

  • Prefer instance principals, resource principals or OKE workload identity for anything running inside OCI. No key to rotate.
  • Keep one key in use per user; the spare slots are for rotation, not for sharing.
  • One automation user per system, so a rotation affects one owner.
  • Put the key's creation date in your inventory and alert on keys older than your rotation period (time-created from api-key list).
  • Run the Audit fingerprint query monthly; unknown source IPs are worth a look even outside rotation.