Query: API Endpoint for Updating PBS Fingerprint

gronax

New Member
Sep 19, 2023
3
0
1
Hi All,

I'm currently working on automating the process of updating the fingerprint for a PBS storage in Proxmox VE 8.2.2. However, I'm encountering difficulties finding the correct API endpoint for this operation.

Here's what I've tried so far:

1. I can successfully retrieve the storage configuration using:
GET /api2/json/nodes/{node}/storage/{storageId}

2. When attempting to update the fingerprint using:
PUT /api2/json/nodes/{node}/storage/{storageId}
with the data: `fingerprint={new_fingerprint}`

I receive a 501 Not Implemented error.

I've verified that my API token has the necessary permissions (Datastore.Audit, Datastore.Allocate, and Sys.Modify).

My questions are:

1. Is there a specific API endpoint for updating the PBS fingerprint in Proxmox VE 8.2.2?
2. If not, is this functionality planned for future releases?
3. Are there any workarounds or alternative methods to programmatically update the PBS fingerprint?

Any help is greatly appreciated. Thanks in advance!

Cheers,
Simon.
 
Beautiful. Thank you Dietmar.

For reference, the solution was to HTTP put /storage/${PVE_STORAGE_ID} with the content "fingerprint=${NEW_FINGERPRINT}"

Here is my full script that I run on PBS as a cronjob to update the PVE storage fingerprint when the PBS ACME certificate renews.

Code:
#!/bin/bash
################################################################################
# Script Name: update_pbs_fingerprint.sh
#
# Description:
# This script updates the fingerprint of a Proxmox Backup Server (PBS) datastore
# in Proxmox Virtual Environment (Proxmox VE). The fingerprint is refreshed daily
# due to the PBS using ACME certificates, which causes the Proxmox VE datastore
# to fail validation unless updated. The script fetches the latest PBS certificate
# fingerprint, updates the corresponding storage configuration in Proxmox VE,
# and verifies the update was successful.
#
# Environment:
# - Proxmox VE (PVE) Host: The server where the Proxmox VE instance is running.
# - Proxmox Backup Server (PBS): The server where the Proxmox Backup Server instance is running.
#
# Environment Variables:
# - PBS_HOST: The hostname or IP address of the Proxmox Backup Server (PBS).
# - PVE_HOST: The hostname or IP address of the Proxmox VE server.
# - PVE_API_TOKEN: The API token used to authenticate against the Proxmox VE API.
# - PVE_STORAGE_ID: The ID of the storage in Proxmox VE that points to the PBS datastore.
#
# Prerequisites:
# 1. Ensure that you have a valid API token created on the Proxmox VE server. The token must
#    have sufficient privileges to update storage configurations.
# 2. The API token format is "user@realm!tokenname=API-Token-ID". Replace this
#    with your actual API token.
# 3. The Proxmox Backup Server must be configured to use an ACME certificate or any other
#    mechanism that refreshes its certificate periodically.
# 4. OpenSSL, curl, and jq must be installed on the system running this script.
#
# How it Works:
# 1. The script connects to the PBS server over port 8007 and fetches the current certificate
#    fingerprint using OpenSSL.
# 2. It checks the current storage configuration and fingerprint in Proxmox VE.
# 3. If the fingerprint needs updating, it sends a PUT request to the Proxmox VE API.
# 4. The script then verifies the update by querying the Proxmox VE API and comparing the
#    returned fingerprint with the one we just set.
# 5. If the update is successful and verified, the script outputs a success message;
#    otherwise, it reports an error.
#
# Execution:
# This script is intended to run on the Proxmox VE server, but it can be executed from any
# server that has access to both the PBS and PVE hosts, provided that the API token is valid
# and the required commands (openssl, curl, jq) are available.
#
# Note:
# No restart of Proxmox VE services is required after updating the fingerprint.
# The new fingerprint takes effect immediately.
################################################################################

# Default debug mode off
DEBUG=0

# Function to log information
log_info() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO]: $1"
}

# Function to log warnings
log_warn() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [WARN]: $1"
}

# Function to log errors
log_error() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR]: $1" >&2
}

# Function to log debug information
log_debug() {
    if [ $DEBUG -eq 1 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') [DEBUG]: $1"
    fi
}

# Function to check if a command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Parse command-line arguments
while getopts "d" opt; do
    case $opt in
        d)
            DEBUG=1
            log_info "Debug mode enabled."
            ;;
        *)
            log_error "Invalid option: -$OPTARG"
            exit 1
            ;;
    esac
