Managed Keys let Stronghold use cryptographic keys stored in an external trusted system, such as an HSM or external KMS, without storing the private key material inside Stronghold itself.

This approach is useful when:

  • private keys must remain outside Stronghold;
  • signing or encryption operations must be performed by an external system;
  • security or compliance requirements prohibit exporting key material.

In Stronghold, a managed key is a named record managed through the sys/managed-keys/<TYPE>/<NAME> API.

How it works

Stronghold stores the configuration needed to access an external key, but not the private key itself. When a secrets engine needs to perform signing, signature verification, encryption, or decryption, it calls the corresponding managed key, which then delegates the operation to the external backend.

This means:

  • key material remains in the external system;
  • Stronghold uses the managed key as an abstraction over the external backend;
  • multiple managed keys can be configured for the same backend if you need different keys or different access policies.

Supported backends

Stronghold supports the following managed key types:

  • pkcs11
  • yandexcloudkms

pkcs11

The pkcs11 type is used for HSMs and PKCS#11-compatible libraries. A managed key of this type references a previously defined kms_library "pkcs11" stanza in Stronghold server configuration.

A typical workflow is:

  • configure kms_library "pkcs11" in the server configuration;
  • register a managed key through sys/managed-keys/pkcs11/<NAME>;
  • optionally verify key access using test/sign;
  • allow the key for the required mount path.

Example:

stronghold write sys/managed-keys/pkcs11/my-hsm-key library=softhsm token_label=managed-keys pin=1234 key_label=my-signing-key usages=sign,verify

pkcs11 parameters

ParameterDescription
libraryRequired. Name of the kms_library "pkcs11" stanza from the server configuration
slotSlot number (decimal string). Exactly one of slot and token_label must be specified
token_labelToken label. Exactly one of slot and token_label must be specified
pinRequired. PIN for access to the token. It is never returned when reading the key (the value is redacted)
key_label, key_idLabel or identifier of the key in the HSM. At least one of them is required. If the key does not exist and allow_generate_key=true, the key is generated with the key_label label
mechanismPKCS#11 mechanism of the key. It must be specified in hexadecimal form with the 0x prefix, for example 0x1041
curveFor ECDSA — the curve (P256, P384, or P521) when generating a key. For GOST mechanisms — the key profile (see below)
key_bitsFor RSA — the key length when generating a key (2048, 3072, or 4096). For AES, only 256 is allowed when generating a key
force_rw_sessionForces read/write sessions, to work around some HSMs. Default is false
max_parallelMaximum number of concurrent operations submitted to the HSM
usagesComma-separated list of allowed operations: encrypt, decrypt, sign, verify, wrap, unwrap. Default is sign,verify

If mechanism is not specified, the key can only be used with an existing key in the HSM, and generation (allow_generate_key=true) is not available.

The pkcs11 type is available in Stronghold EE.

Supported mechanisms

