Every leaked API key, database password, or TLS private key in a public repository starts the same way: a secret that was never centrally managed. Teams scatter credentials across .env files, CI variables, and Slack messages because rotating and auditing them by hand feels harder than it should be. Oracle Cloud Infrastructure's Vault service solves this by giving you a single, encrypted, access-controlled place to store secrets and keys — but only if you configure it correctly. This guide walks through OCI Vault secrets management from provisioning through rotation, access control, and pipeline integration, so you finish with a working vault, a rotating secret, and policies that limit blast radius if a credential is ever compromised.
By the end, you'll have created a vault and master encryption key, stored and versioned a secret, wired up automatic rotation, scoped IAM policies to least privilege, and pulled the secret into a real deployment step — plus a troubleshooting checklist for the errors you're most likely to hit along the way.
Why OCI Vault Secrets Management Matters for Software Supply Chain Security
Hardcoded credentials are one of the most common root causes behind supply chain compromises: a build script with a plaintext token, a Terraform state file checked into version control, a Kubernetes secret mounted with no expiry. OCI Vault addresses this by encrypting secrets at rest with envelope encryption, versioning every change, and gating access through IAM policies tied to your compartment structure. Done right, OCI Vault secrets management gives you an auditable, rotate-able source of truth that removes secrets from source code, CI logs, and shared drives entirely. Done wrong — with an overly broad policy or a rotation job nobody monitors — it just moves the risk instead of removing it. The steps below are built to avoid that trap.
Step 1: Provision a Vault and Master Encryption Key
Start by creating a vault in the compartment where your workload lives. Use a dedicated compartment per environment (dev, staging, prod) so policies stay easy to reason about.
oci kms management vault create \
--compartment-id ocid1.compartment.oc1..exampleuniqueID \
--display-name "prod-secrets-vault" \
--vault-type DEFAULT
Once the vault is active, create the master encryption key OCI Vault will use to wrap every secret you store in it. This key never leaves the vault's hardware security module boundary — OCI uses it to encrypt a per-secret data encryption key, not your plaintext data directly.
oci kms management key create \
--endpoint https://<vault-mgmt-endpoint> \
--compartment-id ocid1.compartment.oc1..exampleuniqueID \
--display-name "prod-secrets-mek" \
--key-shape '{"algorithm":"AES","length":32}' \
--protection-mode HSM
Record the vault OCID and key OCID — both are required for every secret operation that follows.
Step 2: Create and Store Your First Secret
With the vault and key in place, create a secret. OCI Vault stores secret content base64-encoded and automatically versions it, so updates never overwrite history.
echo -n 'super-secret-db-password' | base64 > secret.b64
oci vault secret create-base64 \
--compartment-id ocid1.compartment.oc1..exampleuniqueID \
--vault-id ocid1.vault.oc1..exampleuniqueID \
--key-id ocid1.key.oc1..exampleuniqueID \
--secret-name "prod-db-password" \
--secret-content-content file://secret.b64 \
--description "Production database password"
Verify it landed correctly:
oci vault secret list --compartment-id ocid1.compartment.oc1..exampleuniqueID --output table
Each subsequent update creates a new secret version, and consumers can pin to a specific version OCID or always fetch "current" — useful during rotation windows when both old and new credentials must work briefly.
Step 3: Set Up Oracle Cloud Vault Secret Rotation
Static secrets that never change are almost as risky as no secret management at all. Configure Oracle Cloud Vault secret rotation so credentials expire and refresh on a schedule instead of living forever.
For database and application passwords, pair OCI Vault with a rotation function (an OCI Function invoked on a schedule) that generates a new credential, updates the target system, and writes the new value as a fresh secret version:
oci fn function invoke \
--function-id ocid1.fnfunc.oc1..exampleuniqueID \
--file rotate-db-password.json \
--body '{"secret_id":"ocid1.vaultsecret.oc1..exampleuniqueID"}'
Schedule it with OCI Resource Scheduler or an Events rule that fires on a cron-like interval (30 or 90 days is typical for database credentials; shorter for high-privilege service accounts):
oci events rule create \
--compartment-id ocid1.compartment.oc1..exampleuniqueID \
--display-name "rotate-db-secret-90d" \
--condition '{"eventType":["com.oraclecloud.scheduledjobs.timer"]}' \
--actions '{"actions":[{"actionType":"FAAS","isEnabled":true,"functionId":"ocid1.fnfunc.oc1..exampleuniqueID"}]}'
Keep the previous version active for a short overlap period so in-flight sessions don't break the moment rotation completes.
Step 4: Lock Down Access with IAM Policies
The single most common Vault misconfiguration is a policy scoped too broadly — manage secret-family at the tenancy level instead of the compartment or resource level. Scope policies tightly:
Allow group CI-Deploy-Group to use secret-family in compartment prod-secrets where target.secret.name = 'prod-db-password'
Allow group SecOps-Admins to manage vaults in compartment prod-secrets
Allow group SecOps-Admins to manage keys in compartment prod-secrets
Notice the separation: deployment automation gets use (read-only, decrypt) on a single named secret, while only security operations can manage the vault or key itself. Application instances should authenticate via instance principals or resource principals rather than long-lived API keys, closing the loop on the very problem Vault is meant to solve.
Step 5: Integrate Vault Secrets into Your Deployment Pipeline
Pull secrets into your pipeline at deploy time rather than baking them into images or CI variables. In a build step:
DB_PASSWORD=$(oci secrets secret-bundle get \
--secret-id ocid1.vaultsecret.oc1..exampleuniqueID \
--query 'data."secret-bundle-content".content' \
--raw-output | base64 --decode)
kubectl create secret generic db-credentials \
--from-literal=password="$DB_PASSWORD" \
--dry-run=client -o yaml | kubectl apply -f -
For Kubernetes-native workloads, the OCI Secrets Store CSI Driver mounts vault secrets directly as volumes, avoiding environment-variable exposure in kubectl describe output. For Terraform-managed infrastructure, reference secrets via the oci_secrets_secretbundle data source instead of variables files, so plaintext never touches state unencrypted at rest in your backend.
Step 6: Apply OCI Vault Best Practices for Defense in Depth
A handful of OCI Vault best practices consistently separate teams that avoid incidents from teams that don't:
- Use virtual private vaults for regulated workloads that need dedicated HSM partitions rather than the shared default vault tier.
- Enable auditing through OCI Audit and forward Vault-related events to your SIEM — every
GetSecretBundlecall should be traceable to a principal and a purpose. - Set secret expiration and rotation state on every secret so stale credentials surface in compliance reports automatically instead of relying on tribal knowledge.
- Never store secrets as plain compartment tags or freeform tags — these are visible to anyone with basic read access to the resource.
- Rotate the master encryption key itself periodically (OCI supports key rotation without re-encrypting existing secret versions immediately, deferring to next-use re-wrap), and disable old key versions only after confirming nothing still references them.
- Separate vaults by environment and sensitivity tier so a compromised dev credential can't be used to infer anything about production secret naming or structure.
Troubleshooting and Verification
"NotAuthorizedOrNotFound" on secret read: Almost always an IAM policy scoping issue. Confirm the calling principal (user, group, or instance principal) has a matching use secret-family or read secret-family statement in the correct compartment, and that the target.secret.name condition, if present, matches exactly.
Secret bundle returns old content after rotation: Consumers cached a specific secret version OCID instead of requesting "current." Confirm your retrieval call omits --stage or explicitly requests CURRENT, and check that your rotation function actually created a new version rather than updating metadata only.
Key marked "PENDING_DELETION" unexpectedly: Someone scheduled key deletion, which has a mandatory 7–30 day waiting period by design as a safety net. Cancel it immediately if unintended:
oci kms management key cancel-deletion --key-id ocid1.key.oc1..exampleuniqueID --endpoint https://<vault-mgmt-endpoint>
Rotation function fails silently: Check OCI Functions logs in the Logging service; the most frequent cause is the function's resource principal lacking use secret-family and manage secret-bundles permissions on the target compartment.
Verify end-to-end: Run a full audit pass — list every secret in the compartment, confirm each has a rotation state and an owning policy, and cross-check against your inventory of applications that consume secrets. Any secret with no rotation schedule and no recent access log entry is a candidate for retirement.
How Safeguard Helps
Configuring OCI Vault correctly is necessary but not sufficient — the harder problem is knowing whether every service in your environment is actually using it, and whether the credentials it manages ever leaked upstream before they were centralized. Safeguard continuously scans your source repositories, build artifacts, container images, and CI/CD pipelines for hardcoded secrets, flagging exactly the plaintext credentials that OCI Vault secrets management is meant to eliminate — before they ship. For teams already running Vault, Safeguard maps discovered secrets back to vault-managed equivalents, surfaces stale or unrotated credentials across your software supply chain, and gives security teams a single view of secret hygiene across every repo, registry, and deployment target, so a well-configured vault doesn't sit alongside a codebase full of the exposures it was supposed to prevent.