The information contained in this article has been verified as up-to-date on the date of the original publication of the article. HashiCorp endeavors to keep this information up-to-date and correct, but it makes no representations or warranties of any kind, express or implied, about the ongoing completeness, accuracy, reliability, or suitability of the information provided.
All information contained in this article is for general information purposes only. Any reliance you place on such information as it applies to your use of your HashiCorp product is therefore strictly at your own risk.
Introduction
When renewing or transitioning HashiCorp Vault Enterprise licenses, it is critical to determine if Advanced Data Protection (ADP) features are in use. This assessment identifies active configurations within the following three engines:
Transform Secrets Engine: Used for FPE (Format Preserving Encryption), masking, and tokenization.
KMIP Secrets Engine: Used to manage keys for KMIP-compatible clients (e.g., VMware, NetApp).
Key Management Secrets Engine: Used for lifecycle management of keys in external KMS providers (AWS, Azure, GCP).
If these features are active and the new license does not include the ADP module, these engines will move into a "read-only" state.
Expected Outcome
After running the assessment script, you will receive a summary (and an optional timestamped .txt file) detailing every namespace in your cluster. Each ADP engine found will be labeled as ACTIVE (custom configuration detected) or EMPTY (only default settings or no data found).
Prerequisites
Permissions: A Vault token with Root or Sudo privileges.
Tools:
vaultCLI andjqmust be installed on the machine executing the script.Environment:
VAULT_ADDRandVAULT_TOKENmust be exported in your current shell.
Use Case
This procedure is intended for Vault Administrators performing a license audit. This script provides a safe, throttled way to scan the entire namespace hierarchy to ensure a new license won't put existing ADP engines into a "read-only" state.
Procedure
Step 1: Inspect the New License (Manual Dry-Run)
Before applying the new license, verify which modules it includes. Download your new license file (e.g., new_license.hclic) and run:
vault license inspect /path/to/new_license.hclic | grep -o '{.*}' | jq '{modules: .flags.modules, features: .features}'
After running the vault license inspect command, you will see a JSON object containing two lists: modules and features.
Compare your output to the table below. If you have active usage in your environment, the corresponding value must appear in your license output.
| If you use this engine... | Look for this in modules | ...OR this in features |
|---|---|---|
| Transform | advanced-data-protection-transform |
|
| KMIP | Included in ADP |
|
| Key Management | advanced-data-protection-key-management |
|
| All of the above | advanced-data-protection |
|
Step 2: Create the Assessment Script
Copy and paste the following block into your terminal to create the vault_adp_check.sh file:
cat << 'EOF' > vault_adp_check.sh
#!/bin/bash
# Generate Timestamp: YYYYMMDD_SS
TIMESTAMP=$(date +%Y%m%d_%S)
OUTPUT_FILE=""
DELAY=0.1
BYPASS_PROMPT=false
CURRENT_COUNT=0
usage() {
echo "Usage: $0 [-f] [-y] [-d seconds]"
echo " -f Save results to ${TIMESTAMP}_vault_assessment.txt"
echo " -y Bypass the confirmation prompt (Yes to all)"
echo " -d seconds Set custom API delay in seconds [Default: 0.1s]"
exit 1
}
while getopts "fyd:" opt; do
case $opt in
f) OUTPUT_FILE="${TIMESTAMP}_vault_assessment.txt" ;;
y) BYPASS_PROMPT=true ;;
d) DELAY=$OPTARG ;;
*) usage ;;
esac
done
echo "âŗ Pre-scanning environment for namespace count..."
# Queue-based non-recursive scan for maximum compatibility
ALL_NS=("")
QUEUE=("")
while [ ${#QUEUE[@]} -gt 0 ]; do
CURRENT_SCAN_NS="${QUEUE[0]}"
QUEUE=("${QUEUE[@]:1}") # Pop from queue
export VAULT_NAMESPACE="$CURRENT_SCAN_NS"
CHILDREN=$(vault namespace list -format=json 2>/dev/null | jq -r '.[]' || echo "")
for CHILD in $CHILDREN; do
FULL_PATH="${CURRENT_SCAN_NS}${CHILD}"
ALL_NS+=("$FULL_PATH")
QUEUE+=("$FULL_PATH")
done
done
TOTAL_NS=${#ALL_NS[@]}
unset VAULT_NAMESPACE
echo "------------------------------------------------"
echo "đ Assessment Configuration:"
echo "đ Total namespaces to check: $TOTAL_NS"
echo "âąī¸ Throttling: ${DELAY} seconds delay per namespace"
if [[ -n "$OUTPUT_FILE" ]]; then
echo "đž Output file: $OUTPUT_FILE"
fi
echo "------------------------------------------------"
if [ "$BYPASS_PROMPT" = false ]; then
read -p "Do you want to proceed with the assessment? (y/n): " confirm
if [[ $confirm != [yY] && $confirm != [yY][eE][sS] ]]; then
echo "â Assessment aborted by user."
exit 0
fi
fi
assess_all() {
local current_ns="$1"
export VAULT_NAMESPACE="$current_ns"
((CURRENT_COUNT++))
local progress="[$CURRENT_COUNT/$TOTAL_NS]"
sleep $DELAY
local engines=$(vault secrets list -format=json 2>/dev/null | jq -r 'to_entries[] | select(.value.type=="transform" or .value.type=="kmip" or .value.type=="keymgmt") | "\(.key)|\(.value.type)"')
if [[ -n "$engines" ]]; then
echo "$progress Namespace: [${current_ns:-root}]"
echo "$engines" | while IFS='|' read -r p t; do
local et=0; local label=""; local builtins=0
case "$t" in
transform)
label="custom items"
local rc=$(vault list -format=json "${p}role" 2>/dev/null | jq '. | length' || echo 0)
local tc=$(vault list -format=json "${p}transformation" 2>/dev/null | jq '. | length' || echo 0)
local all_ac=$(vault list -format=json "${p}alphabet" 2>/dev/null | jq '. | length' || echo 0)
local custom_ac=$(vault list -format=json "${p}alphabet" 2>/dev/null | jq -r '.[]' | grep -v "builtin/" | wc -l | tr -d ' ')
et=$((rc + tc + custom_ac)); builtins=$((all_ac - custom_ac)) ;;
kmip)
label="scopes/clients"
local sc=$(vault list -format=json "${p}scope" 2>/dev/null | jq '. | length' || echo 0)
local cc=$(vault list -format=json "${p}client" 2>/dev/null | jq '. | length' || echo 0)
et=$((sc + cc)) ;;
keymgmt)
label="keys/providers"
for sub in "key" "kms" "provider"; do
local c=$(vault list -format=json "${p}${sub}" 2>/dev/null | jq '. | length' || echo 0)
et=$((et + c))
done ;;
esac
if [[ "$et" -gt 0 ]]; then
echo " â ī¸ CRITICAL: [/$p] is ACTIVE ($et $label found)"
elif [[ "$builtins" -gt 0 ]]; then
echo " âšī¸ [/$p] is EMPTY ($builtins built-ins detected)"
else
echo " âšī¸ [/$p] is EMPTY"
fi
done
else
echo "$progress Namespace: [${current_ns:-root}] - No ADP engines."
fi
local children=$(vault namespace list -format=json 2>/dev/null | jq -r '.[]' || echo "")
for child in $children; do
assess_all "${current_ns}${child}"
done
}
# Execute
if [[ -n "$OUTPUT_FILE" ]]; then
assess_all "" | tee "$OUTPUT_FILE"
echo "------------------------------------------------"
echo "â
Assessment Complete. Results: $OUTPUT_FILE"
else
assess_all ""
echo "------------------------------------------------"
echo "â
Assessment Complete."
echo "đĄ TIP: Use -f to save to file, -d to adjust delay, and -y to skip prompt."
fi
unset VAULT_NAMESPACE
EOFStep 3: Make Executable & Run
chmod +x vault_adp_check.sh
./vault_adp_check.shInterpreting Results
| Result | Status | Impact |
|---|---|---|
| â ī¸ CRITICAL: ACTIVE | Custom configurations discovered. | ADP License Required. New license must include ADP. |
| âšī¸ EMPTY | Engine enabled but inactive. | Safe. Can proceed with a standard license. |
Script Flags and Usage
| Flag | Description | Default |
|---|---|---|
-f | Save output to a timestamped .txt file. | Disabled |
-y | Bypass the "y/n" prompt (useful for automation). | Disabled |
-d | Set throttle delay (in seconds) between namespace scans. | 0.1s |
Usage Examples:
Standard run with report:
./vault_adp_check.sh -fHigh-performance throttle (for 1,000+ namespaces):
./vault_adp_check.sh -f -d 0.5Automation-friendly (no prompts):
./vault_adp_check.sh -f -y
Additional Information
Technical Impact: If an ACTIVE engine loses its license, the data remains encrypted but becomes inaccessible for
encode,decode, orsignoperations.Support: If active ADP engines are found and the new license does not support them, contact your HashiCorp Account Team to discuss migration or license adjustments.
Troubleshooting
403 Forbidden: Ensure your
VAULT_TOKENhas a policy that allowsreadandlistonsys/mountsandsys/namespaces.Command not found (jq): This assessment relies on
jqfor JSON processing. You can install it viasudo yum install jqorsudo apt-get install jq.Accidental Installation (Rollback): If a non-ADP license is applied accidentally and services break, you can restore functionality by re-applying the previous (even if expired) license using:
vault write sys/license "text=$(cat old_license.hclic)"Note: An expired license with the correct features is often better than a valid license with the wrong features during an emergency.