MechanismValueKey typeOperations
CKM_ECDSA0x1041ECDSA (P256, P384, P521)sign, verify
CKM_RSA_PKCS0x1RSA (2048, 3072, 4096)sign, verify (PKCS#1 v1.5 or PSS), encrypt, decrypt, wrap, unwrap
CKM_RSA_PKCS_OAEP0x9RSAsame
CKM_RSA_PKCS_PSS0xdRSAsame
CKM_GOSTR34100x1201GOST R 34.10-2012, 256 bits (or GOST 2001)sign, verify
CKM_GOSTR3410_5120xd4321006GOST R 34.10-2012, 512 bitssign, verify
CKM_AES_GCM, CKM_AES_CBC, CKM_AES_CBC_PAD0x1087, 0x1082, 0x1085AES (generated keys are 256-bit)encrypt, decrypt
CKM_KUZNECHIK_CTR_ACPKM, CKM_KUZNECHIK_MGM0xd4321032, 0xd432102dKuznechikencrypt, decrypt

RSA and PSS signatures

For RSA keys, the three RSA mechanisms (CKM_RSA_PKCS, CKM_RSA_PKCS_OAEP, CKM_RSA_PKCS_PSS) only select the RSA key: the signature scheme (PKCS#1 v1.5 or RSA-PSS) is chosen by the calling secrets engine for each operation, as in Go’s crypto/rsa. RSA-PSS is used with the salt length equal to the hash length. The signature is verified locally with the public key exported from the HSM.

  • In PKI, RSA-PSS is requested with the use_pss parameter (when generating a root or intermediate CA, signing, and in roles). If the managed key supports only PSS signatures, set revocation_signature_algorithm for the issuer to one of the PSS algorithms; otherwise, building the CRL fails with an error that mentions PSS.
  • In test/sign, RSA-PSS is requested with the use_pss=true parameter (see Basic operations).

GOST keys

GOST keys in the HSM are used only for signing and signature verification. The mechanism determines the key size:

  • CKM_GOSTR3410 — 256-bit keys;
  • CKM_GOSTR3410_512 — 512-bit keys.

The curve parameter sets the key generation profile and must match the mechanism:

  • gost2001 or gost2012-256 for CKM_GOSTR3410;
  • gost2012-512 for CKM_GOSTR3410_512.

If curve is omitted, the profile is selected based on the mechanism. The Streebog hash algorithm is used for signing: streebog-256 for 256-bit keys and streebog-512 for 512-bit keys. Signature verification is performed by the HSM. When a GOST key is used in pki, the signature algorithm is selected based on the type of the key public part. In transit, a managed GOST key accepts only the Streebog hash algorithm matching the key size.

Example of registering a GOST key:

stronghold write sys/managed-keys/pkcs11/gost-ca-key library=rutoken token_label=managed-keys pin=12345678 key_label=my-gost-key mechanism=0x1201 curve=gost2012-256 usages=sign,verify

yandexcloudkms

The yandexcloudkms type is used for integration with Yandex Cloud KMS.

Its configuration uses:

  • kms_key_id
  • oauth_token or service_account_key_json
  • endpoint when needed

For authentication to Yandex Cloud KMS, Stronghold can use one of the following options:

  • oauth_token
  • service_account_key_json
  • the service account attached to the virtual machine in Yandex Cloud

If neither oauth_token nor service_account_key_json is provided, Stronghold attempts to use the virtual machine service account through the standard instance credentials flow. This is similar to common Vault patterns where cloud KMS integrations can rely on the identity of the running VM instance.

Example:

stronghold write sys/managed-keys/yandexcloudkms/my-yc-key kms_key_id=<KMS_KEY_ID> oauth_token=<OAUTH_TOKEN> usages=sign,verify

Where <KMS_KEY_ID> is the Yandex Cloud KMS key ID, and <OAUTH_TOKEN> is the Yandex Cloud OAuth token.

Example using the virtual machine service account:

stronghold write sys/managed-keys/yandexcloudkms/my-yc-key kms_key_id=<KMS_KEY_ID> usages=sign,verify

The oauth_token and service_account_key_json parameters are mutually exclusive. If one of them is specified, it is used explicitly for authentication to Yandex Cloud.

For yandexcloudkms, the set of allowed operations depends on the key itself and its configuration. If the managed key is going to be used by pki or ssh, it must support signing. For transit, the required operations depend on the selected usage scenario.

Which secrets engines can use Managed Keys

In Stronghold, managed keys can be used by:

  • SSH
  • PKI
  • Transit

SSH

The SSH secrets engine can use a managed key as its certificate authority key and use it to sign SSH certificates.

This is useful when the SSH CA key must remain in an external HSM or KMS.

PKI

The PKI secrets engine can use a managed key for root and intermediate CA generation and for certificate signing.

This is one of the primary managed key use cases in Stronghold. For PKI, it is also important to allow the managed key for the specific PKI mount if the key was not created with any_mount=true.

Example:

stronghold secrets tune -allowed-managed-keys=my-hsm-key pki/

Transit

The Transit secrets engine can use a managed key as an external cryptographic key.

Depending on backend capabilities and the key type, this can allow:

  • signing;
  • signature verification;
  • encryption;
  • decryption.

For Transit, the managed key is specified when creating or rotating a transit key.

Namespaces and scope

A managed key is bound to a specific namespace. The secrets engine that uses the key must exist in the same namespace as the managed key itself.

If the key is not created with any_mount=true, you must explicitly allow its use for a given mount path.

Basic operations

List managed keys of a given type:

stronghold list sys/managed-keys/pkcs11

Read key configuration:

stronghold read sys/managed-keys/pkcs11/my-hsm-key

Verify key accessibility with a test signature:

stronghold write sys/managed-keys/pkcs11/my-hsm-key/test/sign

The test/sign request accepts optional parameters:

  • hash_algorithm — hash algorithm for the test signature. By default, sha2-256 is used; for pkcs11 keys with GOST mechanisms, streebog-256 or streebog-512 is used, depending on the mechanism.
  • use_pss — for RSA keys, sign using RSA-PSS. For RSA keys in yandexcloudkms, which sign only with PSS, it is enabled by default.

Delete a managed key:

stronghold delete sys/managed-keys/pkcs11/my-hsm-key

Practical recommendations

  • Use pkcs11 when keys live in a local or network-attached HSM exposed through a PKCS#11 library.
  • Use yandexcloudkms when keys are managed in Yandex Cloud KMS.
  • Restrict usages to the minimum required operations.
  • If the key should not be available to every mount, do not enable any_mount and configure allowed-managed-keys explicitly.
  • Before attaching a key to pki, ssh, or transit, verify it with test/sign or another appropriate validation flow.