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.
Before installing the module, ensure a Product Admin has created a Signer and added the machine identity (or user) you plan to authenticate as. If the Signer has an approval policy, you’ll also need active access.

Installation

Grab the pre-built binary for your platform from the releases page:
PlatformFile
Linux x86_64libinfisical-pkcs11.so
Linux ARM64libinfisical-pkcs11.so
macOS x86_64libinfisical-pkcs11.dylib
macOS ARM64libinfisical-pkcs11.dylib
Windows x86_64libinfisical-pkcs11.dll
Drop the binary in a known location:
# Linux
sudo cp libinfisical-pkcs11.so /usr/local/lib/
sudo chmod 755 /usr/local/lib/libinfisical-pkcs11.so

# macOS
sudo cp libinfisical-pkcs11.dylib /usr/local/lib/
sudo chmod 755 /usr/local/lib/libinfisical-pkcs11.dylib

Building from source

If you want to build instead of downloading, you need Go 1.24+ and a C compiler:
git clone https://github.com/Infisical/infisical-pkcs-11.git
cd infisical-pkcs-11
make build
The output binary lands in the current directory.

Configuration

The module reads its config from /etc/infisical/pkcs11.conf (override the path with INFISICAL_PKCS11_CONFIG):
{
  "server_url": "https://app.infisical.com",
  "log_level": "info"
}
Then export the authentication credentials as environment variables:
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="<machine-identity-client-id>"
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="<machine-identity-client-secret>"
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.
If you put the config somewhere other than /etc/infisical/pkcs11.conf:
export INFISICAL_PKCS11_CONFIG=/path/to/your/pkcs11.conf

Configuration reference

FieldRequiredDefaultDescription
server_urlYesNoneInfisical server URL. Must use http:// (local dev) or https://.
auth.methodNouniversal-authAuthentication method.
auth.client_idNoNoneMachine identity client ID. Prefer the env var.
auth.client_secretNoNoneMachine identity client secret. Prefer the env var.
tls.ca_cert_pathNoNoneCustom CA bundle path for self-hosted Infisical with a private CA.
tls.skip_verifyNofalseSkip TLS verification (development only, never enable in production).
cache.token_ttl_secondsNo300How long the auth token is cached.
cache.cert_ttl_secondsNo3600How long fetched certificates are cached.
cache.signer_ttl_secondsNo300How long the list of Signers is cached.
approval.signing_durationNoNoneAuto-request signing access with this window when no active access exists. Valid range: 1m to 30d.
approval.signing_countNoNoneAuto-request signing access for this many signatures when no active access exists.
log_levelNoinfoOne of trace, debug, info, warn, error.
log_fileNostderrOptional path to a log file.

Environment variable reference

VariableDescription
INFISICAL_UNIVERSAL_AUTH_CLIENT_IDMachine identity client ID. Overrides config.
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRETMachine identity client secret. Overrides config.
INFISICAL_PKCS11_SERVER_URLOverride server_url.
INFISICAL_PKCS11_CONFIGPath to the config file (default /etc/infisical/pkcs11.conf).
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.
pkcs11-tool \
  --module /usr/local/lib/libinfisical-pkcs11.so \
  --list-slots
You should see one slot per Signer your machine identity is a member of:
Available slots:
Slot 0 (0x0): mobile-app-prod
  token label        : mobile-app-prod
  token manufacturer : Infisical
  token model        : Code Signing
  ...
Slot 1 (0x1): release-signer
  ...
To list the objects (private key, public key, X.509 cert) in a slot:
pkcs11-tool \
  --module /usr/local/lib/libinfisical-pkcs11.so \
  --slot 0 \
  --list-objects
A quick smoke-test sign:
echo "hello" > /tmp/payload.bin
pkcs11-tool \
  --module /usr/local/lib/libinfisical-pkcs11.so \
  --slot 0 \
  --sign --mechanism SHA256-RSA-PKCS \
  --input-file /tmp/payload.bin \
  --output-file /tmp/payload.sig
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:
{
  "server_url": "https://app.infisical.com",
  "approval": {
    "signing_duration": "8h",
    "signing_count": 10
  }
}
  • 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:
{
  "log_level": "debug",
  "log_file": "/tmp/infisical-pkcs11.log"
}
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.