Christoph's 2 Cents

A Backup for My Brain!

CloudDevOpsOracle Cloud InfrastructrureOracle Tools

OCI Vault: Manage a Secret via CLI

The OCI Vault can help you store secrets such as encryption keys, passwords , and more.
I won’t go into the details of how to set up a vault, as this has been done very well by Tim Hall.

Instead I’ll focus on how to use the CLI to manage a secret: How to create and update one, and how to get the secret in clear text.

As an added benefit, rather than just using a plain text example such as “Hello World!”, I’ll actually use a randomly generated, secure password created via openssl.

To get started you’ll need the OCIDs for the vault, its compartment, and the key.

The account to which you connect needs to have a policy to access the secrets.

A secrets administrator needs to have these three policies:

Allow group SecretAdmins to manage vaults in tenancy

Allow group SecretAdmins to manage keys in tenancy

Allow group SecretAdmins to manage secret-family in tenancy

A secrets user can have access to either all secrets in a compartment…

Allow group SecretUsers to read secret-family in compartment Sandbox

…or to a specific secret

Allow group MySecretUsers to read secret-family in compartment Sandbox where target.secret.name = 'my-secret'
export VAULT_OCID=ocid1.vault.oc1.iad.xxx           # Edit as needed
export COMPARTMENT_OCID=ocid1.compartment.oc1..xxx  # Edit as needed
export KEY_OCID=ocid1.key.oc1.iad.xxx               # Edit as needed
export PASSWORD=$(openssl rand -base64 32 | base64) # See http://bit.ly/gen-pwd
export SECRET_NAME="my_secret-demo"
export VAULT_USER_PROFILE="VAULT_USER"              # OCI CLI Profile

# See a list of vaults in a compartment
oci kms management vault list \
    --profile $VAULT_USER_PROFILE \
    -c $COMPARTMENT_OCID \
    --query "data[].{id:id,state:\"lifecycle-state\",name:\"display-name\"}" \
    --output table

# Example Output
+------------------------+------------+--------+
| id                     | name       | state  |
+------------------------+------------+--------+
| ocid1.vault.oc1.phx.xxx| my-vault   | ACTIVE |
+------------------------+------------+--------+

# Create secret
oci vault secret create-base64 \
    --profile $VAULT_USER_PROFILE \
    -c $COMPARTMENT_OCID \
    --secret-name $SECRET_NAME \
    --defined-tags '{"mytags": {"contact": "email@example.com"}} \
    --vault-id $VAULT_OCID \
    --key-id $KEY_OCID \
    --secret-content-content $PASSWORD

# Get secret ocid
export SECRET_OCID=$(oci vault secret list --raw-output --query "data[?\"secret-name\" == '$SECRET_NAME'].id | [0]")

# List secret versions
oci secrets secret-bundle-version list-versions \
    --profile $VAULT_USER_PROFILE \
    --all \
    --secret-id $SECRET_OCID \
    --query "data[].{\"version-number\":\"version-number\",\"stages\":\"stages\"}" \
    --output table

# Example Output
+-----------------------+----------------+
| stages                | version-number |
+-----------------------+----------------+
| ['CURRENT', 'LATEST'] | 6              |
| ['PREVIOUS']          | 5              |
| ['DEPRECATED']        | 4              |
| ['DEPRECATED']        | 3              |
| ['DEPRECATED']        | 2              |
| ['DEPRECATED']        | 1              |
+-----------------------+----------------+


# Get secret decoded text
oci secrets secret-bundle get \
    --profile $VAULT_USER_PROFILE \
    --raw-output \
    --secret-id $SECRET_OCID \
    --query "data.\"secret-bundle-content\".content" | base64 -D


# Get secret decoded text for prior version
oci secrets secret-bundle get \
    --profile $VAULT_USER_PROFILE \
    --raw-output \
    --version-number 1 \
    --secret-id $SECRET_OCID \
    --query "data.\"secret-bundle-content\".content" | base64 -D


# Update a secret
oci vault secret update-base64 \
    --profile $VAULT_USER_PROFILE \
    --secret-id $SECRET_OCID \
    --force \
    --secret-content-content $(openssl rand -base64 32 | base64)


