Oracle has never been more committed to customer success. To enable customers' success, we are releasing more services and features every day. Secrets management is the new feather in the cap. As part of the Oracle Cloud Infrastructure Vault, we can now manage both secrets and keys.
Secrets are credentials such as passwords, certificates, SSH keys, or authentication tokens for third-party cloud services that you use with Oracle Cloud Infrastructure services. Storing secrets in a vault provides greater security than you might achieve by storing them elsewhere, such as in code or configuration files. You can retrieve secrets from the vault when you need them to access resources or other services. You (an application) can cache a secret and use it as long as you need it.
All the tools and methods that you use with other Oracle Cloud Infrastructure services, like cli, API, Java SDK, Python SDK, and of course, console access, will work with Oracle Cloud Infrastructure vault as well. There is a lot of information about Oracle Cloud Infrastructure vault that you can read from here. I will focus on secrets use cases and talk about how to use them.
The following diagram illustrates the most fundamental secrets use case. You create secret (credentials) and store them in Oracle Cloud Infrastructure vault. The application can use/read the secret as needed and then connect to the target service.
In the references, I have added links to documents that talk about creating a secret from Oracle Cloud Infrastructure console, so I will not repeat it here. I will go over how to use the Python SDK to both manage secrets and use secrets in your application. You have to use vaults client to perform CRUD operation on secrets. However, applications should use secrets clients to read secrets. Using secrets client, you cannot perform Create, Update, and Delete operations.
Before you create a secret, you have to create a vault and a key that Oracle Cloud Infrastructure will use to encrypt secrets. I will not get into creating a vault and key. You can refer to kms example for creating vault and key. You will need vault OCID and key OCID to create a secret.
config = config = oci.config.from_file(
"~/.oci/config",
"$OCI_PROFILE") #Replace $OCI_PROFILE with the profile name to use
#Vault client to manage secrets
vaults_client = oci.vault.VaultsClient(config)
vaults_client_composite = oci.vault.VaultsClientCompositeOperations(vaults_client)
def create_secret(vaults_client_composite, compartment_id, secret_content, secret_name, valult_id, key_id):
print("Creating a secret {}.".format(secret_name))
# Create secret_content_details that needs to be passed when creating secret.
secret_description = "This is just a test"
secret_content_details = oci.vault.models.Base64SecretContentDetails(content_type=oci.vault.models.SecretContentDetails.CONTENT_TYPE_BASE64,
name=secret_content,
stage="CURRENT",
content=secret_content)
secrets_details = oci.vault.models.CreateSecretDetails(compartment_id=compartment_id,
description = secret_description,
secret_content=secret_content_details,
secret_name=secret_name,
vault_id=vault_id,
key_id=key_id)
#Create secret and wait for the secret to become active
response = vaults_client_composite.create_secret_and_wait_for_state(create_secret_details=secrets_details,
wait_for_states=[
oci.vault.models.Secret.LIFECYCLE_STATE_ACTIVE])
return response
def create_newsecret_version(vaults_client_composite, secret_content, secret_id):
print("Creating a new secret version {}.".format(secret_id))
#Create secret_content_details that needs to be passed when updating secret content.
secret_content_details = oci.vault.models.Base64SecretContentDetails(content_type=oci.vault.models.SecretContentDetails.CONTENT_TYPE_BASE64,
stage="CURRENT",
content=secret_content)
secrets_details = oci.vault.models.UpdateSecretDetails(secret_content=secret_content_details)
#Create new secret version and wait for the new version to become active.
response = vaults_client_composite.update_secret_and_wait_for_state(secret_id,
secrets_details,
wait_for_states=[
oci.vault.models.Secret.LIFECYCLE_STATE_ACTIVE])
return response
def move_secret(vaults_client, secret_id, target_compartment_id):
print("Moving secret to a target compartment")
#Create an object of Change Secret Compartment Details
target_compartment_details = oci.vault.models.ChangeSecretCompartmentDetails(compartment_id=target_compartment_id)
#Move the secret to target compartment and then wait for the state to become active.
response = vaults_client.change_secret_compartment(secret_id, change_secret_compartment_details=target_compartment_details)
target_state = oci.vault.models.Secret.LIFECYCLE_STATE_ACTIVE.lower()
try:
waiter_result = oci.wait_until(
vaults_client,
vaults_client.get_secret(secret_id),
evaluate_response=lambda r: getattr(r.data, 'lifecycle_state') and getattr(r.data, 'lifecycle_state').lower() == target_state,
waiter_kwargs={}
)
result_to_return = waiter_result
print("Change compartment response is {}.".format(result_to_return.data))
return result_to_return
except Exception as e:
raise oci.exceptions.CompositeOperationError(partial_results=[response], cause=e)
def delete_secret(vaults_client, secret_id, deletion_time):
print("Deleting a secret")
#Create Secret deletion details object.
secret_deletion_details = oci.vault.models.ScheduleSecretDeletionDetails(time_of_deletion=deletion_time)
#Delete the secret or mark the secret for deletion
response = vaults_client.schedule_secret_deletion(secret_id, secret_deletion_details)
print("Secret deletion response is: {}.".format(response.data))
# Usage : python secret_examples.py secret_id
def read_secret_value(secret_client, secret_id):
print("Reading vaule of secret_id {}.".format(secret_id))
response = secret_client.get_secret_bundle(secret_id)
base64_Secret_content = response.data.secret_bundle_content.content
base64_secret_bytes = base64_Secret_content.encode('ascii')
base64_message_bytes = base64.b64decode(base64_secret_bytes)
secret_content = base64_message_bytes.decode('ascii')
return secret_content
config = config = oci.config.from_file(
"~/.oci/config",
"$OCI_PROFILE") #Replace $OCI_PROFILE with the profile name to use
if len(sys.argv) != 2:
raise RuntimeError(
'This example expects an ocid for the secret to read.')
secret_id = sys.argv[1]
secret_client = oci.secrets.SecretsClient(config)
secret_content = read_secret_value(secret_client, secret_id)
print("Decoded content of the secret is: {}.".format(secret_content))
Kiran Thakkar is an expert in Identity and Access Management with more than 10 years of experience in the space. He is also OCI certified Associate Architect and help customers on OCI use cases. He is believer in blockchain technology and follows that space as it grows.
Previous Post
Next Post