HAProxy Enterprise Documentation 2.5r1

Client Certificate Authentication

Client certificate authentication means that the client sends a certificate when they connect over TLS. The load balancer verifies the client's identity based on the certificate. Typically, client certificates are digitally signed with your organization's CA certificate. When a client presents one, you can verify whether it was indeed signed by your CA. If not, deny the request. You would give a unique certificate to each client to which you want to grant access.

Create a Certificate Authority

Creating a client certificate that's signed by your organization's self-signed CA (Certificate Authority) is deemed secure in this scenario, as opposed to procuring one from an external CA. Your organization acts as the Certificate Authority, authenticating these certificates when when they are presented through HTTPS requests by clients.

Creating a Certificate Authority involves several steps, including generating a CA key pair, creating a self-signed CA certificate, and configuring the CA to sign certificates. Here's an overview of the process:

  1. Generate a CA key pair:

    $ openssl req \
      -newkey rsa:2048 \
      -nodes \
      -x509 \
      -days 3650 \
      -keyout privateCA.pem \
      -out cacert.crt

    To break this down:

    • openssl req: Used for creating and processing certificate signing requests (CSRs) and certificates.

    • newkey rsa:2048: Specifies the generation of a new RSA key pair with a key size of 2048 bits.

    • nodes: Indicates that the private key should not be encrypted with a passphrase and will be saved in an unencrypted format.

    • x509: This option tells OpenSSL to generate a self-signed certificate instead of a CSR.

    • days 3650: Specifies the validity period of the certificate as 3650 days (approximately 10 years).

    • keyout: Designates the file name of privateCA.pem for the private key.

    • -out cacert.crt sets the certificate.

    The command will also prompt you to enter information for the certificate, such as the Common Name (CN), organization details, and so on. Fill in the required fields accordingly.

    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:
    State or Province Name (full name) [Some-State]:
    Locality Name (eg, city) []:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []:
    Email Address []:

    The certificate will include information like the CA's name, public key, validity period, and any other relevant details.

  2. Verify the self-signed certificate. This command displays the details of the signed certificate, allowing you to verify its information:

    $ openssl x509 -in cacert.crt -text -noout

    After following these steps, you should have the signed certificate cacert.crt that has been signed by the CA using its private key, establishing trust. Remember to adjust the file names and paths according to your specific setup.

Create a client certificate

In certain scenarios, servers may need to authenticate clients before allowing them access to sensitive resources or services. A client certificate is a type of digital certificate used by web servers to verify the identity of a user or device trying to access these resources.

  1. Create the certificate signing request with the following command:

    $ openssl req \
       -newkey rsa:2048 \
       -nodes \
       -days 3650 \
       -subj "/CN=commonName/O=Organization" \
       -keyout clientKey.pem \
       -out client.csr
  2. Now use the following command to sign the certificate signing request; this uses our previously generated CSR client.csr, CA certificate cacert.crt, and key privateCA.pem to create a client certificate, client.crt.

    $ openssl x509 \
       -req \
       -in client.csr \
       -out client.crt \
       -CA cacert.crt \
       -CAkey privateCA.pem \
       -CAcreateserial \
       -days 3650

Successful confirmation output will look something like this, with an 'OK' statement above your Common Name and Organization:

Certificate request self-signature ok
subject=CN = <YourCommonName>, O = <YourOrganization>

Your client certificate is now ready to be used.

Enable client certificate verification

Enable verification of client certificates by setting verify to required on a bind line. The ca-file parameter specifies the CA file to use to verify:

frontend www
   bind *:443 ssl crt /etc/hapee-2.5/certs/site.pem verify required ca-file /etc/hapee-2.5/certs/cacert.crt

Send a client certificate to servers

HAProxy Enterprise can also send its own client certificate to backend servers. The servers would then be responsible for verifying it. The crt parameter points to your client certificate file:

backend webservers
  server web1 10.0.0.5:443 ssl  verify required  ca-file /etc/hapee-2.5/certs/cacert.crt  crt /etc/hapee-2.5/certs/client.crt

Generate Certificate Revocation List (CRL)

