← Oracle ACE articles

ACE-U field notes

Practical secrets with OCI Vault: creation, rotation, and usage

Storing application credentials in Vault and rotating them without writing custom scripts everywhere.

Shubham Anandani··3 min read

Problem

A database password in an environment variable or a config file is a leak waiting for a screenshot, a log line or a copied image. The harder question is operational: who creates the secret, how does the app read it, and what happens when it changes?

I wanted one flow that answers all three, so rotation is a normal event instead of a project.

Options and trade-offs

  • Secrets in files or environment variables: fast to start, and prone to leaks and drift.
  • A non-OCI secret store: a good option if you already run one, with extra integration and policy work.
  • OCI Vault secrets: IAM-governed, versioned, with rotation options. It needs deliberate policies and a read path.

My recommendation

Create the secret in a vault, with a master encryption key in the same vault, and let the application read the current version at runtime using an instance or resource principal. Rotate sensitive credentials on a schedule and watch the audit log for reads.

Worked example

Reading a secret from Java with an instance principal. Secret content comes back base64 encoded, so decode it and keep it in memory.

var provider = InstancePrincipalsAuthenticationDetailsProvider.builder().build();
try (var secrets = SecretsClient.builder().build(provider)) {
    var req = GetSecretBundleRequest.builder()
            .secretId(System.getenv("DB_SECRET_OCID"))
            .stage(GetSecretBundleRequest.Stage.Current)
            .build();
    var content = (Base64SecretBundleContentDetails)
            secrets.getSecretBundle(req).getSecretBundle().getSecretBundleContent();
    byte[] password = java.util.Base64.getDecoder().decode(content.getContent());
    // use the bytes, then discard them; do not log them
}

The policy that lets only the runtime read that one secret:

Allow dynamic-group app-runtimes to read secret-bundles in compartment apps
  where target.secret.id = '<db_secret_ocid>'

Rotation can be configured on the secret with an interval, or driven through a function that updates the target system, such as an Autonomous Database user, and then writes a new secret version. Because every version has a stage such as current or previous, you can roll back by pointing readers at the earlier version while you investigate.

Checklist

  1. Create the secret with a key in the same vault.
  2. Authorize only the runtime principal to read secret bundles.
  3. Decode at runtime, hold the value in memory and never log it.
  4. Turn on rotation for credentials that matter.
  5. Alert on unusual GetSecretBundle activity in the audit log.
  6. Write down how to restore the previous version if a rotation fails.

Where this doesn't apply

One-time tokens that never need to be read again do not need a vault entry. Very large blobs may also exceed the secret size limit, so check the current limit before choosing Vault for them.

One honest limitation

Rotation and cross-region replication add moving parts. I rehearse a rotation in a test environment before the first production run.

Sources

  • OCI Documentation: Vault, Creating a Secret
  • OCI Documentation: Updating a Secret and Secret Rotation
  • OCI Documentation: Retrieving a Secret Bundle (Java SDK)