IBM Cloud Hardware Security Module (HSM)

IBM Cloud includes an HSM service that provides cryptographic processing for key generation, encryption, decryption, and key storage. This document describes how to use that service with the IBM® Blockchain Platform.

While this tutorial focuses specifically on using IBM Cloud HSM, you can learn more about the overall configuration process for using any HSM that supports PCKS #11 with the IBM Blockchain Platform, see Configuring a node to use a Hardware Security Module.

Why would I want to use an HSM with my IBM Blockchain Platform network?

When a Certificate Authority (CA), peer, or ordering node is configured to use an HSM, their private key is generated by and protected inside a tamper resistant HSM device. IBM Cloud HSM is a FIPS 140-2 Level 3 validated, single-tenant device that implements Gemalto (Luna) HSM. When a CA is configured to use HSM, the CA root private key is stored in the HSM. This is the key that is used to sign enrollment requests. After a peer or ordering node is configured to use HSM, the nodes are able to sign and endorse transactions without ever exposing their private key.

Because only the private keys of node identities are secured in the HSM, when you enroll other admin or client application identities with a CA, their private keys are not stored inside the HSM because they will need their private key to transact on the network.

Using IBM Cloud HSM

IBM Cloud HSM 6.0 and 7.0 are available in the IBM Cloud catalog. Both versions are supported, however, these instructions focus on how to configure IBM Cloud HSM 6.0 to work with the IBM Blockchain Platform. If you are using 7.0, it is possible that some of the commands will differ slightly.

Process overview

This process requires Docker to be installed on the machine where the HSM client is running and that you are familiar with the process for building Docker images. It also presumes you are comfortable with using the Kubernetes CLI to administer your Kubernetes cluster.

When the entire HSM configuration is complete, it resembles the following diagram:

HSM configured with an HSM client image

HSM configured with an HSM client image
Figure 1. An example configuration of an HSM configured with an HSM client image.

The steps in this topic focus specifically on the creation of the Cloud HSM and the HSM Client in the diagram. When you deploy a CA, peer, or ordering node to use the HSM, you need to provide the label and PIN of the HSM partition. This configuration assumes you enabled HSM on your Kubernetes cluster when you deployed the service.

(Deprecated) HSM configured with a PKCS #11 proxy

HSM configured with a PKCS #11 proxy
Figure 2. An example configuration of an HSM configured with a PKCS #11 proxy.

When you choose to deploy the PKCS #11 proxy and configure a node with HSM, you need to provide the PKCS #11 proxy endpoint URL, along with the label and PIN of the HSM partition. It is the combination of the PKCS #11 proxy and the HSM client that allows the node to store and retrieve the node private key from the HSM.

Part One: Set up the HSM device and HSM client

  1. Provision the HSM and configure it with at least one partition. For example, you can follow instructions for Provisioning IBM Cloud HSM.

    Be sure to record the Label and PIN for the partition. You will need to provide these values later when you configure a blockchain node to use this HSM partition. Also, save the IP address associated with the HSM device. We will refer to this value throughout these instructions as <HSM_ADDRESS>.

  2. Install the HSM client on your local machine. Make sure the client version that you are running matches the HSM server version. Record the IP address or fully qualified host name where the HSM client is running. We will refer to this value throughout these instructions as <CLIENT_ADDRESS>.

    The client runs on AIX, Linux, Oracle Solaris, or Microsoft Windows, but is not supported on MacOS.

Part Two: Configure communications between the HSM server and client

In this section you will get the HSM server certificate and create the HSM client certificate-key pair in order for them to be exchanged.

  1. HSM client Run the following command using the HSM client to get the server certificate. This certificate enables the client to communicate with the server.

    scp hsm_admin@<HSM_ADDRESS>:server.pem server.pem
    

    Replace

    • <HSM_ADDRESS> with the IP address of the HSM.
  2. HSM client Now, add the HSM server to the client configuration by running the following command:

    vtl addServer -n <HSM_ADDRESS> -c server.pem
    

    Replace

    • <HSM_ADDRESS> with the IP address of the HSM.
  3. HSM client Create the certificate and private key for the client by running the command:

    vtl createcert -n <CLIENT_ADDRESS>
    

    Replace

    • <CLIENT_ADDRESS> with the IP address or fully qualified host name of the client.

    The name of the generated certificates includes the <CLIENT_ADDRESS>. The output of this command looks similar to:

    Private Key created and written to: /usr/safenet/lunaclient/cert/client/<CLIENT_ADDRESS>Key.pem
    Certificate created and written to: /usr/safenet/lunaclient/cert/client/<CLIENT_ADDRESS>.pem
    
  4. HSM client Copy the client certificate and private key to the HSM server by running the command:

    scp /usr/safenet/lunaclient/cert/client/<CLIENT_ADDRESS>.pem hsm_admin@<HSM_ADDRESS>:.
    

    Replace

    • <CLIENT_ADDRESS> with the IP address or fully qualified host name of the client.
    • <HSM_ADDRESS> with the IP address of the HSM.

Part Three: Register the client with the HSM server

  1. HSM server SSH into the HSM as the admin the HSM server and register the client by running one of the following commands.

    If the <CLIENT_ADDRESS> is the IP address of the client:

    client register -client ${CLIENT_NAME} -ip <CLIENT_ADDRESS>
    

    If the <CLIENT_ADDRESS> is the fully qualified host name of the client:

    client register -client ${CLIENT_NAME} -hostname <CLIENT_ADDRESS>
    

    Replace

    • {CLIENT_NAME} with the name of the client. This value can be anything meaningful to you.
    • <CLIENT_ADDRESS> with either the IP address or fully qualified host name of the client.
  2. HSM server Because network address translation (NAT) exists between the client and the HSM, we need to disable client source IP address validation by the Network Trust Link Server (NTLS) upon Network Trust Link Agent (NTLA) client connection. Disable ip check on the HSM server and then restart the NTLS service on the HSM server by running the following commands:

    ntls ipcheck disable
    service restart ntls
    
  3. HSM server Assign a partition to the newly created client on the HSM server by running the following command:

    client assignpartition -client ${CLIENT_NAME} -partition ${PARTITION_NAME}
    

    Replace

    • {CLIENT_NAME} with the name that you gave to your HSM client.
    • {PARTITION_NAME} with the name of the HSM partition you created in Part one, step 1.

    You can verify the command worked by running the following command:

    client show -client ${CLIENT_NAME}
    

    The output will look similar to:

    ClientID:     hsmclient
    IPAddress:    10.220.203.73
    HTL Required: no
    OTT Expiry:   n/a
    Partitions:   "partition1"
    
    Command Result : 0 (Success)
    
  4. HSM client Verify the client can connect to HSM server by running the command:

    vtl verify
    

    The output will look similar to:

    The following Luna SA Slots/Partitions were found:
    Slot    Serial #            Label
    ====    ================    =====
    0        500752010           partition1
    
  5. HSM client Create a configs folder on the client and then copy the server.pem certificate from Part two, step 1 and the <CLIENT_ADDRESS>Key.pem and <CLIENT_ADDRESS>.pem files from Part two, step 3 into the folder:

    • Copy server.pem to configs/server.pem
    • Copy /usr/safenet/lunaclient/cert/client/<CLIENT_ADDRESS>Key.pem to configs/key.pem
    • Copy /usr/safenet/lunaclient/cert/client/<CLIENT_ADDRESS>.pem to configs/cert.pem

Part Four: Build a Docker image

There are two ways to configure HSM on your blockchain network. The use of a PKCS #11 proxy has been deprecated in favor of building an HSM client image which is simpler to configure and provides better overall performance. Both processes are supported, however if you are configuring a new HSM, it is recommended that you build the HSM client image. Both sets of instructions are provided, starting with Build an HSM client image. If you still prefer to use a PKCS #11 proxy, you can refer to those instructions instead. If you are currently using the PKCS #11 proxy and want to try out the HSM client image, it is possible to have both HSM configurations running on the platform at the same time. However, when you deploy a new node you have to choose which HSM implementation you want to use.

Build an HSM client image

Next we build a Docker file that contains the HSM client image. These instructions assume that you have successfully configured your HSM appliance and HSM client. Use these steps to generate an image that is consumable by the IBM Blockchain Platform operator.

Step one: Modify the HSM client configuration

