Skip to content

Management-Add for PFX/JKS/P12 KV stores fails 403 — Vault 'patch' capability required for passphrase write; error message hides HTTP status #39

Description

@spbsoluble

Summary

Two related issues found during lab testing:

  1. Config/docs gap: VaultSharp's PatchSecretAsync uses HTTP PATCH for passphrase writes on PFX/JKS/P12 KV stores. Vault/OpenBao requires an explicit patch capability in the policy — it is not implied by create or update. The typical example policy in documentation omits patch, causing all file-format Management-Add jobs to fail with 403.

  2. Code quality: When this 403 occurs, the job completion message surfaces only the raw OpenBao response body ({"errors":[]}) with no HTTP status code. This makes it nearly impossible to diagnose from the Command job history without inspecting UO logs.

Environment

  • Extension version: latest main
  • Command version: v25.5.1
  • OpenBao (Vault-compatible) — KV v2 engine

Symptom

Management-Add jobs for HCVKVPFX, HCVKVJKS, HCVKVP12 complete with CompletedWillRetry/Failure:

An error occured while adding lab-hcv-pfx to stores/pfx:
One or more errors occurred. ({"errors":[]}\n) - {"errors":[]}\n.
Certificate thumbprint: 5C125FF80A2B7D1A4D423D688526E1301D659C65.

HCVKVPEM Management-Add succeeds because PEM stores use WriteSecretAutoAsync (HTTP POST) throughout — they never call PatchSecretAutoAsync.

Root Cause

HcvKeyValueClient.CreateNewFileStore writes the passphrase at line ~197:

await PatchSecretAutoAsync(pathToWritePassphrase, passphraseSecretContent, _mountPoint);

PatchSecretAutoAsync calls _vaultClient.V1.Secrets.KeyValue.V2.PatchSecretAsync(...), which VaultSharp implements as PATCH /v1/{mount}/data/{path} with Content-Type: application/merge-patch+json.

Vault/OpenBao requires an explicit patch capability for HTTP PATCH (separate from create/update).

Fix

1. Document the required patch capability

Add to the README/documentation:

path "secret/data/stores/*" {
  capabilities = ["create", "read", "update", "patch", "delete", "list"]
}

2. Improve error message to include HTTP status code

In PatchSecretAutoAsync (or the Management job handler), when a VaultApiException is caught, include ex.StatusCode in the propagated exception message so the job completion message visible in Command includes the HTTP status code (403, 404, 405, etc.) rather than just the raw body.

Example improvement:

throw new Exception($"Vault returned HTTP {ex.StatusCode} for {path}: {ex.Message}. API errors: [{string.Join(", ", ex.ApiErrors ?? new List<string>())}]", ex);

Verification

# Without patch capability — returns 403:
curl -X PATCH https://openbao.lab.local/v1/secret/data/stores/test \
  -H "X-Vault-Token: $UO_TOKEN" \
  -H "Content-Type: application/merge-patch+json" \
  -d '{"data":{"passphrase":"x"}}'
# {"errors":["1 error occurred:\n\t* permission denied\n\n"]}

# With patch capability added — returns 200.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions