# Source: https://infisical.com/docs/documentation/platform/kms/hsm-integration.md

> ## Documentation Index
> Fetch the complete documentation index at: https://infisical.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# HSM Integration

> Learn more about integrating an HSM with Infisical KMS.

<Note>
  Changing the encryption strategy for your instance is an Enterprise-only feature.
  This section is intended for users who have obtained an Enterprise license and are on-premise.

  Please reach out to [sales@infisical.com](mailto:sales@infisical.com) if you have any questions.
</Note>

## Overview

Infisical KMS currently supports two encryption strategies:

1. **Standard Encryption**: This is the default encryption strategy used by Infisical KMS. It uses a software-protected encryption key to encrypt KMS keys within your Infisical instance. The root encryption key is defined by setting the `ENCRYPTION_KEY` environment variable.
2. **Hardware Security Module (HSM)**: This encryption strategy uses a Hardware Security Module (HSM) to create a root encryption key that is stored on a physical device to encrypt the KMS keys within your instance.

## Hardware Security Module (HSM)

<img src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/platform/kms/hsm/hsm-illustration.png" alt="HSM Illustration" />

Using a hardware security module comes with the added benefit of having a secure and tamper-proof device to store your encryption keys. This ensures that your data is protected from unauthorized access.

<Warning>
  All encryption keys used for cryptographic operations are stored within the HSM. This means that if the HSM is lost or destroyed, you will no longer be able to decrypt your data stored within Infisical. Most providers offer recovery options for HSM devices, which you should consider when setting up an HSM device.
</Warning>

Enabling HSM encryption has a set of key benefits:

1. **Root Key Wrapping**: The root KMS encryption key that is used to secure your Infisical instance will be encrypted using the HSM device rather than the standard software-protected key.

#### Caveats

* **Performance**: Using an HSM device can have a performance impact on your Infisical instance. This is due to the additional latency introduced by the HSM device. This is however only noticeable when your instance(s) start up or when the encryption strategy is changed.
* **Key Recovery**: If the HSM device is lost or destroyed, you will no longer be able to decrypt your data stored within Infisical. Most HSM providers offer recovery options, which you should consider when setting up an HSM device.

## Requirements

