Managing Secrets
Create and manage vault secrets, secret tags, and secret rules.
With the importance of using OCI cloud services, it's important to store, retrieve, and manage secrets in its digital vault. Secrets can be a password, certificates, SSH keys, or authentication tokens that you use for connecting to OCI services and systems. Storing secrets in OCI Vault has greater security than storing them in a code or configuration files. The application communicates with the OCI Secret Management to retrieve the secret and connect to the target service.
Oracle Cloud Infrastructure Secret Management lets you to effortlessly protect sensitive data such as API keys, passwords, and encryption keys by using secrets. It offers a robust solution to create, store, manage, and access these secrets securely. The centralized storage it provides leverages the hardware security modules (HSMs) and granular access control to safeguard the security and integrity of critical information. Use OCI Secret Management to eliminate embedding secrets directly in applications and reduce the attack surface and strengthen an application's overall security.
Automatic Secret Generation and Rotation
When a secret is generated, it's updated periodically. You can update a secret manually or set automatically. The automatic generation and rotation of secrets takes off the burden in setting secret manually and rotating it using scripts but instead, provides efficient way to manage secrets from creation, rotation and deletion.
The automatic secret generation feature supports the use of templates for secret generation. With automatic secret rotation, you can set secret interval from 1 to 12 months. The feature integrates with Autonomous Database and Function services, letting you update a secret used in Autonomous Database or Functions code. In OCI Functions, the automatic rotation of secrets lets you easily rotate a credential and run code as part of the rotation process. The automation secret rotation feature is also available for manually created secrets.
Cross Region Replication of Secrets
You can replicate a secret in up to three destination regions. The replicas are read-only, and inherit changes made to the source secret. See Replicating Secrets for more information.
Benefits of using automatic secret rotation
- Enhanced security: Regularly updating your secrets minimizes the impact of compromised credentials leading to a data breach.
- Operational efficiency: Automating manual tasks such as creating, rotating a secret saves time and efficiency.
- Regulated compliance: Adhere to many standards that regulate compliance for secret rotation and automation.
- Reduced human error: Automating repetitive tasks reduces the possibility of human errors to bolster security.
Secret Generation
You can generate a secret for passphrases, SSH keys, and bytes. All secrets that OCI Vault generates are FIPS and security compliant. You can generate a secret using the OCI Console, API, or CLI. When you generate a secret, you must provide the secret context and define the secret template. The secret context defines the secret type and structure of the secret. Based on the secret type that you select; Vault supports different secret generation templates.
PASSPHRASE
: Generate passwords up to 32 characters in length. For OCI Database service default passwords, the maximum character length is 30.SSH_KEY
: Generate RSA key pairs of length 2048, 3072 and 4096. The private key is stored in the PKCS#8 PEM format and the public key is stored in the X.509 PEM format.BYTES
: Generate 512 and 1024 bytes that are FIPS complaint binary secret. Bytes are base64 code.
Secret Types and Default Templates
PASSPHRASE
- Supported templates:
SECRETS_DEFAULT_PASSWORD
andDBAAS_DEFAULT_PASSWORD
- Placeholder in secret template:
%GENERATED_PASSPHRASE%
- Example:
{"user": "abc", "pwd": "%GENERATED_PASSPHRASE%"}
- Supported templates:
-
SSH_KEY
- Supported templates:
RSA_2048
,RSA_3072
,RSA_4096
- Placeholder in secret template:
%GENERATED_PUBLIC_KEY%
,%GENERATED_PRIVATE_KEY%
- Example:
{"publicKey": "%GENERATED_PRIVATE_KEY%", "privateKey": "%GENERATED_PRIVATE_KEY%"} → {"publicKey": "-----BEGIN PUBLIC KEY-----\nBase64 encoded public key\n-----END PUBLIC KEY-----", "privateKey":"-----BEGIN PRIVATE KEY-----\nBase64 encoded private key\n-----END PRIVATE KEY-----"}
- Supported templates:
BYTES
- Supported templates:
BYTES_512
,BYTES_1024
- Placeholder in secret template:
%GENERATED_BYTES%
- Example:
{"host": "abc", "hostLuksKey": "%GENERATED_BYTES%"} → {"host": "abc", "hostLuksKey": "generatedbyteshere=="}
- Supported templates:
Secret Versions and Rotation States
Learn about vault secret versions, rotation states, and the impact of secret version limitation.
Understanding vault secret versions and rotation states helps you track and manage secret contents to stay in compliance with any limits, rotation or other rules, or regulations.
To learn basic secret concepts, including secret versions and rotation states, see Key and Secret Management Concepts. For information about working with secret versions, see Managing Secrets.
Rotation Functions
Rotation functions are responsible for rotating the secrets in Secret Service. Expand the following section to learn about the four steps in a rotation function, and to see sample function handler code
Rotation functions included the following four steps:
VERIFY_CONNECTION
: Verifies the connection to the target system using the existing credentials stored in the secret.CREATE_PENDING_VERSION
: Creates a new pending secret version in the secret.UPDATE_TARGET_SYSTEM
: Updates the target system with the credentials stored in the pending secret version created in the second step.PROMOTE_PENDING_VERSION
: Updates the state of the secret from pending to current.
Function handler:
The function handler must contain the logic to call the appropriate rotation step based on the step parameter. This can be achieved either by using IF ELSE conditional statements or switch case. The function handler generates an error if an invalid step parameter is provided.
Input:
The function handler expects single parameter: SecretRotationInput
. The secretRotationInput
is a POJO (Plain-old java object) containing the parameters required for rotation, including the secretId(String), step(String) and currentVersionNo(Long).
- secretId: The secret identifier or OCID
- step: The rotation step (Must be one of
VERIFY_CONNECTION
,CREATE_PENDING_VERSION
,UPDATE_TARGET_SYSTEM
orPROMOTE_PENDING_VERSION
) - currentVersionNo: The number of the
CURRENT
secret version
SecretRotationInput POJO
@Getter
@Setter
@ToString(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
@Builder(toBuilder = true)
public static class SecretRotationInput {
private String step;
private Long versionNo;
private String secretId;
}
Sample function handler code:
public static class SecretRotationOutput {
int responseCode;
Long currentVersionNo;
String returnMessage;
}
public SecretRotationOutput handleRequest(SecretRotationInput input) {
switch(input.getStep()) {
case "VERIFY_CONNECTION":
return verifyConnection(input.getSecretId());
case "CREATE_PENDING_VERSION":
return createNewPendingVersion(input.getSecretId());
case "UPDATE_TARGET_SYSTEM":
return updateTargetSystem(input.getSecretId(), input.getVersionNo());
case "PROMOTE_PENDING_VERSION":
return promotePendingVersion(input.getSecretId(), input.getVersionNo());
default:
log.error("Secret Rotation: invalid rotation step");
return SecretRotationOutput.builder()
.responseCode(400)
.currentVersionNo(null)
.returnMessage("INVALID STEP")
.build();
}
}
Step 1:
VERIFY_CONNECTION
This step verifies connection to the target system.
- Input: This method expects only the parameter
SecretId
. - Output: This method outputs the
SecretRotationOutput
. - Logic: The function first tries to fetch the
PENDING
version and verify the connection with it. This handles the failure scenario where previous retry failed to promote thePENDING
version, but the version has been successfully applied to the system. If it succeeds, return the success response. If it fails, fetch the current version and check the connection. If that succeeds, return the success response code along with the current version number. If it doesn't succeed, return the error.
Pseudo code for VERIFY_CONNECTION
pseudo code for verifyConnection:
Check if "PENDING" secret version exists
If it exist, verify connection
If succeeds, then return success.
Fetch the "CURRENT" secret version
Verify connection with "CURRENT" secret version
If succeeds, return success and the current version number in the response.
If not, return SecretRotationOutput with appropriate error code and message.
Step 2: CREATE_PENDING_VERSION
Generates a new pending secret version.
- Input: This method also accepts the
secretId
parameter. - Output: This method outputs the
SecretRotationOutput
. -
Logic: This method first checks for the existence of a secret version in
PENDING
state. If one doesn't exist, it generates a newPENDING
secret version. However, if one already exists, the step returns the success response. You can also use the secret metadata field to store extra details about the secret structure and can use the same structure when creating a new secret version. You can also use the Secret service's auto-generation feature to auto-generate the secret content. Auto-generation lets you to write more generic functions.
Pseudo code for CREATE_PENDING_VERSION
pseudo code for createPendingVersion:
Try to get the pending version
If it succeeds, return success
Else create a new secret version in "PENDING" state and then return success
Sample code:
// Constructor
public void constructorClass() {
secretsDpClient = SecretsClient.builder()
.region(region)
.configuration(configuration)
.build(auth_provider);
secretsCpClient = VaultsClient.builder()
.region(region)
.configuration(configuration)
.build(auth_provider);
}
private String createNewPassword() {
// This method must contains the logic to generate the new secret content
}
private SecretRotationOutput createNewPendingVersion(SecretRotationInput input) {
// Make sure the given secret exist
Secret secret = secretsCpClient.getSecret(GetSecretRequest.builder()
.secretId(input.getSecretId())
.build()).getSecret();
// Now try to get the pending secret version, if that fails, create a new one
try {
GetSecretBundleRequest getSecretBundleRequest = GetSecretBundleRequest.builder()
.secretId(input.getSecretId())
.stage(GetSecretBundleRequest.Stage.Pending)
.build();
secretsDpClient.getSecretBundle(getSecretBundleRequest);
return SecretRotationOutput.builder()
.responseCode(200)
.returnMessage("Successfully retrieved the pending secret version")
.build();
} catch (BmcException bmc) {
// Create a new pending version
UpdateSecretDetails updateSecretDetails = secret.getIsAutoGenerationEnabled() ? UpdateSecretDetails.builder()
.secretContent(Base64SecretContentDetails.builder()
.stage(SecretContentDetails.Stage.Pending)
.build())
.build() : UpdateSecretDetails.builder()
.secretContent(Base64SecretContentDetails.builder()
.content(createNewPassword())
.stage(SecretContentDetails.Stage.Pending)
.build())
.build();
secretsCpClient.updateSecret(UpdateSecretRequest.builder()
.secretId(input.getSecretId())
.updateSecretDetails(updateSecretDetails)
.build()).getSecret();
log.info("Successfully added a new version with 'PENDING' stage for secretId {}", input.getSecretId());
return SecretRotationOutput.builder()
.responseCode(200)
.returnMessage("Pending version created successfully")
.currentVersionNo(input.getVersionNo())
.build();
}
}
Step 3: UPDATE_TARGET_SYSTEM
Sets the pending secret in the target system.
- Input: This method accepts the
currentVersionNo
andsecretId
. - Output: This method also outputs the
SecretRotationOutput
. - Logic: This method first tries to login to the target system with the
PENDING
secret version and returns on success. This also handles the failure scenario where previous retry failed to promote the pending version but the version has been successfully applied to the system. If that fails, it tries to login with theCURRENT
secret version. If the current secret version succeeds, it sets thePENDING
password as the user password in the target system.
Pseudo code for UPDATE_TARGET_SYSTEM
Pseudo code for updateTargetSystem:
Fetch the "PENDING" secret version
Check the connection with Pending version
It it works return success and the pending version number in the response
Fetch the "CURRENT" secret version
Check the connection with it
If it works
Update the target system with "PENDING" version
Verify that target system is updated.
if yes then return success and the pending version number in the response
else return the appropriate error code and the error message
If not, return SecretRotationOutput with appropriate error code and message.
Sample code:
private SecretRotationOutput updateTargetSystem(String secretId, Long currentVersionNo) {
// Get the pending secret version
SecretBundle pendingSecretBundle = secretsDpClient.getSecretBundle(GetSecretBundleRequest.builder()
.secretId(secretId)
.stage(GetSecretBundleRequest.Stage.Pending)
.build()).getSecretBundle();
// First try to login with the pending secret, if it succeeds, return
Connection conn = getConnection(pendingSecretBundle);
if(conn) {
log.info("Updated the target system with pending version");
return SecretRotationOutput.builder()
.responseCode(200)
.returnMessage("Successfully update target service")
.currentVersionNo(pendingSecretBundle.getVersionNumber())
.build();
}
SecretBundle currentSecretBundle = secretsDpClient.getSecretBundle(GetSecretBundleRequest.builder()
.versionNumber(currentVersionNo)
.secretId(secretId)
.build()).getSecretBundle();
conn = getConnection(currentSecretBundle);
if(conn) {
// Write logic to update the target system and check the connection with the updated password
} else {
log.error("Unable to log into system using the current version");
return SecretRotationOutput.builder()
.returnMessage("Unable to log into system using the current version")
.responseCode(400)
.build();
}
}
Step 4: PROMOTE_PENDING_VERSION
Finish the rotation by marking the pending secret as current.
- Input: This method accepts the
currentVersionNo
andsecretId
. - Output: This method also outputs the
SecretRotationOutput
. - Logic: Call the Secret service to promote the
PENDING
version toCURRENT
.UpdateRequest
must specify which version need be promoted toCURRENT
.
Pseudo code for PROMOTE_PENDING_VERSION
pseudo code for promotePendingVersion:
Make updateSecret Api call to promote the specified version to "CURRENT"
Sample code:
private SecretRotationOutput promotePendingVersion(String secretId, Long versionNo) {
try {
Secret secret = secretsCpClient.updateSecret(UpdateSecretRequest.builder()
.secretId(secretId)
.updateSecretDetails(UpdateSecretDetails.builder()
.currentVersionNumber(versionNo)
.build())
.opcRequestId(UUID.randomUUID().toString())
.build()).getSecret();
log.info("Successfully promoted the version number {} to 'CURRENT'", versionNo);
return SecretRotationOutput.builder()
.responseCode(200)
.currentVersionNo(secret.getCurrentVersionNumber())
.returnMessage("Successfully promoted the pending version")
.build();
} catch (BmcException bmc) {
log.error("Fail to promote the pending version. SecretId: {}, pendingVersionNo: {}. {}", secretId, versionNo, bmc.getMessage());
return SecretRotationOutput.builder()
.returnMessage(bmc.getMessage())
.responseCode(bmc.getStatusCode())
.build();
}
}
Rotation States
Secret versions can have more than one rotation state at a time. When only one secret version exists, such as when you first create a secret, the secret version is automatically marked as both current and latest. The latest version of a secret contains the secret contents that were last uploaded to the vault. If you need to find which secret version has secret material most recently uploaded, you can use the "latest" status to do this.
When upload new secret contents for secret rotation, you can mark the secret version as pending. This lets you upload the secret material to the vault without immediately putting it into active use. You can continue using the current secret version until you're ready to promote a pending secret version to current status. This typically happens after you have rotated credentials on the target resource or service first. Note that you need to consider the effects of the secret rotation on applications and resources that rely on the secret. Changing which secret version is current could prevent an application or resource that needs it from retrieving the expected secret version from the vault.
Secret versions can also be marked as previous. This lets you easily roll back a secret to a previous version. You might need to do this when a secret is a mistakenly rotated, or when restoring a backup of a resource that needs to resume using an older secret version. A secret version marked as previous is the version that was marked as current directly before the most recent rotation. To roll back to a previous version, you update the secret to specify the secret version number you want.
As long as a secret version hasn't been deleted, you can update the secret to use that past secret version. When you update the secret, the secret version number you select gets marked as current. This has the same effect as promoting a secret version to current.
You can only delete secret versions that have been marked as deprecated. A deprecated secret version is one that's not marked as current, pending, or previous. This helps to prevent circumstances where you might delete a secret version that you need later (for example, when restoring a database you backed up before). A secret version that's marked as anything other than deprecated can be marked as current to return it to active use.
Version Limitation
The limits on secret versions applies to both a secret's versions that are in use and versions that are deprecated, including those that have been scheduled for deletion. For information about limits on the number of versions for a particular secret and for secret versions in a tenancy, see Service Limits.
Before You Begin
Before you begin, we recommend that you first read Secret Rules and Secret Versions and Rotation States to better understand the implications of working with rules, secret versions, and secret version rotation states.
Required IAM Policy
To use Oracle Cloud Infrastructure, an administrator must be a member of a group granted security access in a policy by a tenancy administrator. This access is required whether you're using the Console or the REST API with an SDK, CLI, or other tool. If you get a message that you don't have permission or are unauthorized, verify with the tenancy administrator what type of access you have and which compartment your access works in.
For administrators:
- The policy Let security admins manage vaults, keys, and secrets lets the specified group do everything with vaults, keys, and secrets.
- The policy Create a policy to enable encryption keys lets the specified group do everything with secrets in a specific vault.
- The policy Let users read, update, and rotate all secrets lets the specified group read, update, and rotate all secrets in any vault in the tenancy.
- For more information about permissions or if you need to write more restrictive policies for secrets, see Details for the Vault Service.
If you're new to policies, see Managing Identity Domains and Common Policies.
Tagging Secrets
Apply tags to resources to help organize them according to your business needs. You can apply tags when you create a resource, and you can update a resource later to add, revise, or remove tags. For general information about applying tags, see Resource Tags.
Monitoring Resources
You can monitor the health, capacity, and performance of Oracle Cloud Infrastructure resources by using metrics, alarms, and notifications. For more information, see Monitoring and Notifications.
Moving Resources to a Different Compartment
You can move secrets from one compartment to another. After you move a secret to a new compartment, policies configured for the compartment apply immediately and affect access to the secret and secret versions. Moving a secret doesn't affect access to the vault that a secret is associated with. Similarly, you can move a vault from one compartment to another independently of moving any of its secrets. For more information, see Managing Compartments.