HAProxy
This guide will walk you through the process of securing the SSL keys used for SSL termination in HAProxy by utilizing a Thales Luna HSM in conjunction with the OpenSSL toolkit, enhanced with GemEngine support. HAProxy is a powerful, open-source load balancer that efficiently distributes network or application traffic across multiple servers, ensuring high availability and reliability. By integrating HAProxy with the Thales Luna HSM, we enhance security for SSL termination, providing a robust solution for secure data transport. The Thales Luna HSM provides a dedicated, tamper-resistant environment for cryptographic operations, ensuring that private keys are never exposed to the application layer.
The key benefits of this integration are:
-
Secure generation, storage, and protection of the identity signing private keys using either FIPS 140-2 or FIPS 140-3 Level 3 validated hardware.
-
Full life cycle management of the keys to ensure their integrity and reliability throughout their usage.
-
Maintenance of a comprehensive HSM audit trail for transparency and accountability in key operations.
-
Significant performance enhancements by offloading cryptographic operations from application servers.
Supported Platforms
This integration is tested/verified with Luna HSM on the following operating systems:
Platforms Tested | HAProxy Version | GemEngine Version | OpenSSL Version |
---|---|---|---|
RHEL 8 | 2.2 | 1.3 | 1.0.2 FIPS |
Ubuntu 18.04 | 1.8 | 1.3 | 1.1.1 Non FIPS, 1.0.2 FIPS |
RHEL 7 | 1.8 | 1.2 | 1.0.2 FIPS |
CentOS 7 | 1.8 | 1.2 | 1.0.2 FIPS |
Prerequisites
Before proceeding with the integration, ensure the following tasks are completed:
Configure Luna HSM
Follow these steps to set up your on-premise Luna HSM:
Ensure that the HSM is set up, initialized, provisioned, and ready for deployment. For more information, refer to Luna HSM documentation.
Create a partition that will be later on used by HAProxy.
Create and exchange certificate between the Luna Network HSM and client system. Register client and assign partition to create an NTLS connection.
Initialize Crypto Officer and Crypto User roles for the registered partition.
Run the following command to verify that the partition has been successfully registered and configured:
/usr/safenet/lunaclient/bin/lunacm
Upon successful execution, you should observe an output similar to the example provided below:
lunacm (64-bit) v10.4.0-417. Copyright (c) 2021 Thales Group. All rights reserved. Available HSMs: Slot Id -> 0 Label -> HAProxy Serial Number -> 1280780175865 Model -> LunaSA 7.3.0 Firmware Version -> 7.3.0 Configuration -> Luna User Partition With SO (PW) Key Export With Cloning Mode Slot Description -> Net Token Slot Current Slot Id -> 0
Refer to Luna HSM documentation for detailed steps on creating NTLS connection, initializing the partitions, and assigning various user roles.
For proper configuration of a PED-based Luna HSM, it is recommended to activate partition policies 22 and 23, allowing for both activation and auto-activation.
This integration is fully tested with both HA and FIPS modes.
Set up Luna HSM in FIPS mode
To configure Luna HSM in FIPS Mode, it's important to ensure that your RSA key generation methods comply with FIPS 186-3/4 standards. Specifically, FIPS 186-3/4 approves two methods for generating keys: 186-3 with primes and 186-3 with aux primes. This means that RSA PKCS and X9.31 key generation methods are no longer allowed when operating your Luna HSM in a FIPS-compliant mode. When using the Luna HSM in FIPS mode, you should make adjustments to your configuration settings by following these steps:
Open the configuration file for your Luna HSM.
Look for the [Misc]
section within the configuration file.
Add or modify the following setting within the [Misc]
section:
RSAKeyGenMechRemap=1
This setting instructs the Luna HSM to redirect older key generation mechanisms to the newly approved mechanism when the HSM is operating in FIPS mode.
This adjustment is not necessary for the Universal Client.
This configuration change applies exclusively to Luna Client 7.x.
Set up Luna HSM HA group
Refer to Luna HSM documentation for HA steps and details regarding configuring and setting up two or more HSM boxes on host systems. You must enable the HAOnly
setting in HA for failover to work so that if the primary goes down due to any reason, all calls get automatically routed to the secondary until the primary recovers and starts up.
Download the GemEngine toolkit
To download the GemEngine toolkit with GemEngine support, follow these steps:
Visit the Thales Customer Support portal.
Use the appropriate Doc ID to find and download your desired version of the GemEngine toolkit:
-
GemEngine v1.3: Doc ID KB0017806
-
GemEngine v1.2: Doc ID KB0016309
Ensure you are logged into your Thales Customer Support account to access the downloads.
Set up HAProxy
For this integration, it's recommended to use an Apache web server to serve a static webpage. The following three machines are used in this setup:
- Primary Machine: Acts as the Load Balancer with HAProxy installed. For detailed installation instructions, refer to the HAProxy Documentation.
If you need to install HAProxy with a custom OpenSSL, refer to the Appendix section of this document.
If using Luna HSM in FIPS mode, HAProxy should also be built with OpenSSL that supports the FIPS module.
- Two Secondary Machines: Operate as backend servers with FQDN and IP enabled, running Apache and serving static content.
You can modify this configuration according to your requirements.
Integrate Luna HSM with HAProxy
You can integrate Luna HSM with HAProxy by either generating new SSL keys or migrating your existing keys. If you choose to generate new keys, you need to create a private key and self-signed certificate using OpenSSL with GemEngine, and configure HAProxy for SSL termination. Alternatively, if you have existing SSL keys, you can use them by copying the private key and certificate to the appropriate directory and updating the HAProxy configuration file to reference these files. This flexibility allows you to seamlessly integrate Luna HSM with HAProxy while leveraging your existing security infrastructure or establishing new, secure connections as needed.
Integrate Luna HSM with HAProxy by generating new SSL keys
To integrate Luna HSM with HAProxy, you need to perform the following tasks:
Configure OpenSSL to use GemEngine
Follow these steps to configure OpenSSL to use GemEngine:
Extract the GemEngine toolkit to any directory of your choice.
Locate the OpenSSL engines directory:
-
Use the
gembuild
tool to find the location of the OpenSSL engines directory. This tool is available in the directory where you extracted the GemEngine toolkit. -
Run the following command:
./gembuild locate-engines
- This command will provide the location of the
libgem.so
file. By default, the OpenSSL engines directory is located at/usr/lib64/openssl/engines
.
Copy the libgem.so
file to the OpenSSL engines directory for your specific OpenSSL version. For example:
cp builds/linux/rhel/64/1.0.2/libgem.so /usr/lib64/openssl/engines
Verify GemEngine loading:
- Execute the following command to verify that the GemEngine is loading correctly:
openssl engine gem -v
- You should see an output similar to the following:
(gem) Gem engine support enginearg, openSession, closeSession, login, logout, engineinit, CONF_PATH, ENGINE_INIT, ENGINE2_INIT, engine2init, DisableCheckFinalize, SO_PATH, GET_HA_STATE, SET_FINALIZE_PENDING, SKIP_C_INITIALIZE, IntermediateProcesses
If you are installing OpenSSL from source, refer to the README-GEMBUILD
text file in the /docs
directory for further details on compiling and building with GemEngine.
Create a passfile and store the partition password in it:
echo> /tmp/passfile
Update the Chrystoki.conf
file:
-
Open the
/etc/Chrystoki.conf
file in a text editor. -
Add the following GemEngine section to the file:
GemEngine = { LibPath = /usr/safenet/lunaclient/lib/libCryptoki2_64.so; LibPath64 = /usr/safenet/lunaclient/lib/libCryptoki2_64.so; EnableDsaGenKeyPair = 1; EnableRsaGenKeyPair = 1; DisablePublicCrypto = 1; EnableRsaSignVerify = 1; EnableLoadPubKey = 1; EnableLoadPrivKey = 1; DisableCheckFinalize = 0; IntermediateProcesses = 0; DisableEcdsa = 1; DisableDsa = 0; DisableRand = 0; EngineInit =:0:0:passfile= ; EnableLoginInit = 1; }
Make sure to replace placeholders like <partition_password>
, <slot_id>
, and <path_to_passfile>
with your actual values.
Configure HAProxy for SSL termination
Follow these steps to configure HAProxy for SSL termination using GemEngine:
Run the following command to generate a private key:
openssl genrsa -engine gem -out key.pem
Use the private key generated in the previous step to create a self-signed certificate:
openssl req -engine gem -new -x509 -days 365 -key key.pem -out cert.cer
This integration uses self-signed certificates for a test environment only. For a production environment, use a certificate authority to issue the certificate.
Copy the private key and certificate to a new file at /etc/pki/tls/certs/haproxy.pem
using the following command:
cat key.pem cert.cer > /etc/pki/tls/certs/haproxy.pem
Open the HAProxy configuration file (/etc/opt/rh/rh-haproxy18/haproxy/haproxy.cfg
) in a text editor and add the following code:
global log 127.0.0.1 local2 pidfile /var/run/rh-haproxy18-haproxy.pid maxconn 4000 pidfile /var/run/haproxy.pid user haproxy group hsmusers daemon ssl-engine gem tune.ssl.default-dh-param 2048 defaults mode http log global option httplog option dontlognull retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s frontend https-in bind *:80 use_backend static option forwardfor bind *:443 ssl crt /etc/pki/tls/certs/haproxy.pem backend static balance roundrobin server server1.example.com 10.164.76.117:80 check server server2.example.com 10.164.78.118:80 check
The actual path for haproxy.cfg
may vary depending on your HAProxy installation. The fields in haproxy.cfg
may also vary according to your requirements. Follow the HAProxy Documentation for detailed information on each field. Ensure you add ssl-engine gem
to the global section so that OpenSSL can use GemEngine.
Check and set SELinux
to permissive mode:
- Temporarily set SELinux to permissive mode by running:
setenforce 0
- To make this change permanent, edit the SELinux configuration file:
sudo nano /etc/selinux/config
- Change the following line:
SELINUX=permissive
- Reboot the system for the changes to take effect:
sudo reboot
If you are using Ubuntu, you can skip this step.
Start the HAProxy Service:
- Start the HAProxy service by running:
sudo systemctl start haproxy.service
- Ensure HAProxy is allowed through the firewall. Add the HAProxy service to the firewall daemon:
sudo firewall-cmd --add-service=haproxy --permanent sudo firewall-cmd --reload
Verify that the HAProxy service starts without any errors:
sudo systemctl status haproxy.service -l
You should see output indicating that the service is active and running, similar to this:
rh-haproxy18-haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/rh-haproxy18-haproxy.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2019-03-01 12:08:44 IST; 3s ago Main PID: 17189 (haproxy) Tasks: 2 CGroup: /system.slice/rh-haproxy18-haproxy.service +-17189 /opt/rh/rh-haproxy18/root/usr/sbin/haproxy -Ws -f /etc/opt/rh/rh-haproxy18/haproxy/haproxy.cfg -p /run/rh-haproxy18-haproxy.pid +-17197 /opt/rh/rh-haproxy18/root/usr/sbin/haproxy -Ws -f /etc/opt/rh/rh-haproxy18/haproxy/haproxy.cfg -p /run/rh-haproxy18-haproxy.pid Mar 01 12:08:42 localhost.localdomain systemd[1]: Starting HAProxy Load Balancer... Mar 01 12:08:43 localhost.localdomain haproxy[17181]: STC client identity not configured Mar 01 12:08:44 localhost.localdomain haproxy[17189]: STC client identity not configured Mar 01 12:08:44 localhost.localdomain systemd[1]: Started HAProxy Load Balancer.
Open any web browser and navigate to:
https://:443
When prompted, accept the self-signed certificate. Verify the certificate details to ensure it matches the one you created.
Integrate Luna HSM with HAProxy by migrating existing SSL keys
To integrate Luna HSM with HAProxy using existing SSL keys, ensure that the HAProxy server is already configured and running with SSL, where the SSL certificate and keys were generated by OpenSSL and stored in a directory. Follow these steps to migrate your existing SSL keys:
Execute the steps outlined in the Configure OpenSSL to use GemEngine section to set up OpenSSL with GemEngine.
Find the directory where your SSL private key and certificate are stored.
Run the following command to extract the public key from your private key:
openssl rsa -in server.key -pubout -out pubkey.pem
Replace server.key
with the name of your private key file.
Use the following command to convert your private key to PKCS#8 format:
openssl pkcs8 -in server.key -topk8 -nocrypt -out privatekey.pem
Replace server.key
with the name of your private key file.
Use the CMU utility provided with Luna Client to import the public key and private key to the HSM.
- For the public key:
/usr/safenet/lunaclient/bin/cmu import -inputFile pubkey.pem -label haproxy_public_key -pubkey=rsa
- For the private key:
/usr/safenet/lunaclient/bin/cmu importkey -PKCS8 -in privatekey.pem -keyalg RSA
When prompted, provide the partition password.
Verify keys on Luna HSM partition:
- Check that the keys are generated on the Luna HSM partition and note the private key handle:
/usr/safenet/lunaclient/bin/cmu list
- Example output:
Certificate Management Utility (64-bit) v10.3.0-275. Copyright (c) 2020 SafeNet. All rights reserved. Please enter password for token in slot 0 : ******* handle=2000001 label=CMU Unwrapped RSA Private Key handle=2000002 label=haproxy_public_key
If you have multiple keys, you can recognize the private key by providing it a label. Use the following command:
/usr/safenet/lunaclient/bin/cmu setattribute -handle=2000001 -label=haproxy_private_key
Ensure that the private key label matches the label of the public key:
/usr/safenet/lunaclient/bin/cmu list
Example output:
Certificate Management Utility (64-bit) v10.3.0-275. Copyright (c) 2020 SafeNet. All rights reserved. Please enter password for token in slot 0 : ******* handle=2000001 label=haproxy_private_key handle=2000002 label=haproxy_public_key
Copy the SAUTIL utility provided with the OpenSSL toolkit to create the private key reference in software:
cp /home/gemengine-1.2/builds/linux/rhel/64/1.0.2/sautil /usr/bin/
Create private key reference:
- Run the SAUTIL utility to create a private key reference to the actual private key imported in Luna HSM:
sautil -v -s 0 -i 0:0 -a 0:RSA -f HSMKey_ref.pem -o -q -c
- Provide the HSM partition password and key handle when prompted. After successful execution of the SAUTIL command,
HSMKey_ref.pem
will be generated.
Delete the private key generated by OpenSSL and the PKCS#8 format key that was used before importing the key into Luna HSM:
rm -rf server.key privatekey.pem
Create the combined certificate file:
- Combine the private key reference and the existing certificate into a new file at
/etc/pki/tls/certs/haproxy.pem
:
cat HSMKey_ref.pem softcert.cer > /etc/pki/tls/certs/haproxy.pem
- Replace
softcert.cer
with your existing certificate file that was generated using the software key.
Open the HAProxy configuration file in a text editor and ensure the following configuration is included:
global log 127.0.0.1 local2 pidfile /var/run/rh-haproxy18-haproxy.pid maxconn 4000 pidfile /var/run/haproxy.pid user haproxy group hsmusers daemon ssl-engine gem tune.ssl.default-dh-param 2048 defaults mode http log global option httplog option dontlognull retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s frontend https-in bind *:80 use_backend static option forwardfor bind *:443 ssl crt /etc/pki/tls/certs/haproxy.pem backend static balance roundrobin server server1.example.com 10.164.76.117:80 check server server2.example.com 10.164.78.118:80 check
The path to haproxy.cfg
may differ based on your HAProxy installation. Adjust fields as needed according to your setup. Ensure you add ssl-engine gem
to the global section so that OpenSSL uses GemEngine and the correct certificate location is specified.
Configure SELinux:
- Check the SELinux setting and temporarily set it to permissive mode:
setenforce 0
- To make this change permanent, edit
/etc/selinux/config
and set:
SELINUX=permissive
- Reboot the system to apply the changes:
reboot
If you are using Ubuntu, this step is not required.
Restart the HAProxy service to apply the new configuration:
systemctl restart haproxy.service
Ensure that the HAProxy service is added to the firewall rules to allow traffic through the firewall.
Check the status of the HAProxy service to confirm that it is running without errors:
systemctl status haproxy.service
Example output:
haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2021-02-23 14:40:21 IST; 1h 35min ago Docs: man:haproxy(1) file:/usr/share/doc/haproxy/configuration.txt.gz Process: 164765 ExecStart=/usr/sbin/haproxy -W -f $CONFIG -p $PIDFILE $EXTRAOPTS (code=exited, status=0/SUCCESS) Process: 164754 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS) Main PID: 164775 (haproxy) Tasks: 3 (limit: 23814) Memory: 24.9M CGroup: /system.slice/haproxy.service ├─164775 /usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid └─164776 /usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid Feb 23 14:40:21 localhost.localdomain haproxy[164765]: [NOTICE] 053/144021 (164775) : New worker #1 (164776) forked Feb 23 14:40:21 localhost.localdomain systemd[1]: Started HAProxy Load Balancer.
Open a browser and navigate to the HAProxy load balancer:
https://:443
Accept the certificate and verify its details to ensure the integration is complete.
Appendix
This section provides detailed instructions and procedures for:
Install HAProxy with custom OpenSSL
To install HAProxy with custom OpenSSL:
Install required packages:
apt install make gcc perl libpcre3-dev zlib1g-dev -y
Download HAProxy source:
wget https://www.haproxy.org/download/1.8/src/haproxy-1.8.8.tar.gz
Extract the source archive:
tar xzf haproxy-1.8.8.tar.gz
Navigate to the extracted directory:
cd haproxy-1.8.8
Compile HAProxy with custom OpenSSL:
make TARGET=generic USE_OPENSSL=1 SSL_INC=/usr/local/ssl/include SSL_LIB=/usr/local/ssl/lib USE_PCRE=1 USE_ZLIB=1 USE_GETADDRINFO=1 USE_REGPARM=1 USE_PCRE_JIT=1 USE_NS=1
Ensure the SSL_INC
and SSL_LIB
paths match the location where Custom OpenSSL is installed.
Install HAProxy:
make install
Copy the HAProxy binary:
cp /usr/local/sbin/haproxy /usr/sbin/haproxy
Check that HAProxy is using the desired Custom OpenSSL version:
haproxy -vv
Create the service file /lib/systemd/system/haproxy.service
with the following content:
[Unit] Description=HAProxy Load Balancer Documentation=man:haproxy(1) Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz After=network.target rsyslog.service [Service] EnvironmentFile=-/etc/default/haproxy Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" Environment="LD_LIBRARY_PATH=/usr/local/ssl/lib/" ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS ExecStart=/usr/sbin/haproxy -W -f $CONFIG -p $PIDFILE $EXTRAOPTS ExecReload=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS ExecReload=/bin/kill -USR2 $MAINPID KillMode=mixed Restart=always SuccessExitStatus=143 Type=forking [Install] WantedBy=multi-user.target
Ensure the Environment="LD_LIBRARY_PATH"
points to the custom OpenSSL library folder.
Create /etc/haproxy/haproxy.cfg
with the following content:
global log /dev/log local0 log /dev/log local1 notice stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon defaults log global mode http option httplog option dontlognull
Create the haproxy
user if it doesn’t already exist:
id -u haproxy &> /dev/null || useradd -s /usr/sbin/nologin -r haproxy
Create the HAProxy directory:
mkdir -p /run/haproxy
Reload the systemd daemon and start the HAProxy service:
systemctl daemon-reload systemctl start haproxy.service
Ensure that the HAProxy service starts successfully. Follow the instructions in the Integrate Luna HSM with HAProxy section to complete the setup.
Configure backend servers for HAProxy
To configure backend servers for HAProxy:
Install Apache server:
apt install httpd -y
Modify your webpage content in the /var/www/html/index.html
file as needed.
Start the Apache service:
systemctl start httpd
Configure HAProxy server to run in chroot
To configure the HAProxy server to run in chroot:
This guide assumes the chroot directory is /var/lib/haproxy
. If you are using a different directory, adjust the paths accordingly.
Follow the steps in the Integrate Luna HSM with HAProxy section to ensure integration is complete.
Stop the HAProxy service if it is currently running.
systemctl stop haproxy.service
Create the directory for chroot.
mkdir -p /var/lib/haproxy
Create the /usr/safenet
directory within the chroot directory.
mkdir -p /var/lib/haproxy/usr/safenet
Mount the existing /usr/safenet
directory to the chroot directory.
mount --bind /usr/safenet /var/lib/haproxy/usr/safenet
Create the /etc
directory within the chroot directory and copy the Chrystoki.conf
file to it.
mkdir /var/lib/haproxy/etc cp /etc/Chrystoki.conf /var/lib/haproxy/etc/
Provide the HAProxy user with the necessary permissions for the Chrystoki.conf
file.
setfacl -m u:haproxy:rwx /var/lib/haproxy/etc/Chrystoki.conf
Create the /tmp
directory within the chroot directory.
mkdir /var/lib/haproxy/tmp
Mount the existing /tmp
directory to the chroot directory.
mount --bind /tmp /var/lib/haproxy/tmp
Add the following line to the global section of the /etc/haproxy/haproxy.cfg
file to specify the chroot directory.
chroot /var/lib/haproxy
Reload the system daemon and start the HAProxy service.
systemctl daemon-reload systemctl start haproxy.service
The above mounts are temporary and will be lost after a reboot. To make these mounts persistent, add them to the /etc/fstab
file.