done

# Check for required commands
for cmd in openssl curl jq; do
    if ! command_exists "$cmd"; then
        log_error "Required command '$cmd' not found. Please install it and try again."
        exit 1
    fi
done

# Set variables
PBS_HOST="pbs.com"
PVE_HOST="pve.com"
PVE_API_TOKEN="pbs@pam!update-pbs-fingerprint=xxxxxxxxxxxxxxxxxxxxxxxx"
PVE_STORAGE_ID="pbs"

# Validate environment variables
for var in PBS_HOST PVE_HOST PVE_API_TOKEN PVE_STORAGE_ID; do
    if [ -z "${!var}" ]; then
        log_error "$var is not set or is empty"
        exit 1
    fi
done

# Function to make API calls and display results
make_api_call() {
    local method=$1
    local endpoint=$2
    local data=$3
    local response

    log_debug "Making $method request to $endpoint"
    response=$(curl -s -X $method "https://${PVE_HOST}:8006/api2/json$endpoint" \
        -H "Authorization: PVEAPIToken=${PVE_API_TOKEN}" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        ${data:+-d "$data"})

    log_debug "Response: $response"
    echo "$response" | jq .
}

# Fetch the new fingerprint
NEW_FINGERPRINT=$(echo | openssl s_client -connect ${PBS_HOST}:8007 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256 | cut
-d '=' -f 2)

# Check OpenSSL connection and fingerprint extraction
if [ $? -ne 0 ] || [ -z "$NEW_FINGERPRINT" ]; then
    log_error "Unable to connect to PBS or extract fingerprint from the certificate"
    exit 1
fi

# Validate fingerprint format (assuming SHA256 fingerprint format)
if ! [[ $NEW_FINGERPRINT =~ ^([0-9A-F]{2}:){31}[0-9A-F]{2}$ ]]; then
    log_error "Extracted fingerprint does not match expected format"
    exit 1
fi

log_info "New fingerprint: ${NEW_FINGERPRINT}"

# Check current storage configuration
log_info "Checking current storage configuration..."
CURRENT_CONFIG=$(make_api_call GET "/storage/${PVE_STORAGE_ID}")
log_debug "Current config response: $CURRENT_CONFIG"

CURRENT_FINGERPRINT=$(echo "$CURRENT_CONFIG" | jq -r '.data.fingerprint // empty' 2>/dev/null)
if [ $? -ne 0 ]; then
    log_error "Error parsing current configuration JSON. Raw response:"
    echo "$CURRENT_CONFIG"
    exit 1
fi

log_info "Current fingerprint: ${CURRENT_FINGERPRINT}"

if [ "$CURRENT_FINGERPRINT" = "$NEW_FINGERPRINT" ]; then
    log_info "Fingerprint is already up to date. No changes needed."
    exit 0
fi

# Attempt to update the fingerprint
log_info "Attempting to update the fingerprint..."
UPDATE_RESPONSE=$(make_api_call PUT "/storage/${PVE_STORAGE_ID}" "fingerprint=${NEW_FINGERPRINT}")
log_debug "Update response: $UPDATE_RESPONSE"

# Check if the update was successful
if echo "$UPDATE_RESPONSE" | grep -q '"data":null'; then
    log_error "Failed to update the fingerprint. API returned null data."
    exit 1
fi

# Verify the fingerprint update
log_info "Verifying the fingerprint update..."
VERIFY_CONFIG=$(make_api_call GET "/storage/${PVE_STORAGE_ID}")
log_debug "Verify config response: $VERIFY_CONFIG"

UPDATED_FINGERPRINT=$(echo "$VERIFY_CONFIG" | jq -r '.data.fingerprint // empty' 2>/dev/null)
if [ $? -ne 0 ]; then
    log_error "Error parsing verification configuration JSON. Raw response:"
    echo "$VERIFY_CONFIG"
    exit 1
fi

log_info "Updated fingerprint: ${UPDATED_FINGERPRINT}"

if [ "$UPDATED_FINGERPRINT" = "$NEW_FINGERPRINT" ]; then
    log_info "Fingerprint successfully updated and verified."
else
    log_error "Fingerprint update failed. Current fingerprint does not match the new fingerprint."
    log_error "Current fingerprint: ${UPDATED_FINGERPRINT}"
    log_error "Expected fingerprint: ${NEW_FINGERPRINT}"
    exit 1
fi

log_info "Script execution completed successfully."
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!