* An HSM device *(PKCS#11 compatible library)* from a compatible provider such as [Thales Luna HSM](https://cpl.thalesgroup.com/encryption/data-protection-on-demand/services/luna-cloud-hsm), [AWS CloudHSM](https://aws.amazon.com/cloudhsm/), [Fortanix HSM](https://www.fortanix.com/platform/data-security-manager), or others.
  Infisical is validated to work with PKCS#11 2.30 and newer. If your HSM device doesn't follow the >=2.30 PKCS#11 standard you may see degraded performance.

## Environment Variable Configuration

To configure your Infisical instance to use an HSM, you must set the required environment variables. Below you'll find an example of the required environment variables.
For further instructions on how to configure the HSM device for your Infisical instance, please see the [Setup Instructions](#setup-instructions) section.

```dotenv  theme={"dark"}
HSM_LIB_PATH=/usr/local/lib/cloudhsm/cloudhsm.so
HSM_SLOT=1
HSM_KEY_LABEL=infisical-key
HSM_PIN=your:pin
```

* `HSM_LIB_PATH`: The path to the PKCS#11 library provided by the HSM provider. This usually comes in the form of a `.so` for Linux and MacOS, or a `.dll` file for Windows. For Docker, you need to mount the library path as a volume. Further instructions can be found below. If you are using Docker, make sure to set the HSM\_LIB\_PATH environment variable to the path where the library is mounted in the container.
* `HSM_PIN`: The PKCS#11 PIN to use for authentication with the HSM device.
* `HSM_SLOT`: The slot number to use for the HSM device. This is typically between `0` and `5` for most HSM devices.
* `HSM_KEY_LABEL`: The label of the key to use for encryption. **Please note that if no key is found with the provided label, the HSM will create a new key with the provided label.**

You can read more about the [default instance configurations](/self-hosting/configuration/envars) here.

## PKCS#11 Key Attributes

If no AES key or HMAC key already exists with the label you defined on the `HSM_KEY_LABEL` environment variable, then Infisical will create one for you automatically using the label specified on `HSM_KEY_LABEL`.
Below you'll find a list of the attributes each key will be created with.

### AES Key

<Accordion title="Bring your own key minimum requirements (optional)">
  If you bring your own AES key and don't let Infisical create it for you it must have at least the following attributes:

  * `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class *(secret key)*.
  * `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type *(AES key)*.
  * `CKA_VALUE_LEN`: `32` — 256-bit key size.
  * `CKA_ENCRYPT`: `true` — Encryption capabilities enabled.
  * `CKA_DECRYPT`: `true` — Decryption capabilities enabled.
  * `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused.

  <Warning>
    Note that for security reasons it is highly recommended to create an AES key with the full set of key attributes seen below if you're going to bring your own key.
  </Warning>
</Accordion>

* `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class *(secret key)*.
* `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type *(AES key)*.
* `CKA_VALUE_LEN`: `32` — 256-bit key size.
* `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable.
* `CKA_ENCRYPT`: `true` — Encryption capabilities enabled.
* `CKA_DECRYPT`: `true` — Decryption capabilities enabled.
* `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused.
* `CKA_EXTRACTABLE`: `false` — The key material is not extractable from the HSM.
* `CKA_SENSITIVE`: `true` — The key material is marked as sensitive.
* `CKA_PRIVATE`: `true` — The key material is marked as private to the slot and can't be accessed from other slots.

### HMAC Key

<Accordion title="Bring your own key minimum requirements (optional)">
  If you bring your own HMAC key and don't let Infisical create it for you it must have at least the following attributes:

  * `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class *(secret key)*.
  * `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class *(generic secret key)*.
  * `CKA_VALUE_LEN`: `32` — 256-bit key size
  * `CKA_SIGN`: `true` — Signing capabilities enabled
  * `CKA_VERIFY`: `true` — Verifying capabilities enabled.
  * `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused.

  <Warning>
    Note that for security reasons it is highly recommended to create an HMAC key with the full set of key attributes seen below if you're going to bring your own key.
  </Warning>
</Accordion>

* `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class *(secret key)*.
* `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class *(generic secret key)*.
* `CKA_VALUE_LEN`: `32` — 256-bit key size.
* `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable, suffixed with `_HMAC`. If you specify `infisical-key-v1`, then the HMAC key label will become `infisical-key-v1_HMAC`.
* `CKA_SIGN`: `true` — Signing capabilities enabled
* `CKA_VERIFY`: `true` — Verifying capabilities enabled.
* `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused.
* `CKA_EXTRACTABLE`: `false` — The key material is not extractable from the HSM.
* `CKA_SENSITIVE`: `true` — The key material is marked as sensitive.
* `CKA_PRIVATE`: `true` — The key material is marked as private to the slot and can't be accessed from other slots.

## Setup Instructions

<Steps>
  <Step title="Setting up an HSM Device">
    To set up HSM encryption, you need to configure an HSM provider and HSM key. The HSM provider is used to connect to the HSM device, and the HSM key is used to encrypt Infisical's KMS keys. We recommend using a Cloud HSM provider such as [Thales Luna HSM](https://cpl.thalesgroup.com/encryption/data-protection-on-demand/services/luna-cloud-hsm), [AWS CloudHSM](https://aws.amazon.com/cloudhsm/), or [Fortanix HSM](https://www.fortanix.com/platform/data-security-manager).

    You need to follow the instructions provided by the HSM provider to set up the HSM device. Once the HSM device is set up, the HSM device can be used within Infisical.

    After setting up the HSM from your provider, you will have a set of files that you can use to access the HSM. These files need to be present on the machine where Infisical is running.
    If you are using containers, you will need to mount the folder where these files are stored as a volume in the container.

    The setup process for an HSM device varies depending on the provider. We have created guides for Thales Luna Cloud HSM and Fortanix HSM, which you can find below.
  </Step>

  <Step title="Configure HSM on Infisical">
    <Warning>
      Are you using Docker or Kubernetes for your deployment? If you are using Docker or Kubernetes, please follow the instructions in the [Using HSM's in your Deployment](#using-hsms-in-your-deployment) section.
    </Warning>

    Configuring the HSM on Infisical requires setting a set of environment variables:

    * `HSM_LIB_PATH`: The path to the PKCS#11 library provided by the HSM provider. This usually comes in the form of a `.so` for Linux and MacOS, or a `.dll` file for Windows. For Docker, you need to mount the library path as a volume. Further instructions can be found below. If you are using Docker, make sure to set the HSM\_LIB\_PATH environment variable to the path where the library is mounted in the container.
    * `HSM_PIN`: The PKCS#11 PIN to use for authentication with the HSM device.
    * `HSM_SLOT`: The slot number to use for the HSM device. This is typically between `0` and `5` for most HSM devices.
    * `HSM_KEY_LABEL`: The label of the key to use for encryption. **Please note that if no key is found with the provided label, the HSM will create a new key with the provided label.**

    You can read more about the [default instance configurations](/self-hosting/configuration/envars) here.
  </Step>

  <Step title="Restart Instance">
    After setting up the HSM, you need to restart the Infisical instance for the changes to take effect.
  </Step>

  <Step title="Navigate to the Server Admin Console">
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/platform/kms/hsm/server-admin-console.png" alt="Server Admin Console" />
  </Step>

  <Step title="Update the KMS Encryption Strategy to HSM">
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/platform/kms/hsm/encryption-strategy.png" alt="Set Encryption Strategy" />

    Once you press the 'Save' button, your Infisical instance will immediately switch to the HSM encryption strategy. This will re-encrypt your KMS key with keys from the HSM device.
  </Step>

  <Step title="Verify Encryption Strategy">
    To verify that the HSM was correctly configured, you can try creating a new secret in one of your projects. If the secret is created successfully, the HSM is now being used for encryption.
  </Step>
</Steps>

## Using HSMs In Your Deployment

<Tabs>
  <Tab title="Docker">
    When using Docker, you need to mount the path containing the HSM client files. This section covers how to configure your Infisical instance to use an HSM with Docker.

    <Tabs>
      <Tab title="Thales Luna Cloud HSM">
        <Steps>
          <Step title="Create HSM client folder">
            When using Docker, you are able to set your HSM library path to any location on your machine. In this example, we are going to be using `/etc/luna-docker`.

            ```bash  theme={"dark"}
              mkdir /etc/luna-docker
            ```

            After [setting up your Luna Cloud HSM client](https://thalesdocs.com/gphsm/luna/7/docs/network/Content/install/client_install/add_dpod.htm), you should have a set of files, referred to as the HSM client. You don't need all the files, but for simplicity we recommend copying all the files from the client.

            A folder structure of a client folder will often look like this:

            ```
            partition-ca-certificate.pem
            partition-certificate.pem
            server-certificate.pem
            Chrystoki.conf
            /plugins
              libcloud.plugin
            /lock
            /libs
              /64
                libCryptoki2.so
            /jsp
              LunaProvider.jar
              /64
                libLunaAPI.so
            /etc
              openssl.cnf
            /bin
              /64
                ckdemo
                lunacm
                multitoken
                vtl
            ```

            The most important parts of the client folder is the `Chrystoki.conf` file, and the `libs`, `plugins`, and `jsp` folders. You need to copy these files to the folder you created in the first step.

            ```bash  theme={"dark"}
              cp -r /<path-to-where-your-luna-client-is-located> /etc/luna-docker
            ```
          </Step>

          <Step title="Update Chrystoki.conf">
            The `Chrystoki.conf` file is used to configure the HSM client. You need to update the `Chrystoki.conf` file to point to the correct file paths.

            In this example, we will be mounting the `/etc/luna-docker` folder to the Docker container under a different path. The path we will use in this example is `/usr/safenet/lunaclient`. This means `/etc/luna-docker` will be mounted to `/usr/safenet/lunaclient` in the Docker container.

            An example config file will look like this:

            ```Chrystoki.conf  theme={"dark"}
                Chrystoki2 = {
                  # This path points to the mounted path, /usr/safenet/lunaclient
                  LibUNIX64 = /usr/safenet/lunaclient/libs/64/libCryptoki2.so;
                }

                Luna = {
                  DefaultTimeOut = 500000;
                  PEDTimeout1 = 100000;
                  PEDTimeout2 = 200000;
                  PEDTimeout3 = 20000;
                  KeypairGenTimeOut = 2700000;
                  CloningCommandTimeOut = 300000;
                  CommandTimeOutPedSet = 720000;
                }

                CardReader = {
                  LunaG5Slots = 0;
                  RemoteCommand = 1;
                }

                Misc = {
                  # Update the paths to point to the mounted path if your folder structure is different from the one mentioned in the previous step.
                  PluginModuleDir = /usr/safenet/lunaclient/plugins;
                  MutexFolder = /usr/safenet/lunaclient/lock;
                  PE1746Enabled = 1;
                  ToolsDir = /usr/bin;

                }

                Presentation = {
                  ShowEmptySlots = no;
                }

                LunaSA Client = {
                  ReceiveTimeout = 20000;
                  # Update the paths to point to the mounted path if your folder structure is different from the one mentioned in the previous step.
                  SSLConfigFile = /usr/safenet/lunaclient/etc/openssl.cnf;
                  ClientPrivKeyFile = ./etc/ClientNameKey.pem;
                  ClientCertFile = ./etc/ClientNameCert.pem;
                  ServerCAFile = ./etc/CAFile.pem;
                  NetClient = 1;
                  TCPKeepAlive = 1;
                }


                REST = {
                  AppLogLevel = error
                  ServerName = <REDACTED>;
                  ServerPort = 443;
                  AuthTokenConfigURI = <REDACTED>;
                  AuthTokenClientId = <REDACTED>;
                  AuthTokenClientSecret = <REDACTED>;
                  RestClient = 1;
                  ClientTimeoutSec = 120;
                  ClientPoolSize = 32;
                  ClientEofRetryCount = 15;
                  ClientConnectRetryCount = 900;
                  ClientConnectIntervalMs = 1000;
                }
                XTC = {
                  Enabled = 1;
                  TimeoutSec = 600;
                }
            ```

            Save the file after updating the paths.
          </Step>

          <Step title="Run Docker">
            Running Docker with HSM encryption requires setting the HSM-related environment variables as mentioned previously in the [HSM setup instructions](#setup-instructions). You can set these environment variables in your Docker run command.

            We are setting the environment variables for Docker via the command line in this example, but you can also pass in a `.env` file to set these environment variables.

            <Warning>
              If no key is found with the provided key label, the HSM will create a new key with the provided label.
              Infisical depends on an AES and HMAC key to be present in the HSM. If these keys are not present, Infisical will create them. The AES key label will be the value of the `HSM_KEY_LABEL` environment variable, and the HMAC key label will be the value of the `HSM_KEY_LABEL` environment variable with the suffix `_HMAC`.
            </Warning>

            ```bash  theme={"dark"}
            docker run -p 80:8080 \
              -v /etc/luna-docker:/usr/safenet/lunaclient \
              -e HSM_LIB_PATH="/usr/safenet/lunaclient/libs/64/libCryptoki2.so" \
              -e HSM_PIN="<your-hsm-device-pin>" \
              -e HSM_SLOT=<hsm-device-slot> \
              -e HSM_KEY_LABEL="<your-key-label>" \

              # The rest are unrelated to HSM setup...
              -e ENCRYPTION_KEY="<>" \
              -e AUTH_SECRET="<>" \
              -e DB_CONNECTION_URI="<>" \
              -e REDIS_URL="<>" \
              -e SITE_URL="<>" \
              infisical/infisical:<version> # Replace <version> with the version you want to use
            ```

            We recommend reading further about [using Infisical with Docker](/self-hosting/deployment-options/standalone-infisical).
          </Step>
        </Steps>

        After following these steps, your Docker setup will be ready to use HSM encryption.
      </Tab>

      <Tab title="Fortanix HSM">
        <Steps>
          <Step title="Set up Fortanix HSM">
            To use Fortanix HSM with Infisical, you need to:

            1. Create an App in Fortanix:
               * Set Interface value to be PKCS#11
               * Select API key as authentication method
               * Assign app to a group

                        <img src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/platform/kms/hsm/fortanix-hsm-setup.png" alt="Fortanix HSM Setup" />

            2. Take note of the domain (e.g., apac.smartkey.io). You will need this to set up the configuration file for the Fortanix client.
          </Step>

          <Step title="Install PKCS11 Library">
            The easiest approach would be to download the `.so` file for Linux directly from the [Fortanix PKCS#11 installation page](https://fortanix.zendesk.com/hc/en-us/sections/4408769080724-PKCS-11).

            Create a configuration file named `pkcs11.conf` with the following content:

            ```
            api_endpoint = "https://apac.smartkey.io"
            prevent_duplicate_opaque_objects = true
            retry_timeout_millis = 60000
            ```

            Note: Replace `apac.smartkey.io` with your actual Fortanix domain if different. For more details about the configuration file format and additional options, refer to the [Fortanix PKCS#11 Configuration File Documentation](https://support.fortanix.com/docs/clients-pkcs11-library#511-configuration-file-format).
          </Step>

          <Step title="Create a directory for Fortanix files">
            Create a directory to store the Fortanix library and configuration file:

            ```bash  theme={"dark"}
            mkdir -p /etc/fortanix-hsm
            ```

            Copy the downloaded `.so` file and the `pkcs11.conf` file to this directory:

            ```bash  theme={"dark"}
            cp /path/to/fortanix_pkcs11_4.37.2554.so /etc/fortanix-hsm/
            cp /path/to/pkcs11.conf /etc/fortanix-hsm/
            ```
          </Step>

          <Step title="Run Docker">
            Run Docker with Fortanix HSM by mounting the directory and setting the required environment variables:

            ```bash  theme={"dark"}
            docker run -p 80:8080 \
              -v /etc/fortanix-hsm:/etc/fortanix-hsm \
              -e HSM_LIB_PATH="/etc/fortanix-hsm/fortanix_pkcs11_4.37.2554.so" \  # Path to the PKCS#11 library
              -e HSM_PIN="MDE3YWUxO..." \  # Your Fortanix app API key used for authentication
              -e HSM_SLOT=0 \              # Slot value (arbitrary for Fortanix HSM)
              -e HSM_KEY_LABEL="hsm-key-label" \  # Label to identify the encryption key in the HSM
              -e FORTANIX_PKCS11_CONFIG_PATH="/etc/fortanix-hsm/pkcs11.conf" \  # Path to Fortanix configuration file
              
              # The rest are unrelated to HSM setup...
              -e ENCRYPTION_KEY="<>" \
              -e AUTH_SECRET="<>" \
              -e DB_CONNECTION_URI="<>" \
              -e REDIS_URL="<>" \
              -e SITE_URL="<>" \
              infisical/infisical:<version> # Replace <version> with the version you want to use
            ```

            <Warning>
              Note: Fortanix HSM integration only works for AMD64 CPU architectures.
            </Warning>
          </Step>
        </Steps>

        After following these steps, your Docker setup will be ready to use Fortanix HSM encryption.
      </Tab>

      <Tab title="AWS CloudHSM">
        ### Prerequisites

        * An [activated AWS CloudHSM cluster](https://docs.aws.amazon.com/cloudhsm/latest/userguide/activate-cluster.html) with at least 1 HSM device.
        * A [HSM user with the `Crypto User` role](https://docs.aws.amazon.com/cloudhsm/latest/userguide/cloudhsm_cli-user-create.html). In this guide we are using a user with the username `testUser` and the password `testPassword`.

        <Steps>
          <Step title="Configure CloudHSM client">
            Before using the CloudHSM client, it must be configured properly so Infisical can use it for cryptographic operations.

            **1. Download the AWS CloudHSM client**

            You can download the AWS CloudHSM client from [the AWS documentation](https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-library-install.html).

            <Note>
              Note that the AWS CloudHSM client is only available for Linux and Windows.
              If you're on a different operating system, you'll need to access a Linux machine to configure the client, such as an AWS EC2 Debian instance.
            </Note>

            **2. Configure the CloudHSM client**

            After installing the CloudHSM client, you should see all related files in the `/opt/cloudhsm/` directory on your machine.

            You need to run the `configure-pkcs11` binary which will configure the client to connect with your AWS CloudHSM cluster. Depending on if you have multiple HSM's inside your cluster, you'll need to run the command with different arguments. Below you'll find the appropriate command for your use case:

            <AccordionGroup>
              <Accordion title="Single HSM">
                ```bash  theme={"dark"}
                sudo /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_ENI_IPV4_ADDRESS> --disable-key-availability-check
                ```

                <Info>
                  To use a single HSM, you must first manage client key durability settings by setting `disable_key_availability_check` to true by passing the `--disable-key-availability-check` flag. For more information read the [Key Synchronization](https://docs.aws.amazon.com/cloudhsm/latest/userguide/manage-key-sync.html) section in the AWS CloudHSM documentation.
                </Info>
              </Accordion>

              <Accordion title="Multiple HSM's">
                ```bash  theme={"dark"}
                sudo /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_ENI_IPV4_ADDRESS_1> <HSM_ENI_IPV4_ADDRESS_2> ... --disable-key-availability-check
                ```
              </Accordion>
            </AccordionGroup>

            At this point you should have:

            1. [Activated the CloudHSM cluster](https://docs.aws.amazon.com/cloudhsm/latest/userguide/activate-cluster.html)
            2. [Created a Crypto User HSM user](https://docs.aws.amazon.com/cloudhsm/latest/userguide/cloudhsm_cli-user-create.html)
            3. Downloaded and configured the CloudHSM client as described in the previous steps.

            **3. Download the configured HSM client files**

            After configuring the CloudHSM client, you should notice that the PKCS11 configuration file has been updated to include the HSM's ENI IP address. You can find this file in the `/opt/cloudhsm/etc/cloudhsm-pkcs11.cfg` directory, and it should look like this:

            ```json cloudhsm-pkcs11.cfg theme={"dark"}
            {
              "clusters": [
                {
                  "type": "hsm1",
                  "cluster": {
                    // Your issuing CA certificate.
                    // As per AWS documentation, this defaults to `/opt/cloudhsm/etc/customerCA.crt`.
                    "hsm_ca_file": "/opt/cloudhsm/etc/customerCA.crt",
                    "servers": [
                      {
                        "hostname": "<HSM_ENI_IPV4_ADDRESS_1>",
                        "port": 2223,
                        "enable": true
                      },
                      {
                        "hostname": "<HSM_ENI_IPV4_ADDRESS_2>",
                        "port": 2223,
                        "enable": true
                      }
                    ],
                    // Only relevant if you passed the --disable-key-availability-check flag
                    "options": {
                      "disable_key_availability_check": true
                    }
                  }
                }
              ],
              "logging": {
                "log_type": "file",
                "log_file": "/opt/cloudhsm/run/cloudhsm-pkcs11.log",
                "log_level": "info",
                "log_interval": "daily"
              }
            }
            ```

            Save the entire `/opt/cloudhsm` folder, as you will need to mount this to your Infisical Docker container in the later steps. In this guide we will be saving all the files from the folder as `/etc/cloudhsm` and mounting it to the `/etc/cloudhsm` directory in the Docker container.
          </Step>

          <Step title="Find HSM slot number">
            On the same machine that you configured the CloudHSM client, you can use `pkcs11-tool` to find the HSM slot number and to verify that the client is working correctly.

            First, install the `pkcs11-tool` package:

            ```bash  theme={"dark"}
            sudo apt-get install opensc -y
            ```

            Then, run the following command to find the HSM slot number:

            ```bash  theme={"dark"}
            pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so --list-slots --login
            ```

            It'll prompt you to log in with your PIN, which is your username and password separated by a colon. Example: `testUser:testPassword`.

            This will output the HSM slot number like so:

            ```bash  theme={"dark"}
            ubuntu@ec-2:~$ pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so --list-slots
            Available slots:
            Slot 0 (0x2000000000000001): hsm1
              token label        : hsm1
              token manufacturer : Marvell Semiconductors, Inc.
              token model        : LS2
              token flags        : login required, rng, token initialized
              hardware version   : 66.48
              firmware version   : 10.2
              serial num         : 
              pin min/max        : 8/32
            ```

            In this case we see that the HSM has a slot in the position of `0`. This slot number will be used in the later steps to set the `HSM_SLOT` environment variable.
          </Step>

          <Step title="Download the HSM issuing CA certificate">
            When you initialized your HSM, you were prompted to download the cluster CSR and sign it.
            In order to use the HSM with Infisical, you need to obtain the issuer CA certificate that was used to sign the cluster CSR.

            If you followed [the official AWS documentation](https://docs.aws.amazon.com/cloudhsm/latest/userguide/initialize-cluster.html), you should have a CA certificate called `customerCA.crt`.

            Save the CA certificate to a path, as this will need to be mounted as a Docker volume in the next step. For this example, we'll save it to `/aws-files/customerCA.crt`.
          </Step>

          <Step title="Run Docker">
            Running Docker with HSM encryption requires setting the HSM-related environment variables as mentioned previously in the [HSM setup instructions](#setup-instructions). You can set these environment variables in your Docker run command.

            We are setting the environment variables for Docker via the command line in this example, but you can also pass in a `.env` file to set these environment variables.

            <Warning>
              If no key is found with the provided key label, the HSM will create a new key with the provided label.
              Infisical depends on an AES and HMAC key to be present in the HSM. If these keys are not present, Infisical will create them. The AES key label will be the value of the `HSM_KEY_LABEL` environment variable, and the HMAC key label will be the value of the `HSM_KEY_LABEL` environment variable with the suffix `_HMAC`.
            </Warning>

            ```bash  theme={"dark"}
            docker run -p 80:8080 \

              # Mount the HSM client files to "/opt/cloudhsm"
              -v /etc/cloudhsm:/opt/cloudhsm \
              # Mount the issuer CA certificate to "/opt/cloudhsm/etc/customerCA.crt"
              -v /aws-files/customerCA.crt:/opt/cloudhsm/etc/customerCA.crt \

              # Set the HSM library path to whats expected within Docker (/opt/cloudhsm/lib/libcloudhsm_pkcs11.so)
              -e HSM_LIB_PATH="/opt/cloudhsm/lib/libcloudhsm_pkcs11.so" \
              # Set the HSM PIN to the username and password of the HSM user, separated by a colon
              -e HSM_PIN=CryptoUserUsername:CryptoUserPassword \
              # Set the HSM slot number to the slot number of the HSM device as found in the previous step
              -e HSM_SLOT=<hsm-device-slot> \
              # Set the HSM key label to a label that will be used to identify the encryption key in the HSM. This key label does not need to exist before hand.
              -e HSM_KEY_LABEL=infisical-crypto-key \

              # The rest of your environment variables ...
              # -e ...
              infisical/infisical:<version> # Replace <version> with the version you want to use
            ```

            We recommend reading further about [using Infisical with Docker](/self-hosting/deployment-options/standalone-infisical).
          </Step>
        </Steps>

        After following these steps, your Docker setup will be ready to use HSM encryption.
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Kubernetes">
    When you are deploying Infisical with the [Kubernetes self-hosting option](/self-hosting/deployment-options/kubernetes-helm), you can still use HSM encryption, but you need to ensure that the HSM client files are present in the container.

    <Tabs>
      <Tab title="Thales Luna Cloud HSM">
        <Note>
          This is only supported on helm chart version `1.7.1` and above. Please see the [Helm Chart Changelog](https://github.com/Infisical/infisical/blob/main/helm-charts/infisical-standalone-postgres/CHANGELOG.md#141-march-19-2025) for more information.
        </Note>

        <Steps>
          <Step title="Create HSM client folder">
            When using Kubernetes, you need to mount the path containing the HSM client files. This section covers how to configure your Infisical instance to use an HSM with Kubernetes. In this example, we are going to be using `/etc/luna-docker`.

            ```bash  theme={"dark"}
            mkdir /etc/luna-docker
            ```

            After [setting up your Luna Cloud HSM client](https://thalesdocs.com/gphsm/luna/7/docs/network/Content/install/client_install/add_dpod.htm), you should have a set of files, referred to as the HSM client. You don't need all the files, but for simplicity we recommend copying all the files from the client.

            A folder structure of a client folder will often look like this:

            ```
            partition-ca-certificate.pem
            partition-certificate.pem
            server-certificate.pem
            Chrystoki.conf
            /plugins
              libcloud.plugin
            /lock
            /libs
              /64
                libCryptoki2.so
            /jsp
              LunaProvider.jar
              /64
                libLunaAPI.so
            /etc
              openssl.cnf
            /bin
              /64
                ckdemo
                lunacm
                multitoken
                vtl
            ```

            The most important parts of the client folder is the `Chrystoki.conf` file, and the `libs`, `plugins`, and `jsp` folders. You need to copy these files to the folder you created in the first step.

            ```bash  theme={"dark"}
              cp -r /<path-to-where-your-luna-client-is-located>/* /etc/luna-docker
            ```

            <Note>
              The `/*` wildcard will copy all files and folders within the HSM client. The wildcard is important to ensure that the file structure is inline with the rest of this guide.
            </Note>

            After copying the files, the `/etc/luna-docker` directory should have the following file structure:

            ```bash  theme={"dark"}
            $ ls -R /etc/luna-docker
            Chrystoki.conf etc lock server-certificate.pem
            Chrystoki.conf.tmp2E jsp partition-ca-certificate.pem setenv
            lch-support-linux-64bit partition-certificate.pem
            bin libs plugins

            /etc/luna-docker/bin:
            64

            /etc/luna-docker/bin/64:
            ckdemo cmu lunacm multitoken vtl

            /etc/luna-docker/etc:
            openssl.cnf

            /etc/luna-docker/jsp:
            64 LunaProvider.jar

            /etc/luna-docker/jsp/64:
            libLunaAPI.so

            /etc/luna-docker/libs:
            64

            /etc/luna-docker/libs/64:
            libCryptoki2.so

            /etc/luna-docker/lock:

            /etc/luna-docker/plugins:
            libcloud.plugin
            ```
          </Step>

          <Step title="Update Chrystoki.conf">
            The `Chrystoki.conf` file is used to configure the HSM client. You need to update the `Chrystoki.conf` file to point to the correct file paths.

            In this example, we will be mounting the `/etc/luna-docker` folder from the host to containers in our deployment's pods at the path `/usr/safenet/lunaclient`. This means the contents of `/etc/luna-docker` on the host will be accessible at `/usr/safenet/lunaclient` within the containers.

            An example config file will look like this:

            ```Chrystoki.conf  theme={"dark"}
              Chrystoki2 = {
                # This path points to the mounted path, /usr/safenet/lunaclient
                LibUNIX64 = /usr/safenet/lunaclient/libs/64/libCryptoki2.so;
              }

              Luna = {
                DefaultTimeOut = 500000;
                PEDTimeout1 = 100000;
                PEDTimeout2 = 200000;
                PEDTimeout3 = 20000;
                KeypairGenTimeOut = 2700000;
                CloningCommandTimeOut = 300000;
                CommandTimeOutPedSet = 720000;
              }

              CardReader = {
                LunaG5Slots = 0;
                RemoteCommand = 1;
              }

              Misc = {
                # Update the paths to point to the mounted path if your folder structure is different from the one mentioned in the previous step.
                PluginModuleDir = /usr/safenet/lunaclient/plugins;
                MutexFolder = /usr/safenet/lunaclient/lock;
                PE1746Enabled = 1;
                ToolsDir = /usr/bin;

              }

              Presentation = {
                ShowEmptySlots = no;
              }

              LunaSA Client = {
                ReceiveTimeout = 20000;
                # Update the paths to point to the mounted path if your folder structure is different from the one mentioned in the previous step.
                SSLConfigFile = /usr/safenet/lunaclient/etc/openssl.cnf;
                ClientPrivKeyFile = ./etc/ClientNameKey.pem;
                ClientCertFile = ./etc/ClientNameCert.pem;
                ServerCAFile = ./etc/CAFile.pem;
                NetClient = 1;
                TCPKeepAlive = 1;
              }


              REST = {
                AppLogLevel = error
                ServerName = <REDACTED>;
                ServerPort = 443;
                AuthTokenConfigURI = <REDACTED>;
                AuthTokenClientId = <REDACTED>;
                AuthTokenClientSecret = <REDACTED>;
                RestClient = 1;
                ClientTimeoutSec = 120;
                ClientPoolSize = 32;
                ClientEofRetryCount = 15;
                ClientConnectRetryCount = 900;
                ClientConnectIntervalMs = 1000;
              }
              XTC = {
                Enabled = 1;
                TimeoutSec = 600;
              }
            ```

            Save the file after updating the paths.
          </Step>

          <Step title="Creating Persistent Volume Claim (PVC)">
            You need to create a Persistent Volume Claim (PVC) to mount the HSM client files to the Infisical deployment.

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: PersistentVolumeClaim
            metadata:
              name: infisical-data-pvc
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 500Mi
            EOF
            ```

            The above command will create a PVC named `infisical-data-pvc` with a storage size of `500Mi`. You can change the storage size if needed.

            Next we need to create a temporary pod with the PVC mounted as a volume, allowing us to copy the HSM client files into this mounted storage.

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: Pod
            metadata:
              name: hsm-setup-pod
            spec:
              containers:
              - name: setup
                image: busybox
                command: ["/bin/sh", "-c", "sleep 3600"]
                volumeMounts:
                - name: hsm-data
                  mountPath: /data
              volumes:
              - name: hsm-data
                persistentVolumeClaim:
                  claimName: infisical-data-pvc
            EOF
            ```

            The above command will create a pod named `hsm-setup-pod` with a busybox image. The pod will sleep for 3600 seconds *(one hour)*, which is enough time to upload the HSM client files to the PVC.

            Ensure that the pod is running and is healthy by running the following command:

            ```bash  theme={"dark"}
            kubectl wait --for=condition=Ready pod/hsm-setup-pod --timeout=60s
            ```

            Next we need to copy the HSM client files into the PVC.

            ```bash  theme={"dark"}
            kubectl exec hsm-setup-pod -- mkdir -p /data/ # Create the data directory
            kubectl cp /etc/luna-docker/. hsm-setup-pod:/data/ # Copy the HSM client files into the PVC
            kubectl exec hsm-setup-pod -- chmod -R 755 /data/ # Set the correct permissions for the HSM client files
            ```

            Finally, we are ready to delete the temporary pod, as we have successfully uploaded the HSM client files to the PVC. This step may take a few minutes to complete.

            ```bash  theme={"dark"}
            kubectl delete pod hsm-setup-pod
            ```
          </Step>

          <Step title="Updating your environment variables">
            Next we need to update the environment variables used for the deployment. If you followed the [setup instructions for Kubernetes deployments](/self-hosting/deployment-options/kubernetes-helm), you should have a Kubernetes secret called `infisical-secrets`.
            We need to update the secret with the following environment variables:

            * `HSM_LIB_PATH` - The path to the HSM client library *(mapped to `/usr/safenet/lunaclient/libs/64/libCryptoki2.so`)*
            * `HSM_PIN` - The PIN for the HSM device that you created when setting up your Luna Cloud HSM client
            * `HSM_SLOT` - The slot number for the HSM device that you selected when setting up your Luna Cloud HSM client
            * `HSM_KEY_LABEL` - The label for the HSM key. If no key is found with the provided key label, the HSM will create a new key with the provided label.

            The following is an example of the secret that you should update:

            ```yaml  theme={"dark"}
            apiVersion: v1
            kind: Secret
            metadata:
              name: infisical-secrets
            type: Opaque
            stringData:
              # ... Other environment variables ...
              HSM_LIB_PATH: "/usr/safenet/lunaclient/libs/64/libCryptoki2.so" # If you followed this guide, this will be the path of the Luna Cloud HSM client
              HSM_PIN: "<your-hsm-device-pin>"
              HSM_SLOT: "<hsm-device-slot>"
              HSM_KEY_LABEL: "<your-key-label>"
            ```

            Save the file after updating the environment variables, and apply the secret changes

            ```bash  theme={"dark"}
            kubectl apply -f ./secret-file-name.yaml
            ```
          </Step>

          <Step title="Updating the Deployment">
            After we've successfully configured the PVC and updated our environment variables, we are ready to update the deployment configuration so that the pods it creates can access the HSM client files.

            ```yaml  theme={"dark"}
              # ... The rest of the values.yaml file ...
              
              image:
                repository: infisical/infisical
                tag: "v0.117.1-postgres"
                pullPolicy: IfNotPresent

              extraVolumeMounts:
                - name: hsm-data
                  mountPath: /usr/safenet/lunaclient # The path we will mount the HSM client files to

              extraVolumes:
                - name: hsm-data 
                  persistentVolumeClaim:
                    claimName: infisical-data-pvc # The PVC we created in the previous step

              # ... The rest of the values.yaml file ...
            ```
          </Step>

          <Step title="Upgrading the Helm Chart">
            After updating the values.yaml file, you need to upgrade the Helm chart in order for the changes to take effect.

            ```bash  theme={"dark"}
            helm upgrade --install infisical infisical-helm-charts/infisical-standalone --values /path/to/values.yaml
            ```
          </Step>

          <Step title="Restarting the Deployment">
            After upgrading the Helm chart, you need to restart the deployment in order for the changes to take effect.

            ```bash  theme={"dark"}
            kubectl rollout restart deployment/infisical-infisical
            ```
          </Step>
        </Steps>

        After following these steps, your Kubernetes setup will be ready to use HSM encryption.
      </Tab>

      <Tab title="Fortanix HSM">
        <Steps>
          <Step title="Set up Fortanix HSM">
            First, you need to set up Fortanix HSM by:

            1. Creating an App in Fortanix:
               * Set Interface value to be PKCS#11
               * Select API key as authentication method
               * Assign app to a group

                        <img src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/platform/kms/hsm/fortanix-hsm-setup.png" alt="Fortanix HSM Setup" />

            2. Take note of the domain (e.g., apac.smartkey.io). You will need this when setting up the configuration file.
          </Step>

          <Step title="Create configuration files">
            Create a directory to store the Fortanix configuration files:

            ```bash  theme={"dark"}
            mkdir -p /etc/fortanix-hsm
            ```

            Download the Fortanix PKCS#11 library for Linux from the [Fortanix PKCS#11 installation page](https://fortanix.zendesk.com/hc/en-us/sections/4408769080724-PKCS-11).

            Create a configuration file named `pkcs11.conf` with the following content:

            ```
            api_endpoint = "https://apac.smartkey.io"
            prevent_duplicate_opaque_objects = true
            retry_timeout_millis = 60000
            ```

            Note: Replace `apac.smartkey.io` with your actual Fortanix domain if different.
          </Step>

          <Step title="Creating a Persistent Volume Claim (PVC)">
            Create a Persistent Volume Claim to store the Fortanix files:

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: PersistentVolumeClaim
            metadata:
              name: fortanix-hsm-pvc
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 100Mi
            EOF
            ```

            Create a temporary pod to upload the files:

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: Pod
            metadata:
              name: fortanix-setup-pod
            spec:
              containers:
              - name: setup
                image: busybox
                command: ["/bin/sh", "-c", "sleep 3600"]
                volumeMounts:
                - name: fortanix-data
                  mountPath: /data
              volumes:
              - name: fortanix-data
                persistentVolumeClaim:
                  claimName: fortanix-hsm-pvc
            EOF
            ```

            Ensure the pod is running:

            ```bash  theme={"dark"}
            kubectl wait --for=condition=Ready pod/fortanix-setup-pod --timeout=60s
            ```

            Copy the Fortanix files to the PVC:

            ```bash  theme={"dark"}
            kubectl exec fortanix-setup-pod -- mkdir -p /data/
            kubectl cp /etc/fortanix-hsm/fortanix_pkcs11_4.37.2554.so fortanix-setup-pod:/data/
            kubectl cp /etc/fortanix-hsm/pkcs11.conf fortanix-setup-pod:/data/
            kubectl exec fortanix-setup-pod -- chmod -R 755 /data/
            ```

            Delete the temporary pod:

            ```bash  theme={"dark"}
            kubectl delete pod fortanix-setup-pod
            ```
          </Step>

          <Step title="Update the Kubernetes Secret">
            Update your Kubernetes secret with the Fortanix HSM environment variables:

            ```yaml  theme={"dark"}
            apiVersion: v1
            kind: Secret
            metadata:
              name: infisical-secrets
            type: Opaque
            stringData:
              # ... Other environment variables ...
              HSM_LIB_PATH: "/etc/fortanix-hsm/fortanix_pkcs11_4.37.2554.so"  # Path to the PKCS#11 library in the container
              HSM_PIN: "<your-fortanix-api-key>"  # Your Fortanix app API key used for authentication
              HSM_SLOT: "0"            # Slot value (can be set to 0 for Fortanix HSM as it's arbitrary)
              HSM_KEY_LABEL: "hsm-key-label"  # Label to identify the encryption key in the HSM
              FORTANIX_PKCS11_CONFIG_PATH: "/etc/fortanix-hsm/pkcs11.conf"  # Path to Fortanix configuration file
            ```

            Apply the updated secret:

            ```bash  theme={"dark"}
            kubectl apply -f ./secret-file-name.yaml
            ```
          </Step>

          <Step title="Update Helm Values">
            Update your Helm values to mount the Fortanix HSM files:

            ```yaml  theme={"dark"}
            # ... The rest of the values.yaml file ...

            image:
              repository: infisical/infisical
              tag: "v0.117.1-postgres"
              pullPolicy: IfNotPresent

            extraVolumeMounts:
              - name: fortanix-data
                mountPath: /etc/fortanix-hsm  # The path where Fortanix files will be available

            extraVolumes:
              - name: fortanix-data
                persistentVolumeClaim:
                  claimName: fortanix-hsm-pvc

            # ... The rest of the values.yaml file ...
            ```

            <Warning>
              Note: Fortanix HSM integration only works for AMD64 CPU architectures.
            </Warning>
          </Step>

          <Step title="Upgrade and Restart">
            Upgrade the Helm chart with the new values:

            ```bash  theme={"dark"}
            helm upgrade --install infisical infisical-helm-charts/infisical-standalone --values /path/to/values.yaml
            ```

            Restart the deployment:

            ```bash  theme={"dark"}
            kubectl rollout restart deployment/infisical-infisical
            ```
          </Step>
        </Steps>

        After following these steps, your Kubernetes setup will be ready to use Fortanix HSM encryption.
      </Tab>

      <Tab title="AWS CloudHSM">
        ### Prerequisites

        * An [activated AWS CloudHSM cluster](https://docs.aws.amazon.com/cloudhsm/latest/userguide/activate-cluster.html) with at least 1 HSM device.
        * A [HSM user with the `Crypto User` role](https://docs.aws.amazon.com/cloudhsm/latest/userguide/cloudhsm_cli-user-create.html). In this guide we are using a user with the username `testUser` and the password `testPassword`.
        * A Kubernetes cluster

        <Note>
          AWS CloudHSM is supported on helm chart version `1.7.1` and above. Please see the [Helm Chart Changelog](https://github.com/Infisical/infisical/blob/main/helm-charts/infisical-standalone-postgres/CHANGELOG.md#141-march-19-2025) for more information.
        </Note>

        <Steps>
          <Step title="Creating Persistent Volume Claim (PVC)">
            <Accordion title="Prerequisites for using AWS EKS">
              If you're using AWS EKS, you need to specify a storage class for the PVC and ensure that the EBS CSI Driver is installed and running.

              By default, EKS exposes `gp2` as the default storage class. Below are the steps required for setting the default storage class and ensuring the EBS CSI Driver is installed and running:

              <Steps>
                <Step title="Enable OIDC authentication">
                  Enable OIDC authentication for the EKS cluster:

                  ```bash  theme={"dark"}
                  eksctl utils associate-iam-oidc-provider \
                  --region <your-region> \
                  --cluster <your-cluster-name> \
                  --approve
                  ```

                  * Replace `<your-region>` with your AWS region.
                  * Replace `<your-cluster-name>` with your cluster name.
                </Step>

                <Step title="Check if the EBS CSI Driver is installed and running">
                  1. Check if EBS CSI Driver is installed and running by running the following command:

                  ```bash  theme={"dark"}
                  kubectl get pods -n kube-system | grep ebs-csi
                  ```

                  If you see no pods, you need to install the EBS CSI Driver as seen in the next step.
                </Step>

                <Step title="Install EBS CSI Driver using eksctl">
                  Create a new IAM service account for the EBS CSI Driver:

                  ```bash  theme={"dark"}
                  eksctl create iamserviceaccount \
                    --name ebs-csi-controller-sa \
                    --namespace kube-system \
                    --region <your-region> \
                    --cluster <your-cluster-name> \
                    --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
                    --approve \
                    --role-name AmazonEKS_EBS_CSI_DriverRole
                  ```

                  * Replace `<your-cluster-name>` with your cluster name.
                  * Replace `<your-region>` with your AWS region.

                  Install the EBS CSI Driver:

                  ```bash  theme={"dark"}
                  eksctl create addon \
                  --name aws-ebs-csi-driver \
                  --cluster <your-cluster-name> \
                  --region <your-region> \
                  --service-account-role-arn arn:aws:iam::<account-id>:role/AmazonEKS_EBS_CSI_DriverRole \
                  --force
                  ```

                  * Replace `<your-cluster-name>` with your cluster name.
                  * Replace `<your-region>` with your AWS region.
                  * Replace `<account-id>` with your actual account ID. Can be obtained by running `aws sts get-caller-identity --query Account --output text`.
                </Step>

                <Step title="Verify the EBS CSI Driver is installed and running">
                  Verify the EBS CSI Driver is installed and running by running the following command:

                  ```bash  theme={"dark"}
                  kubectl get pods -n kube-system | grep ebs-csi
                  ```

                  You should see an output like this:

                  ```bash  theme={"dark"}
                  kubectl get pods -n kube-system | grep ebs-csi
                  ebs-csi-controller-6b6bbf996-rvf8r   6/6     Running   0          21s
                  ebs-csi-controller-6b6bbf996-vk4ng   6/6     Running   0          21s
                  ebs-csi-node-c6vbb                   3/3     Running   0          21s
                  ebs-csi-node-s9zlr                   3/3     Running   0          21s
                  ```
                </Step>

                <Step title="Find the enabled storage class">
                  You can find the enabled storage class by running the following command:

                  ```bash  theme={"dark"}
                  kubectl get storageclass
                  ```

                  You should see an output like this:

                  ```bash  theme={"dark"}
                  $ kubectl get storageclass

                  NAME   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
                  gp2    kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  65m
                  ```

                  In this case, the enabled storage class is `gp2`.
                </Step>

                <Step title="Set the default storage class">
                  You can set the default PVC storage class by patching the storage class with the following command:

                  ```bash  theme={"dark"}
                  kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
                  ```

                  This will set the `gp2` storage class as the default storage class.

                  Now when you run `kubectl get storageclass`, you should see that `gp2` is the default storage class.

                  ```bash  theme={"dark"}
                  $ kubectl get storageclass 

                  NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
                  gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  68m
                  ```

                  Notice the `(default)` next to the `gp2` storage class.
                </Step>
              </Steps>
            </Accordion>

            You need to create a Persistent Volume Claim (PVC) to mount the HSM client files to the Infisical deployment.

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: PersistentVolumeClaim
            metadata:
              name: cloudhsm-data-pvc
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 500Mi
            EOF
            ```

            The above command will create a PVC named `cloudhsm-data-pvc` with a storage size of `500Mi`. You can change the storage size if needed.

            Next we need to create a temporary pod with the PVC mounted as a volume, allowing us to copy the HSM client files into this mounted storage.

            ```bash  theme={"dark"}
            kubectl apply -f - <<EOF
            apiVersion: v1
            kind: Pod
            metadata:
              name: cloudhsm-setup-pod
            spec:
              containers:
              - name: setup
                image: debian:bookworm
                command: ["/bin/sh", "-c", "sleep 7200"]
                volumeMounts:
                - name: cloudhsm-data
                  mountPath: /data
              volumes:
              - name: cloudhsm-data
                persistentVolumeClaim:
                  claimName: cloudhsm-data-pvc
            EOF
            ```

            The above command will create a pod named `cloudhsm-setup-pod` with a Debian image. The pod will sleep for 7200 seconds *(two hours)*, which is enough time to set up the PVC and configure the HSM client.

            Ensure that the pod is running and is healthy by running the following command:

            ```bash  theme={"dark"}
            kubectl wait --for=condition=Ready pod/cloudhsm-setup-pod --timeout=120s
            ```
          </Step>

          <Step title="Configure the PVC">
            We need to configure the PVC to work with the CloudHSM, so Infisical can consume the HSM client files.

            **2.1. Start a shell in the PVC pod:**

            This will allow us to run commands directly within the setup pod. We'll use this to configure the CloudHSM client and to validate that it's working correctly.

            ```bash  theme={"dark"}
            kubectl exec -it cloudhsm-setup-pod -- /bin/sh
            ```

            **2.2. Install the necessary packages:**

            This will install the necessary packages to allow us to test and install the CloudHSM client.

            ```bash  theme={"dark"}
            apt-get update -y
            apt-get install opensc telnet wget -y
            ```

            **2.3. Try to reach the HSM device:**

            We need to validate that we're able to reach the HSM device from within Kubernetes. You can use telnet to ping the HSM device like so:

            ```bash  theme={"dark"}
            telnet <HSM_ENI_IPV4_ADDRESS> 2223
            ```

            You should see an output like this:

            ```bash  theme={"dark"}
            $ telnet <HSM_ENI_IPV4_ADDRESS> 2223                                                 
            Trying <HSM_ENI_IPV4_ADDRESS>...
            Connected to <HSM_ENI_IPV4_ADDRESS>.
            ```

            If it gets stuck on `Trying ....`, you may have configured your HSM client's security group incorrectly. Make sure you configure the security group to allow traffic from EKS on port 2223-2225.

            **2.4. Install the AWS CloudHSM client:**

            The Infisical images run on Debian, so we need to install a Debian-compatible version of the AWS CloudHSM client.

            ```bash  theme={"dark"}
            wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Jammy/cloudhsm-pkcs11_latest_u22.04_amd64.deb
            apt-get install ./cloudhsm-pkcs11_latest_u22.04_amd64.deb -y
            ```

            **2.5. Configure the CloudHSM client:**

            After installing the CloudHSM client, you should see all related files in the `/opt/cloudhsm/` directory on the CloudHSM setup pod.

            You need to run the `configure-pkcs11` binary which will configure the client to connect with your AWS CloudHSM cluster. Depending on if you have multiple HSM's inside your cluster, you'll need to run the command with different arguments. Below you'll find the appropriate command for your use case:

            <AccordionGroup>
              <Accordion title="Single HSM">
                ```bash  theme={"dark"}
                /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_ENI_IPV4_ADDRESS> --disable-key-availability-check
                ```

                <Info>
                  To use a single HSM, you must first manage client key durability settings by setting `disable_key_availability_check` to true by passing the `--disable-key-availability-check` flag. For more information read the [Key Synchronization](https://docs.aws.amazon.com/cloudhsm/latest/userguide/manage-key-sync.html) section in the AWS CloudHSM documentation.
                </Info>
              </Accordion>

              <Accordion title="Multiple HSM's">
                ```bash  theme={"dark"}
                /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_ENI_IPV4_ADDRESS_1> <HSM_ENI_IPV4_ADDRESS_2> ... --disable-key-availability-check
                ```
              </Accordion>
            </AccordionGroup>

            **2.6. Verify the CloudHSM client is configured correctly:**

            You can verify the CloudHSM client is configured correctly by running the following command:

            ```bash  theme={"dark"}
            cat /opt/cloudhsm/etc/cloudhsm-pkcs11.cfg
            ```

            You should see an output like this:

            ```json  theme={"dark"}
            {
              "clusters": [
                {
                  "type": "hsm1",
                  "cluster": {
                    "hsm_ca_file": "/opt/cloudhsm/etc/customerCA.crt",
                    "servers": [
                      {
                        "hostname": "172.31.39.155",
                        "port": 2223,
                        "enable": true
                      }
                    ],
                    "options": {
                      "disable_key_availability_check": true
                    }
                  }
                }
              ],
              "logging": {
                "log_type": "file",
                "log_file": "/opt/cloudhsm/run/cloudhsm-pkcs11.log",
                "log_level": "info",
                "log_interval": "daily"
              }
            }
            ```

            **2.7. Exit the pod:**

            Exit the pod by running the following command:

            ```bash  theme={"dark"}
            exit
            ```

            **2.8. Copy your issuer CA certificate to the PVC:**

            When you initialized your HSM, you were prompted to download the cluster CSR and sign it.
            In order to use the HSM with Infisical, you need to obtain the issuer CA certificate that was used to sign the cluster CSR.

            If you followed [the official AWS documentation](https://docs.aws.amazon.com/cloudhsm/latest/userguide/initialize-cluster.html), you should have a CA certificate called `customerCA.crt`.

            Copy the CA certificate from your local machine to the setup pod:

            ```bash  theme={"dark"}
            kubectl cp /path/to/customerCA.crt cloudhsm-setup-pod:/opt/cloudhsm/etc/customerCA.crt
            ```

            Ensure that the file is at `/opt/cloudhsm/etc/customerCA.crt` inside the setup pod by running the following command:

            ```bash  theme={"dark"}
            kubectl exec -it cloudhsm-setup-pod -- cat /opt/cloudhsm/etc/customerCA.crt
            ```

            **2.9. Test the HSM client:**

            Finally, after we're done configuring the HSM client, we need to test it to ensure that it's working correctly.

            First, start a new shell into the setup pod by running the same shell command as before:

            ```bash  theme={"dark"}
            kubectl exec -it cloudhsm-setup-pod -- /bin/sh
            ```

            Next, try generating a random 32 bytes long string by running the following command:

            ```bash  theme={"dark"}
            pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
              --login --pin <crypto-user-username>:<crypto-user-password> \
              --generate-random 32 | base64
            ```

            You should see an output like this:

            ```bash  theme={"dark"}
            Using slot 0 with a present token (0x2000000000000001)
            av1dlhVEsssjpcTNS+ysGUoKWH6+/PCaEDIdal5oQc0=
            ```

            <Note>
              Replace the `<crypto-user-username>:<crypto-user-password>` with your username and password combination of the Crypto user you have created that you want to use to perform cryptographic operations.

              In AWS CloudHSM, the PIN is always the username and password separated by a colon.
            </Note>

            **2.10. Copy the configured client to the PVC:**

            Copy from the HSM files into the `/data` directory in the PVC, which is what will be mounted for the Infisical deployment.

            ```bash  theme={"dark"}
            cp -r /opt/cloudhsm/. /data/
            ```

            Verify the files were copied correctly by running the following command:

            ```bash  theme={"dark"}
            ls -la /data/
            ```

            You should see an output like this:

            ```bash  theme={"dark"}
            drwxr-xr-x. 8 root root 4096 Oct 13 18:50 .
            drwxr-xr-x. 1 root root  131 Oct 13 18:29 ..
            drwxr-xr-x. 2 root root 4096 Oct 13 18:50 bin
            drwxr-xr-x. 3 root root 4096 Oct 13 18:50 doc
            drwxr-xr-x. 2 root root 4096 Oct 13 18:50 etc
            drwxr-xr-x. 3 root root 4096 Oct 13 18:50 include
            drwxr-xr-x. 2 root root 4096 Oct 13 18:50 lib
            drwxr-xr-t. 2 root root 4096 Oct 13 18:50 run
            ```

            **2.11. Set the correct permissions for the HSM client files:**

            ```bash  theme={"dark"}
            chmod -R 755 /data/
            ```

            **2.12. Exit the pod:**

            Exit the pod by running the following command:

            ```bash  theme={"dark"}
            exit
            ```

            **2.13. Delete the setup pod:**

            Delete the setup pod by running the following command:

            ```bash  theme={"dark"}
            kubectl delete pod cloudhsm-setup-pod
            ```
          </Step>

          <Step title="Updating your environment variables">
            Next we need to update the environment variables used for the deployment. If you followed the [setup instructions for Kubernetes deployments](/self-hosting/deployment-options/kubernetes-helm), you should have a Kubernetes secret called `infisical-secrets`.
            We need to update the secret with the following environment variables:

            * `HSM_LIB_PATH` - The path to the CloudHSM PKCS#11 library *(mapped to `/opt/cloudhsm/lib/libcloudhsm_pkcs11.so`)*
            * `HSM_PIN` - The PIN for the HSM device, which is the username and password of your Crypto User separated by a colon (e.g., `testUser:testPassword`)
            * `HSM_SLOT` - The slot number for the HSM device that you found in the previous step
            * `HSM_KEY_LABEL` - The label for the HSM key. If no key is found with the provided key label, the HSM will create a new key with the provided label.

            The following is an example of the secret that you should update:

            ```yaml  theme={"dark"}
            apiVersion: v1
            kind: Secret
            metadata:
              name: infisical-secrets
            type: Opaque
            stringData:
              # ... Other environment variables ...
              HSM_LIB_PATH: "/opt/cloudhsm/lib/libcloudhsm_pkcs11.so"
              HSM_PIN: "testUser:testPassword"  # Replace with your actual Crypto User credentials
              HSM_SLOT: "0"  # Replace with your actual slot number
              HSM_KEY_LABEL: "infisical-crypto-key"
            ```

            Save the file after updating the environment variables, and apply the secret changes

            ```bash  theme={"dark"}
            kubectl apply -f ./secret-file-name.yaml
            ```
          </Step>

          <Step title="Updating the Deployment">
            After we've successfully configured the PVC and updated our environment variables, we are ready to update the deployment configuration so that the pods it creates can access the HSM client files.

            ```yaml  theme={"dark"}
              # ... The rest of the values.yaml file ...
              infisical:
                image:
                  repository: infisical/infisical
                  tag: "v0.151.0"
                  pullPolicy: IfNotPresent

                extraVolumeMounts:
                  - name: cloudhsm-data
                    mountPath: /opt/cloudhsm  # The path we will mount the HSM client files to

                extraVolumes:
                  - name: cloudhsm-data 
                    persistentVolumeClaim:
                      claimName: cloudhsm-data-pvc  # The PVC we created in the previous step

              # ... The rest of the values.yaml file ...
            ```

            <Warning>
              Make sure to set the `tag` to **`v0.151.0-nightly-20251013.1` or above**, as this is the minimum Infisical version that supports AWS CloudHSM.
            </Warning>

            <Warning>
              Ensure that the configuration file at `/opt/cloudhsm/etc/cloudhsm-pkcs11.cfg` references the correct path for the issuer CA certificate (`/opt/cloudhsm/etc/customerCA.crt`). This should already be configured correctly if you followed the previous steps.
            </Warning>
          </Step>

          <Step title="Upgrading the Helm Chart">
            After updating the values.yaml file, you need to upgrade the Helm chart in order for the changes to take effect.

            ```bash  theme={"dark"}
            helm repo update
            helm upgrade --install infisical infisical-helm-charts/infisical-standalone --values /path/to/values.yaml
            ```
          </Step>

          <Step title="Restarting the Deployment">
            After upgrading the Helm chart, you need to restart the deployment in order for the changes to take effect.

            ```bash  theme={"dark"}
            kubectl rollout restart deployment/infisical-infisical-standalone-infisical
            ```
          </Step>
        </Steps>

        After following these steps, your Kubernetes setup will be ready to use AWS CloudHSM encryption.
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

## Disabling HSM Encryption

To disable HSM encryption, navigate to Infisical's Server Admin Console and set the KMS encryption strategy to `Software-based Encryption`. This will revert the encryption strategy back to the default software-based encryption.

<Note>
  In order to disable HSM encryption, the Infisical instance must be able to access the HSM device. If the HSM device is no longer accessible, you will not be able to disable HSM encryption.
</Note>