Version: 1.4.2
Last Updated: April 2026
Classification: Public
Related: Security Hardening, HashiCorp Vault Integration
VaultSigningProvider is a signing-only provider that uses HashiCorp Vault Transit Engine for cryptographic signature operations. It does NOT support key management operations (getKey, rotateKey, listKeys, etc.).
- ✅ Sign data using Vault Transit Engine keys
- ✅ Verify signatures using Vault Transit Engine
- ❌ NOT for key extraction - keys never leave Vault
- ❌ NOT for key management - use Vault API or VaultKeyProvider
VaultSigningProvider::Config config;
config.vault_addr = "https://vault.example.com:8200";
config.vault_token = "s.xxxxx";
config.transit_mount = "transit";
VaultSigningProvider provider(config);
// ✅ Signing works
std::vector<uint8_t> data = {1, 2, 3, 4};
SigningResult result = provider.sign("my-signing-key", data);// ❌ Key operations throw KeyOperationException with helpful error messages
try {
auto key = provider.getKey("my-key"); // THROWS
} catch (const KeyOperationException& e) {
// Error: "VaultSigningProvider: getKey() not implemented - signing-only provider.
// Use VaultKeyProvider for key management operations.
// See: docs/security/VAULT_SIGNING_PROVIDER.md"
}
// ❌ These also throw with similar messages:
provider.rotateKey("my-key"); // THROWS
provider.listKeys(); // THROWS
provider.getKeyMetadata("my-key"); // THROWS
provider.deleteKey("my-key", 1); // THROWS
provider.hasKey("my-key"); // THROWS
provider.createKeyFromBytes("k", data); // THROWS-
Keys Never Leave Vault
- Private keys remain in Vault's secure storage
- Only signatures are returned to the application
- Reduces attack surface for key extraction
-
Least Privilege
- Application only needs signing permissions
- No access to key material or management operations
- Follows principle of least privilege
-
Simplified Token Policies
# Vault policy for signing-only access path "transit/sign/my-signing-key" { capabilities = ["update"] } path "transit/verify/my-signing-key" { capabilities = ["update"] }
- ✅ Pro: Enhanced security through limited scope
- ✅ Pro: Clear separation of concerns
- ❌ Con: Cannot be used as a full KeyProvider
- ❌ Con: Requires separate mechanism for key management
Option 1: Use VaultKeyProvider
#include "security/vault_key_provider.h"
VaultKeyProvider::Config config;
config.vault_addr = "https://vault.example.com:8200";
config.vault_token = "s.xxxxx";
config.transit_mount = "transit";
auto provider = std::make_shared<VaultKeyProvider>(config);
// ✅ Supports full KeyProvider interface
auto key = provider->getKey("my-key");
uint32_t new_version = provider->rotateKey("my-key");
auto keys = provider->listKeys();Option 2: Use Vault CLI/API Directly
# Key rotation via Vault CLI
vault write -f transit/keys/my-key/rotate
# List keys
vault list transit/keys
# Get key metadata
vault read transit/keys/my-keyOption 3: Use Cloud KMS
// AWS KMS
#include "security/aws_kms_provider.h"
// Azure Key Vault
#include "security/azure_keyvault_provider.h"
// GCP Cloud KMS
#include "security/gcp_kms_provider.h"VaultSigningProvider is the right choice! It provides:
- Minimal permissions required
- Clear security boundaries
- Simple signing workflow
Set this environment variable to explicitly acknowledge the signing-only limitation:
export THEMIS_VAULT_SIGNING_ONLY=1Purpose:
- Documents intent to use signing-only functionality
- May suppress certain warnings in future versions
- Makes limitation explicit in deployment configuration
# config/security.yaml
vault:
provider: vault_signing
# Vault connection
vault_addr: "https://vault.example.com:8200"
vault_token: "${VAULT_TOKEN}" # Use environment variable
transit_mount: "transit"
# Optional settings
request_timeout_ms: 5000
verify_ssl: true# Required
export THEMIS_VAULT_ADDR="https://vault.example.com:8200"
export THEMIS_VAULT_TOKEN="s.xxxxx"
# Optional
export THEMIS_VAULT_TRANSIT_MOUNT="transit" # default: "transit"
export THEMIS_VAULT_SIGNING_ONLY="1" # acknowledge limitation-
Enable Transit Engine
vault secrets enable transit -
Create Signing Key
vault write -f transit/keys/themis-signing-key \ type=rsa-2048 \ exportable=false
-
Create Token Policy
# signing-policy.hcl path "transit/sign/themis-signing-key" { capabilities = ["update"] } path "transit/verify/themis-signing-key" { capabilities = ["update"] }
-
Generate Application Token
vault token create -policy=signing-policy
- Keys created with
exportable=false - Token policy limited to signing operations only
- Token TTL configured appropriately
- TLS enabled for Vault communication (
verify_ssl: true) - Token stored securely (not in version control)
- Token rotation policy in place
All unsupported operations throw KeyOperationException with descriptive messages:
VaultSigningProvider: getKey() not implemented - signing-only provider.
Use VaultKeyProvider for key management operations.
See: docs/security/VAULT_SIGNING_PROVIDER.md
Error Message Components:
- Provider identification:
VaultSigningProvider: - Specific operation:
getKey() not implemented - Explanation:
signing-only provider - Guidance:
Use VaultKeyProvider for key management operations - Documentation:
See: docs/security/VAULT_SIGNING_PROVIDER.md
TEST(VaultSigningProviderTest, SigningWorks) {
// Set up Vault connection
VaultSigningProvider::Config config;
config.vault_addr = "http://localhost:8200";
config.vault_token = "test-token";
VaultSigningProvider provider(config);
std::vector<uint8_t> data = {1, 2, 3, 4};
SigningResult result = provider.sign("test-key", data);
EXPECT_TRUE(result.signature.size() > 0);
EXPECT_EQ(result.algorithm, "VAULT+TRANSIT");
}
TEST(VaultSigningProviderTest, KeyOperationsThrow) {
VaultSigningProvider::Config config;
VaultSigningProvider provider(config);
EXPECT_THROW(provider.getKey("key"), KeyOperationException);
EXPECT_THROW(provider.rotateKey("key"), KeyOperationException);
EXPECT_THROW(provider.listKeys(), KeyOperationException);
}See: tests/test_vault_signing_provider.cpp
Issue: KeyOperationException: getKey not implemented
- Cause: Attempting to use VaultSigningProvider as a full KeyProvider
- Solution: Use
VaultKeyProviderinstead, or implement key management separately
Issue: Vault not configured: THEMIS_VAULT_ADDR not set
- Cause: Environment variables not set
- Solution: Set
THEMIS_VAULT_ADDRandTHEMIS_VAULT_TOKEN
Issue: Vault request failed: Couldn't connect to server
- Cause: Vault server not reachable
- Solution: Check network connectivity, Vault address, and firewall rules
- NIST SP 800-57: Key management via separate mechanism
- PCI DSS 3.6: Keys protected in Vault (never extracted)
- GDPR Article 32: Cryptographic protection maintained
- ISO 27001 A.10.1.2: Least privilege principle
All signing operations are logged by Vault Transit Engine:
vault audit enable file file_path=/var/log/vault_audit.log
# Review signing operations
vault audit log | grep "transit/sign"VaultSigningProvider is a specialized, security-focused provider for signing operations only:
✅ Use When:
- You need signing operations via Vault Transit
- Keys should never leave Vault
- Minimal permissions are required
❌ Don't Use When:
- You need to extract key material
- You need key management operations
- You need full KeyProvider interface
For full key management, use VaultKeyProvider or cloud KMS alternatives.