Skip to main content
The Infisical PKCS#11 module is a small native library (.so, .dylib, or .dll) that exposes your Infisical Signers to any tool that supports the PKCS#11 v2.40 standard. Tools like jarsigner, osslsigncode, cosign, apksigner, openssl, and gpg work without modification. They make their usual PKCS#11 calls; the module forwards them to Infisical and returns the signature.
Signing on Windows with signtool? Use the Windows KSP instead.

Before you start

You authenticate as a member of the Signer, using either a Machine Identity or your own Infisical access token. To use a Machine Identity, set it up once:
  1. Create a Machine Identity and enable Universal Auth on it, then copy its Client ID and Client Secret. The module uses these to authenticate, and you will set them in Configuration below.
  2. Add the identity to the Signer with the Administrator or Operator role, from the Signer’s Members tab. Auditors cannot sign.
  3. If the Signer has an approval policy, get active signing access before signing (or use Automatic Signing Access Requests).
To sign as yourself instead, use your own access token (see Configuration). You still need to be a member of the Signer with the Administrator or Operator role.
The Signer itself is created by a Product Admin. If you do not have one yet, create it first.

Installation

Grab the pre-built binary for your platform from the releases page: Drop the binary in a known location:

Building from source

If you want to build instead of downloading, you need Go 1.24+ and a C compiler:
The output binary lands in the current directory.

Configuration

The module reads its config from /etc/infisical/pkcs11.conf (override the path with INFISICAL_CONFIG):
Then export the authentication credentials as environment variables:
Credentials can also live in the config file under auth.client_id and auth.client_secret, but environment variables are strongly recommended so secrets don’t end up in version control, backups, or shared logs.

Sign with an access token instead

Instead of a machine identity, you can hand the module an Infisical access token directly, either your own or a machine identity’s. Set INFISICAL_TOKEN and the module uses it as-is:
JWT tokens expire, so this access is temporary. The module does not refresh the token; once it expires, signing fails until you supply a new one. This is handy for signing as yourself or for a quick one-off; for unattended or CI/CD signing use a machine identity with Universal Auth (client ID and secret), which the module re-authenticates automatically.
If you put the config somewhere other than /etc/infisical/pkcs11.conf:

Configuration reference

Environment variable reference

Environment variables always take precedence over values in the configuration file.

Verify the Module

Use pkcs11-tool (from OpenSC: brew install opensc or apt install opensc) to confirm everything is wired up.
You should see one slot per Signer your machine identity is a member of:
To list the objects (private key, public key, X.509 cert) in a slot:
A quick smoke-test sign:
If the Signer has an approval policy and you don’t have active access, the sign call is rejected with CKR_GENERAL_ERROR and the module logs a “signing requires approval” line. See Automatic Signing Access Requests below to make this seamless.

Automatic Signing Access Requests

When a Signer has a policy attached, sign calls without active access normally fail. The module can automatically open a signing request for you on the first denied call. You just need to add an approval block to the config:
  • signing_duration requests an access window of this duration (30m, 8h, 2d; range 1m to 30d).
  • signing_count requests access good for this many signing operations.
Set one or both depending on what the Signer’s policy expects. The values are capped at the policy’s maxWindow / maxSignings.
The first sign call still fails until an approver approves the auto-created request. Once approved, retry the sign and it succeeds. The module logs that the request was created so you know what to do.

Example CI workflow

  1. Pipeline calls jarsigner (or any PKCS#11 tool) against the Infisical module.
  2. No active access exists, so Infisical returns 403.
  3. The module sees the approval block and auto-creates a signing request with the configured duration and count.
  4. Pipeline fails on this run.
  5. A reviewer approves the request in the Infisical UI.
  6. Pipeline is rerun and the sign call succeeds under the freshly-issued access record.
For fully unattended CI, have an Administrator pre-approve signing access via Pre-approve signing before the pipeline runs.

Troubleshooting

Turn on debug logging in the config first. It’ll usually tell you exactly what went wrong:
Almost always one of three things:
  1. The machine identity is not a member of any Signer in your organization. Have an Admin add it to a Signer (any role works).
  2. The credentials are wrong. Check the auth token line in the log; if it says 401, regenerate the universal-auth client secret.
  3. The server_url points at the wrong instance. The module log line Initialized with universal-auth (auto-authenticated) confirms a successful login.
Almost always means the server rejected the sign. Common reasons (visible in the debug log):
  • No active access. The Signer has an approval policy and you don’t yet have access. See Request to sign.
  • Access expired or signatures exhausted. Request access again.
  • Signer is Disabled. Re-enable it in the UI.
  • Certificate expired. Issue a new one or wait for auto-renewal.
Network or TLS problem. Check server_url, confirm the host is reachable from the machine, and verify TLS. If you self-host with a private CA, set tls.ca_cert_path to its bundle. As a last resort during local dev, you can set tls.skip_verify: true (never in production).
The module rejects any other scheme (file://, gopher://, etc.) to prevent credentials being sent to unintended targets. Make sure your server_url starts with http:// or https://.
The Signer is in Pending or Failed status; no certificate has been issued yet. Check the Signer’s status in the UI; for external CAs (AWS Private CA, Azure AD CS), issuance can take minutes. Once the Signer becomes Active, the cert is fetched automatically.

What’s next

Sign JARs

jarsigner with the PKCS#11 module.

Sign containers

cosign sign with Infisical.

Sign Windows binaries

osslsigncode for .exe / .dll / .msi.

Sign APKs

apksigner for Android.

Sign with OpenSSL

Raw signing primitives.

Sign with GPG

Use GPG via the PKCS#11 module.