# Delete a secret. Time must be at least 24 hours in the future
oci vault secret schedule-secret-deletion \
    --secret-id $SECRET_OCID \
    --time-of-deletion 2020-09-03T10:20-0600


# Cancel secret deletion
oci vault secret cancel-secret-deletion \
    --secret-id $SECRET_OCID


# List all secrets in all vaults
oci vault secret list \
    --profile $VAULT_USER_PROFILE \
    -c $COMPARTMENT_OCID \
    --query "data[].{id:id,\"secret-name\":\"secret-name\",state:\"lifecycle-state\",\"time-of-deletion\":\"time-of-deletion\"}" \
    --output table

# List all ACTIVE secrets in a particular vault
MY_VAULT_OCID="ocid1.vault.oc1.iad.bzqujmc6aagyg.xxx"
oci vault secret list \
    -c $COMPARTMENT_OCID \
    --query "data[?\"vault-id\" == '${MY_VAULT_OCID}' && \"lifecycle-state\" == 'ACTIVE' ].{id:id,\"secret-name\":\"secret-name\",state:\"lifecycle-state\",\"time-of-deletion\":\"time-of-deletion\"}" \
    --all \
    --output table

# Example Output
+-------------------------------+----------------+------------------+---------------------------+
| ocid1.vaultsecret.oc1.iad.xxx | secret5        | ACTIVE           | None                      |
| ocid1.vaultsecret.oc1.iad.xxx | secret4        | PENDING_DELETION | 2020-09-03T16:20:00+00:00 |
| ocid1.vaultsecret.oc1.iad.xxx | my_secret      | ACTIVE           | None                      |
| ocid1.vaultsecret.oc1.iad.xxx | cmr-secret3    | ACTIVE           | None                      |
| ocid1.vaultsecret.oc1.iad.xxx | cmr-secret1    | ACTIVE           | None                      |
| ocid1.vaultsecret.oc1.iad.xxx | cmr-apache-pvt | ACTIVE           | None                      |
| ocid1.vaultsecret.oc1.iad.xxx | cat_manga      | ACTIVE           | None                      |
+-------------------------------+----------------+------------------+---------------------------+

Fetch Secret Contents Script

Here is a useful bash script that will find secrets by name, and display their decoded contents:

#!/bin/bash

# This script accepts a case insensitive query string.
# It searches for vault secrets containing the query string in the name
# and with a lifecycle-state of ACTIVE.
# Docs:
# https://docs.oracle.com/en-us/iaas/Content/Search/Concepts/querysyntax.htm
# https://docs.oracle.com/en-us/iaas/Content/Search/Concepts/queryoverview.htm#resourcetypes

if [ -z "$1" ]
  then
    echo "Usage:"
    echo "  " ${0##*/} "<query string>"
    exit
fi

QUERY=$1

RES=$(oci search resource structured-search \
  --query-text "query vaultsecret resources where (displayName =~ '${QUERY}' && lifecycleState == 'ACTIVE')" \
  --query "data.items[*].{id:identifier,name:\"display-name\",\"lifecycle-state\":\"lifecycle-state\"}")


VAULT_USER_PROFILE="DEFAULT"

for SECRET_JSON in $(echo $RES | jq -c '.[]')
do
  SECRET_OCID=$(echo ${SECRET_JSON} | jq -r '.id')
  SECRET_NAME=$(echo ${SECRET_JSON} | jq -r '.name')
  VAL=$(oci secrets secret-bundle get \
    --profile $VAULT_USER_PROFILE \
    --raw-output \
    --secret-id $SECRET_OCID \
    --query "data.\"secret-bundle-content\".content" | base64 -D)
  echo "${SECRET_NAME}:  ${VAL}"
  echo ""
done
$ get_secrets mysecret
mysecret_123:  "do not have read this"

Useful Links:
Vault Overview
A Secure Way of Managing Secrets in OCI
Vault Policies
Using the OCI Instance Principals and Vault with Python to retrieve a Secret
Vault Service to generate, manage and encrypt & decrypt using Key