Installation PKCS#11 with Docker
This guide explains how to install the Primus PKCS#11 Provider for applications that are deployed in container environments such as Docker Compose or Kubernetes.
This guide assumes that you are already familiar with the traditional, native Linux installation of the Primus PKCS#11 Provider. It also assumes that you know either Docker Compose and/or know how to operate a Kubernetes cluster with Helm.
Overview
The native Linux installation method is interactive.
Administrators manually unpack the archive, edit the config files, and interactively
use the ppin tool to exchange the Setup Password for the Permanent Secret.
This is not suitable for container environments. Instead, the installation must be translated to container concepts.
Recall that a complete Primus PKCS#11 Provider installation consists of the following files
in the locations /usr/local/primus and /etc/primus/.
$ tree -a /usr/local/primus/
/usr/local/primus/
├── bin
│ └── ppin
├── etc
│ ├── .secrets.cfg
│ └── primus.cfg
├── include
│ ├── oasis-pkcs11-v3.2
│ │ ├── pkcs11.h
│ │ ├── pkcs11f.h
│ │ └── pkcs11t.h
│ ├── pkcs11-2.4.0.h
│ ├── pkcs11-2.5.2.h
│ └── pkcs11.h
└── lib
├── libprimusP11.so -> libprimusP11.so.2
├── libprimusP11.so.2 -> libprimusP11.so.2.7.0
└── libprimusP11.so.2.7.0
6 directories, 12 files
$ tree -a /etc/primus/
/etc/primus/
├── .secrets.cfg
└── primus.cfg
1 directory, 2 files
In order to have a working Primus PKCS#11 Provider usable by applications, you need to get at a minimum the following files into the container:
/usr/local/primus/libprimusP11.so(The final .so, either directly or through symlinks.)/etc/primus/.secrets.cfg/etc/primus/primus.cfg
The libprimusP11.so can be copied as-is from the release artifacts.
It can either be mounted as a volume or baked into the container image.
The .secrets.cfg and primus.cfg must be manually prepared.
They are configuration files and should be mounted as a volume.
Steps
Step 1: Prepare Files
Follow the native Linux installation guide
and install the Primus PKCS#11 Provider on a temporary host.
This can even be a Docker container that you delete afterwards.
Use the ppin tool to create the .secrets.cfg file.
This step results in a working setup with complete .secrets.cfg and primus.cfg files.
Step 2: Deploy PKCS#11 Configuration to Kubernetes
Deploy the .secrets.cfg, the primus.cfg, and your PKCS#11 Password to your Kubernetes cluster.
Replace PRIMUSDEV with your real PKCS#11 Password/PIN.
kubectl create secret generic hsm-secrets \
--from-literal=secrets.cfg="$(cat .secrets.cfg)" \
--from-literal=pkcs11pin="PRIMUSDEV"
kubectl create configmap hsm-config --from-file=primus.cfg=primus.cfg
Skip this step if you use Docker Compose.
Step 3: Build Init Container Image
Build a small container image containing the contents of /usr/local/primus/.
This will serve as an init container that copies the files into an shared volume during pod/service initialization.
-
Download the PKCS#11 API Provider.
-
Unpack the ZIP:
export VERSION=x.x.xunzip PrimusAPI_PKCS11-v${VERSION}.zip -
Create a
Dockerfile:FROM alpine:3ARG ARCH=x86_64ARG VERSION=2.7.0COPY PrimusAPI_PKCS11-X-${VERSION}-rhel8-${ARCH}.tar.gz /primus.tar.gz# This must run at container start time, so that it writes to the volume mount!CMD tar -x -C /usr/local -f /primus.tar.gz -
Build and push the container image:
export VERSION=x.x.xdocker build --build-arg VERSION="${VERSION}" --build-arg ARCH="x86_64" -t primus-pkcs11:${VERSION} .docker push primus-pkcs11:${VERSION} docker://registry.example.com/primus-pkcs11:${VERSION}
Step 4: Deploy with Docker Compose or Helm
Modify your deployment configuration (docker-compose.yml or Helm chart) to look something like the below.
This example uses OpenBao, but it should work similar for other applications.
- Docker Compose
- Kubernetes/Helm
services:
openbao:
image: docker.io/openbao/openbao-hsm-ubi:2.6.1
volumes:
- primus-library:/usr/local/primus
- ./primus.cfg:/etc/primus/primus.cfg:ro
- ./.secrets.cfg:/etc/primus/.secrets.cfg:ro
pre_start:
- image: registry.example.com/primus-pkcs11:2.7.0
volumes:
primus-library:
server:
image:
repository: "openbao/openbao-hsm-ubi"
extraSecretEnvironmentVars:
- envName: BAO_HSM_PIN
secretName: hsm-secrets
secretKey: pkcs11pin
volumes:
- name: hsm-config
configMap:
name: hsm-config
- name: hsm-secrets
secret:
secretName: hsm-secrets
- name: primus-library
emptyDir: {}
volumeMounts:
- name: hsm-config
mountPath: "/etc/primus/primus.cfg"
subPath: primus.cfg
readOnly: true
- name: hsm-secrets
mountPath: "/etc/primus/.secrets.cfg"
subPath: secrets.cfg
readOnly: true
- name: primus-library
mountPath: "/usr/local/primus"
readOnly: true
extraInitContainers:
- name: init-primus-library
image: "registry.example.com/primus-pkcs11:2.7.0"
volumeMounts:
- name: primus-library
mountPath: "/usr/local/primus"
The configurations work as follows:
- The init container (
pre_start/extraInitContainers) executes once at service/pod startup.- Learn more about init containers in the Docker Compose and Kubernetes docs.
- The volume persists and shares the files in
/usr/local/primus/. Kubernetes uses anemptyDirvolume. - The
CMDin the init container image fills the/usr/local/primus/. (It only makes meaningful changes if the volume is empty or if you update the init container image with a new PKCS#11 provider version.) - The
primus.cfgand.secrets.cfgare mounted from the manually created files. They can be read-only, because the application doesn't need to modify them.
Step 5: Configure Application
You can now configure your application to access the Primus PKCS#11 Provider.
Troubleshooting
The most common problem are Unix permission issues. Make sure that your containerized application has read access to all of:
/usr/local/primus/(recursively)/etc/primus/.secrets.cfgand/etc/primus/primus.cfg
You may need to manually use chown/chmod to adjust the permissions of the contents of the volume mounts.
Logging
The Primus PKCS#11 Provider writes to a log file, whose location
is configured in primus.cfg.
It is recommended to also capture these logs for auditability and debugging.
Change the log location:
primus:
{
// ... Slot definitions ...
log:
{
file = "/var/log/primus/primus.log";
// ...
}; /* end log */
}; /* end primus */
Then mount /var/log/primus/ as a volume to persist the logs.
Conclusion
Your application running in Docker/Kubernetes is now be able to access and use the Primus PKCS#11 Provider.