A Certificate Revocation List (CRL) contains a list of the certificates that have been revoked.

  1. Create the directory structure and necessary files. You can choose different directory paths however ensure all created files are in the proper locations:

    $ mkdir ./databaseCA
    $ cd ./databaseCA
    $ mkdir certs private crl
    $ touch index.txt serial crlnumber
    $ echo 01 > serial
    $ echo 1000 > crlnumber
  2. Next, you'll need a configuration file for OpenSSL. This file is often named openssl.cnf and can be found in the directories /usr/lib/ssl/ or /etc/ssl/. Below is a example snippet from the file:

    # OpenSSL example configuration file.
    # See doc/man5/config.pod for more info.
    
    ####################################################################
    [ ca ]
    default_ca        = CA_default            # The default ca section
    ####################################################################
    [ CA_default ]
    
    dir               = ./databaseCA          # Where everything is kept
    certs             = $dir/certs            # Where the issued certs are kept
    crl_dir           = $dir/crl              # Where the issued crl are kept
    database  = $dir/index.txt        # database index file.
    #unique_subject   = no                    # Set to 'no' to allow creation of
                   # several certs with same subject.
    new_certs_dir     = $dir/newcerts         # default place for new certs.
    
    certificate       = $dir/cacert.crt       # The CA certificate
    serial            = $dir/serial           # The current serial number
    crlnumber = $dir/crlnumber        # the current crl number
                   # must be commented out to leave a V1 CRL
    crl               = $dir/crl.pem          # The current CRL
    private_key       = $dir/privateCA.pem # The private key
    x509_extensions   = usr_cert              # The extensions to add to the cert
    
    # crlnumber must also be commented out to leave a V1 CRL.
    crl_extensions = crl_ext
    
    default_days    = 3650                   # how long to certify for
    default_crl_days= 30                    # how long before next CRL
    default_md      = sha256                # use SHA-256 by default
    preserve        = no                    # keep passed DN ordering

    In this configuration, ./databaseCA is the directory where OpenSSL will store its database of certificates, ./privateCA.pem is the CA's private key, and ./cacert.crt is the CA's certificate. Ensure the directory and file paths match your environment, which we created in step one. Consult OpenSSL.org's documentation for a complete list of configuration options.

  3. Set up the CRL file. This OpenSSL command generates the file ca.crl, which contains the updated list of certificates that have been revoked based on the existing configurations:

    $ sudo openssl ca -config openssl.cnf -gencrl -out /etc/hapee-2.7/ca.crl

Revoking certificates

By using Certificate Revocation Lists (CRLs), you can effectively revoke client certificates in your HAProxy Enterprise environment. Revoked certificates will be denied access based on your configured CRL file.

Here is an example snippet in which we add the crl-file argument to deny access to clients who have revoked certificates:

frontend www
   mode http
   bind 192.168.10.1:443 ssl crt /etc/hapee-2.5/server.crt verify required ca-file /etc/hapee-2.5/certs/cacert.crt crl-file /etc/hapee-2.5/ca.crl

The option crl-file ./ca.crl is used to check if the client has been revoked in the Certificate Revocation List provided in the argument.

  1. If you need to revoke a particular certificate, you can run this command:

    $ openssl ca -config openssl.cnf -revoke client.crt

    This will immediately revoke the cert client.crt as confirmed by the output:

    Using configuration from openssl.cnf
    Revoking Certificate 01.
    Data Base Updated

    Now the cert client.crt has been invalidated.

  2. Once this is done, you can either decide to create a new CRL or update the existing one. In our example, we will update the existing CRL:

    $ sudo openssl ca -config openssl.cnf -gencrl -out /etc/hapee-2.7/ca.crl
  3. Reload HAProxy Enterprise when you're done making changes.

    $ sudo systemctl reload hapee-2.5-lb

Additional revocation options

  • Including crt-ignore-err all instructs HAProxy Enterprise to disregard any errors related to client certificates.

  • The option crl-file ./ca.crl verifies whether the client's certificate has been revoked.

    frontend www
       mode http
       bind 192.168.10.1:443 ssl crt /etc/hapee-2.5/server.pem ca-file /etc/hapee-2.5/cacert.crt verify required crt-ignore-err all crl-file /etc/hapee2.5/ca.crl

Please verify your environment paths for the keys, certificates, and CRL.

Make authentication optional

In the following configuration, both users with and without a certificate are allowed to establish a connection.

The keywords verify optional enables this behavior.

frontend www
   mode http
   bind 192.168.10.1:443 ssl crt /etc/hapee-2.5/server.pem ca-file /etc/hapee-2.5/cacert.crt verify optional crl-file /etc/hapee-2.5/ca.crl

Reload HAProxy Enterprise when you're done making changes.

$ sudo systemctl reload hapee-2.5-lb

Show error pages for certificate errors

By utilizing the configuration options below, we can direct users to different backends based on the presence or absence of a certificate.

  1. Configure HTML pages on your webserver. For example, certexpired.html and certrevoked.html pages.

    • The file /certexpired.html could present a dedicated page to users whose certificate has expired, providing guidance on how to renew or request a new certificate.

    • Those with revoked certificates could be directed to the dedicated page /certrevoked.html.

  2. Edit your load balancer configuration to include redirect location directives:

    backend servers
       mode http
       option http-server-close
       redirect location /certexpired.html if { ssl_c_verify 10 } ! { path /certexpired.html }
       redirect location /certrevoked.html if { ssl_c_verify 23 } ! { path /certrevoked.html }
  3. Reload HAProxy Enterprise when you're done making changes.

    $ sudo systemctl reload hapee-2.5-lb

Redirect HTTP to HTTPS

It is possible to redirect HTTP requests to HTTPS by including an http-request redirect scheme line:

frontend www
   mode http
   bind *:443 ssl crt /etc/hapee-2.5/certs/site.pem verify required ca-file /etc/hapee-2.5/certs/cacert.crt
   http-request redirect scheme https unless { ssl_fc }
   default_backend servers

The line http-request redirect scheme https unless { ssl_fc } is the redirect command. If a connection comes in over HTTP through the frontend www, then it is redirected to use HTTPS instead.

This configuration ensures that all incoming connections are served over HTTPS (port 443).

For more information see redirects under Traffic Routing.

Reload HAProxy Enterprise when you're done making changes.

$ sudo systemctl reload hapee-2.5-lb

Next up

JSON Web Token-Based Authorization