Each HSM has its own configuration file that is typically named Chrystoki.conf. This is the main configuration file for the HSM integration and controls many aspects of the HSM client operation. After you install the HSM client, you need to modify the etc/Chrystoki.conf file to point to the hsm folder that contains the HSM shared object library and cryptographic material. The paths specified in Chrystoki.conf represent the location where the IBM Blockchain Platform operator mounts these files on the containers. You need to modify parameters inside the Chrystoki2 and LunaSA Client sections as follows:

Chrystoki2 settings

LunaSA Client settings Typically no changes would be required here unless you have explicitly modified the names of these files.

The following example shows what the file would look like if you were using IBM Cloud HSM. It provides the path to the HSM shared object, certificate and keys. Note that the naming of these files depends on the HSM library that is being used.

Chrystoki2 = {
     LibUNIX = /hsm/libCryptoki2.so;
     LibUNIX64 = /hsm/libCryptoki2_64.so;
}
...
LunaSA Client = {
...
     ClientPrivKeyFile = /hsm/key.pem;
     ClientCertFile = /hsm/cert.pem;
     ServerCAFile = /hsm/cafile.pem;
...
}
Step two: Build the HSM client image

The HSM client image can be built with a Docker file similar to the following:

FROM registry.access.redhat.com/ubi8/ubi-minimal as builder

## This directory contains the installation files for gemalto/luna client
COPY 64 64

RUN microdnf install -y \
   gcc \
   gcc-c++ \
   openssh-clients \
   bind-utils \
   iputils \
   && cd 64 && \
   # NOTE we are accepting the license for installing gemalto client here
   # please take a look at the license before moving forward
   echo "y" | ./install.sh -p sa

### Final image ###

FROM registry.access.redhat.com/ubi8/ubi-minimal

# Copy the library files from builder
COPY --from=builder /usr/lib/libCryptoki2_64.so /usr/lib/libCryptoki2_64.so
COPY --from=builder /usr/lib/libCryptoki2_64.so.2 /usr/lib/libCryptoki2_64.so.2
COPY --from=builder /usr/lib/libCryptoki2_64.so.6.3.0 /usr/lib/libCryptoki2_64.so.6.3.0

Now, run the following command to build the Docker image:

docker build -t hsm-client:v1 -f Dockerfile .
Step three: Push the Docker image to your container registry

After the image is built, the next step is to push the image to your Docker registry (for example, Docker Hub). The commands look similar to:

docker login -u <DOCKER_HUB_ID> -p <DOCKER_HUB_PWD>
docker tag hsm-client:v1 <DOCKER_HUB_ID>/hsm-client:v1
docker push <DOCKER_HUB_ID>/hsm-client:v1

Create a Kubernetes image pull secret

If the HSM client image that you published is not public, then the operator requires an image pull secret that contains a valid username and password (or access token) for the container registry. If the image is public, the imagepullsecret is not required and you can skip this command. To build the image pull secret named hsm-docker-secret, run the following command in the namespace or project where you deployed the service:

kubectl create secret docker-registry hsm-docker-secret --docker-server=<DOCKER_REGISTRY_SERVER> --docker-username=<DOCKER_USER> --docker-password=<DOCKER_PASSWORD> --docker-email=<DOCKER_EMAIL> -n <NAMESPACE>

Replace:

Step four: Create a Kubernetes secret hsmcrypto

In order for a CA, peer, or ordering node to be able to communicate with the HSM client image you need to create a Kubernetes secret named hsmcrypto that contains the keys and configuration files for the HSM that you are using. When the console deploys a node that is configured with HSM, it uses this secret to access the HSM client image keys and configuration files.

The secret needs to be created in the operator namespace. If you are using the IBM Cloud HSM, the command would be:

$ kubectl create secret generic hsmcrypto -n <NAMESPACE> --from-file=Chrystoki.conf --from-file=cert.pem --from-file=key.pem --from-file=server.pem

Replace <NAMESPACE> with the name of your operator Kubernetes namespace or OpenShift project. If you are not using IBM Cloud HSM, you need to replace the values of the --from-file parameters with the set of certificates and configuration files that are required for your HSM client image.

When successful, the output looks similar to:

secret/hsmcrypto created

To verify the contents of the secret, run the command:

kubectl get secret -n <namespace> hsmcrypto -o yaml

