Why this matters
Most apps need at least one password, API key or signing key. The usual shortcut is a config file, an environment variable, a container image layer or a CI variable. Each copy widens the blast radius and each copy drifts. Oracle Cloud's OCI Vault gives you one place to store the value, one IAM model to control reads, and one audit trail for access.
Vault does not remove the need to design. The app now depends on a network call and an IAM policy. If the vault is unreachable or the policy is wrong, the app fails at startup. Decide early whether it should fail closed, or start with a cached last known good value for read paths.
Compartments are the main boundary. Put production secrets in a production compartment and keep development credentials out of it. A single vault per environment is easier to reason about than one shared vault with clever policies. The trade-off is more keys and more policy lines to maintain.
Before you start
Pick the vault type. OCI Vault offers a virtual private vault, which gives you a dedicated HSM partition, and a private vault, which shares an HSM partition. The dedicated option costs more and buys isolation. Many apps are fine on a private vault, provided the IAM boundary is tight.
Choose the master encryption key. Secrets are encrypted with a key in the same vault. The key can be software protected or HSM protected. Deleting or disabling that key makes every secret under it unreadable, so treat key administration as a separate, small role.
Map identities before you create anything. Admins need manage vaults, manage keys and manage secret-family in the compartment. The app needs only read secret-family. On compute, use a dynamic group that matches instances by compartment or defined tags. On OKE, decide which identity the pods inherit. On OCI Functions, use a resource principal.
Agree on names and versions. Use one secret per credential, named with environment, app and purpose, such as prod-billing-db-password. A single JSON blob forces a full rewrite to rotate one field and gives every reader access to every field. Decide whether the app reads CURRENT or LATEST, and who creates the next version.
How to do it
Create the vault and key in the app's compartment, then create the secret with the OCI CLI or Console. The secret content is base64 encoded. Keep the secret OCID in app configuration, not the value. Then grant the app identity read access and make the app fetch the bundle at startup.
Fetching is a short code path: call the secret bundle API, decode the base64, keep the value in memory, and use it where needed. Do not write it to disk, do not log it, and do not pass it to child processes unless you have to. Set a timeout and retry with backoff. Add a refresh interval or refresh on deploy so a new version is picked up.
On OKE, remember that an instance principal belongs to the node, not the pod. Every pod on that node can read what the node can read. Split node pools by trust level, or run a controller that syncs only the secrets each namespace needs. On Functions, a resource principal keeps the grant tied to the function.
- Create the vault in the app compartment. Use the OCI Console under Identity and Security, Vault, or the CLI. Pick a private vault unless you need dedicated HSM isolation. Keep production and nonproduction separate.
- Create a master encryption key. Create the key inside the vault and give it a clear name, such as prod-app-key. Choose software or HSM protection based on your isolation needs. Restrict manage keys to a small admin group.
- Store one credential per secret. Name secrets by environment, app and purpose. Base64 encode the value before upload. Use oci vault secret create-base64 with the vault OCID, key OCID and secret name.
- Grant the app identity read access. Create a dynamic group for the app instances. Add a policy such as allow dynamic-group app-prod to read secret-family in compartment Prod. Do not grant at the tenancy root.
- Fetch the bundle at runtime. Call oci secrets secret-bundle get with the secret OCID and stage CURRENT. Decode the base64 content and hold it in memory. Set short timeouts and retry with backoff.
- Rotate with secret versions. Add a new version instead of overwriting the old one. Roll the app or let the refresh pick it up. Pin CURRENT and promote deliberately, or use LATEST for faster change with more risk.
- Cache in memory and fail safely. Keep a short in-memory cache, never a file on disk. Choose fail closed for high-risk actions, or last known good for read paths. Log the secret name and version, never the value.
How to check it worked
Test from inside the app identity, not from your admin shell. Run a bundle get from a test instance in the dynamic group. It should return the base64 content. Run the same call from a host outside the group and confirm it is denied with a 403 or 404.
Use OCI Audit to confirm reads. Filter events by the secret OCID and the principal. You should see the app's identity and nothing unexpected. Check the app logs show the secret name and version, never the value.
Run a rotation drill. Add a new version, deploy or wait for the refresh, and confirm the app uses the new value. Then check that old versions are not still in use. Finally, inspect the image, config maps and startup scripts for leftover copies.
Mistakes to avoid
Putting secret content in Terraform state is a common slip. The OCI provider resource for a secret can write the content to state, and state often lands in a bucket or a shared backend. Create secrets outside Terraform, or treat the state as sensitive and restrict who can read it.
Do not grant read secret-family at the tenancy root or on a shared vault that holds every environment. One compromised app then reads every secret it can reach. Use compartments, separate vaults and narrow dynamic groups. On OKE, check what the node identity can read before you trust a pod.
Do not cache forever. Long-running apps can hold an old credential for months. Set a refresh interval and track the version. Do not delete a key or vault without checking dependencies: deletion makes secrets unreadable. Use the waiting period and delete protection where available.
Do not use environment variables as the only copy. They leak through process listings, crash dumps and debug endpoints. Load from Vault into memory and keep the value out of logs. If you want an outside read on the IAM and vault setup, the Cloud security review from Cloudverg is $6,500/month, fixed scope, and covers a read-only review of up to 5 cloud accounts or subscriptions.
Frequently asked questions
How do applications read secrets from OCI Vault?
The app calls the secret bundle API with the secret OCID, using an instance principal, resource principal or user principal. The response contains base64 content. Decode it in memory and avoid logging it.
How do I restrict who can read a secret in OCI Vault?
Use compartments and IAM policies. Grant read secret-family to a narrow group or dynamic group in that compartment, not at the tenancy root. Keep admin rights to manage vaults, manage keys and manage secret-family in a separate group.
Should I use environment variables for secrets on Oracle Cloud?
They are fine for a local test but weak for production. They can show up in process listings, crash dumps and debug endpoints. Fetch from OCI Vault at runtime and keep the value in memory.