You should see results similar to:

apiVersion: v1
data:
  Chrystoki.conf: ""
  cafile.pem: ""
  cert.pem: ""
  key.pem: ""
kind: Secret
metadata:
  name: hsmcrypto
  namespace: <NAMESPACE>

Step five: Create the HSM configmap

Copy the following text and save it to a file named ibp-hsm-config.yaml:

version: v1
type: hsm
library:
  image: <HSM_IMAGE_URL>
  auth:
    imagePullSecret: <IMAGE_PULL_SECRET>
  filepath: <HSM_LIBRARY_FILE_PATH>
envs:  
- name: <ENVIRONMENT_VARIABLE_NAME>
  value: <ENVIRONMENT_VARIABLE_VALUE>
mountpaths:
- mountpath: <MOUNTPATH>
  name: <MOUNTPATH_NAME>
  secret: <HSM_CRYPTO_SECRET>
  paths:
  - key: <KEY>
    path: <PATH>
  - key: <KEY>
    path: <PATH>
- mountpath: <MOUNTPATH>
  name: <MOUNTPATH_NAME>
  secret: <HSM_CRYPTO_SECRET>
  paths:
  - key: <KEY>
    path: <PATH>
  - key: <KEY>
    path: <PATH>

Replace the following values:

Each HSM likely has a different set of keys that are required by the HSM client. Optionally replicate the "key" and "path" sections according to the number required by your HSM client. Similarly, if multiple sets of folders need to be mounted, you can replicate the "mountpath" section.

For example, if you are using IBM Cloud HSM, the file looks similar to:

version: v1
type: hsm
library:
  image: us.icr.io/hsm/gemalto-client:v1.2.3-amd64
  auth:
    imagePullSecret: hsm-docker-secret
  filepath: /usr/lib/libCryptoki2_64.so
mountpaths:
- mountpath: /hsm
  name: hsmcrypto
  paths:
  - key: cafile.pem
    path: cafile.pem
  - key: cert.pem
    path: cert.pem
  - key: key.pem
    path: key.pem
  - key: server.pem
    path: server.pem
  secret: hsmcrypto
- mountpath: /etc/Chrystoki.conf
  name: hsmconfig
  secret: hsmcrypto
  subpath: Chrystoki.conf

In this example, the first mountpath contains four configuration files (cafile.pem, cert.pem, key.pem, server.pem) and the hsmcrypto secret, and all of them are mounted to the mountpath /hsm. The actual name of the mountpath is hsmcrypto, and it contains an exact mapping of the key value pair to the Kubernetes secret and the location to mount it to. For example, cafile.pem is read from the path cafile.pem in the hsmcrypto mountpath using the hsmcrypto secret and mounted to /hsm/cafile.pem.

A second mountpath is included for the HSM /etc/Chrystoki.conf file. Because the HSM requires its config file in the /etc folder, which is a system directory, we need to use the subpath parameter to avoid replacing the entire /etc directory. If the subpath is not used, the entire /etc directory is replaced with the volume being mounted.

Run the following command to create the configmap named ibp-hsm-config in your cluster namespace or project:

kubectl create configmap ibp-hsm-config --from-file=ibp-hsm-config.yaml -n <NAMESPACE>

The output looks similar to:

configmap/ibp-hsm-config created

What's next

After you have used these instructions to configure your IBM Cloud HSM and build the HSM client image or PKCS #11 proxy, you are ready to configure your blockchain nodes to use the HSM. When you create a CA, peer, or ordering node, select the HSM Advanced deployment option to configure the node to use this HSM.

When a node is configured with HSM, a temporary Kubernetes job is started to run this HSM "enrollment" process. Before configuring a node to use HSM, ensure that you have enough resources in your cluster to support this job that takes approximately 0.1CPU and 100Mi memory.

On the HSM configuration panel, the Use HSM client image toggle is visible. When it is on, you can enter the following values:

If you prefer to use an HSM that was configured with a PKCS #11 proxy instead, slide the Use HSM client image toggle to off. One additional field becomes visible:

When the node is deployed, a private key for the specified node enroll ID and secret is generated by the HSM and stored securely in the appliance.

Using multiple partitions

If your HSM has multiple partitions, only one PKCS #11 proxy is required to communicate with the HSM.