Skip to content
Alexander Krizhanovsky edited this page Oct 8, 2023 · 33 revisions

Compatibility

Tempesta TLS supports TLS 1.2 only and TLS 1.3 is going to be implemented soon. Any SSL versions as well as old TLS versions such as 1.0 and 1.1 aren't supported. Insecure features commented in RFC 2525 are also gone: compression, renegotiations (Triple Handshakes and Cookie Cutters: Breaking andFixing Authentication over TLS describes attacks using TLS renegotiations), non-ephemeral key exchanges, weak ciphers like RC4 and DES and hashes like MD5, truncated HMAC, and so on.

Supported ciphersuites

  • ECDHE-ECDSA-WITH-AES-128-GCM-SHA256
  • ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
  • ECDHE-ECDSA-WITH-AES-256-CCM
  • ECDHE-ECDSA-WITH-AES-128-CCM
  • ECDHE-RSA-WITH-AES-128-GCM-SHA256
  • ECDHE-RSA-WITH-AES-256-GCM-SHA384
  • DHE-RSA-WITH-AES-256-GCM-SHA384
  • DHE-RSA-WITH-AES-128-GCM-SHA256
  • DHE-RSA-WITH-AES-256-CCM
  • DHE-RSA-WITH-AES-128-CCM

During a TLS handshake Tempesta TLS picks the first ciphersuite from the list which is also present in the ClientHello list.

ECDHE and ECDSA algorithms are the most optimized, so we recommend to use ECDHE-ECDSA ciphersuites. At the moment, the RSA algorithm isn't performance optimized, so we recommend to avoid it (RSA is the subject for performance optimization is task https://github.com/tempesta-tech/tempesta/issues/1335).

Supported elliptic curves

At the moment we support only 1 NIST curve (short Weierstrass): secp256r1 (prime256v1).

Support of Curve25519 (Montgomery) is the subject for the task https://github.com/tempesta-tech/tempesta/issues/1335 .

Performance & security

By default Tempesta TLS uses point randomization to prevent side channel attacks (read our Netdev 0x14 paper for details). This configuration provide the best performance and good security if you trust your CPU vendor since we use RDRAND instruction for random numbers generation.

If you do not trust your CPU vendor, then please use CRYPTO_CONST_TIME configuration option to make Tempesta TLS to use algorithms with constant time instead of relying on point randomization. To do so, you need to recompile Tempesta with:

$ CRYPTO_CONST_TIME=1 make

Also reference how to build Tempesta FW from source code.

Configuration

TempestaFW allows the use of TLS-encrypted HTTP connections (HTTPS). HTTPS traffic is terminated on TempestaFW. Backend servers always receive unencrypted traffic.

First configure TLS listening ports by adding proto=https option for the listen directive.

Example:

listen 443 proto=https;

Then add public certificate and the private key to configuration. PKCS#12 format isn't supported, please use OpenSSL command line tool to convert file formats if you want to store certificates in PKCS#12.

Certificates can be defined on per-vhost basis or at global level. Up to 8 certificates can be defined for each vhost.

To configure certificates for specific vhost, insert directives tls_certificate -- path to file with public certificate; tls_certificate_key -- path to file with private key; inside vhost section. The directives can be listed multiple times to configure multiple possible certificates. Note, that certificates based on elliptic curves provide better performance and less CPU consumption that RSA ones. It is recommended to place certificates based on elliptic curves before RSA ones in certificate list, because certificates are tried one-by-one.

vhost tempesta-tech.com {
    tls_certificate /path/to/tfw-root.crt;
    tls_certificate_key /path/to/tfw-root.key;

    tls_certificate /path/to/other/tfw-root.crt;
    tls_certificate_key /path/to/other/tfw-root.key;
}

Directive tls_certificate must be always followed by tls_certificate_key directive. If the condition is broken the syntax error will be thrown. Once both are described, certificate is parsed and loaded into Tempesta. If an error happens, configuration process will be aborted and line number of the certificate caused error will be printed in the error message.

Same syntax is used to describe certificates at the top level of the configuration file, the certificates will be applied to implicit default vhost then:

tls_certificate /path/to/tfw-root.crt;
tls_certificate_key /path/to/tfw-root.key;

tls_certificate /path/to/other/tfw-root.crt;
tls_certificate_key /path/to/other/tfw-root.key;

To chose the most suitable certificate for a new TLS connection Tempesta extracts Server Name Indication and information about supported algorithms from ClientHello message.

Server name extracted from the SNI extension in the ClientHello is compared across vhosts names defined in configuration file. If match is found that vhost is used, otherwise connection is rejected. If client doesn't send SNI, then default vhost is used.

Server name in the SNI extension in the ClientHello message must conform one of the vhost names defined in the configuration file, otherwise connection will be rejected. If no TLS certificates is configured for target vhost, default vhost is chosen as a fallback option.

If client doesn't send SNI extension, then target server name is not specified and the connection is established to default vhost.

E.g. if client requests server name example.com, vhost name example.com will be chosen for that connection. If vhost example.com doesn't exist in the configuration incoming TLS connection will be rejected.

After vhost is determined, Tempesta tries certificates defined for that vhost one-by-one and chooses the first matching client abilities. Thus more preferable certificates should be defined first.

Note, although vhost is chosen for the TLS connection at establishing stage, it doesn't affect request distribution and doesn't replace http_chain directive.

The tls_match_any_server_name directive can be defined for the default vhost to match unknown server names to default vhost:

tls_match_any_server_name;

Example configurations

Example 1. Multiple vhosts are defined in the configuration, each has its own certificate. If a client requests server names example.com, library.com or store.com, TLS connection is established. If client doesn't send SNI extension, TLS connection is rejected.

listen 443 proto=https;
listen 80;

srv_group sg1 {
    server 127.0.0.1:8080;
}
srv_group sg2 {
    server 127.0.0.1:8081;
}
srv_group sg3 {
    server 127.0.0.1:8082;
}

vhost example.com {
    proxy_pass sg1;
    tls_certificate     /root/certbot/example/cert.pem;
    tls_certificate_key /root/certbot/example/privkey.pem;
}
vhost library.com {
    proxy_pass sg2;
    tls_certificate     /root/certbot/library/cert.pem;
    tls_certificate_key /root/certbot/library/privkey.pem;
}
vhost store.com {
    proxy_pass sg3;
    tls_certificate     /root/certbot/store/cert.pem;
    tls_certificate_key /root/certbot/store/privkey.pem;
}

http_chain {
    host == "example.com" -> example.com;
    host == "library.com" -> library.com;
    host == "store.com"   -> store.com;
    -> block;
}

Example 2. Two vhosts, but only one supports TLS connections. If a client requests server names library.com, TLS connection is established. If client doesn't send SNI extension, TLS connection is rejected.

listen 443 proto=https;
listen 80;

srv_group sg1 {
    server 127.0.0.1:8080;
}
srv_group sg2 {
    server 127.0.0.1:8081;
}

vhost example.com {
    proxy_pass sg1;
    # No TLS certificates: this vhost is available only by HTTP connections.
}
vhost library.com {
    proxy_pass sg2;
    # TLS certificates configured, both HTTP and HTTPS connections to this vhost
    # are possible.
    tls_certificate     /root/certbot/library/cert.pem;
    tls_certificate_key /root/certbot/library/privkey.pem;
}

http_chain {
    host == "example.com" -> example.com;
    host == "library.com" -> library.com;
    -> block;
}

Example 3. Global certificate is used for two vhosts, while the third uses it's own certificate. If a client requests server names example.com, crm.example.com or doesn't specify any (missing SNI extension), TLS connection is established using /root/certbot/cert.pem certificate. If a client requests server name store.com, TLS connection is established using /root/certbot/store/cert.pem certificate.

listen 443 proto=https;
listen 80;

srv_group sg1 {
    server 127.0.0.1:8080;
}
srv_group sg2 {
    server 127.0.0.1:8081;
}
srv_group sg3 {
    server 127.0.0.1:8083;
}

vhost crm.example.com {
    proxy_pass sg1;
}
vhost example.com {
    proxy_pass sg2;
}
# vhost with it's own certificate.
vhost store.com {
    proxy_pass sg3;
    tls_certificate /root/certbot/store/cert.pem;
    tls_certificate_key /root/certbot/store/privkey.pem;
}

# Singe TLS certificate for all the domains except 'store.com'
tls_certificate /root/certbot/cert.pem;
tls_certificate_key /root/certbot/privkey.pem;

http_chain {
    host == "crm.example.com" -> crm.example.com;
    host == "example.com"     -> example.com;
    host == "store.com"       -> store.com;
    -> block;
}

Example 4. Thousands of vhosts, few have their own certificates, but majority relies on global certificate. Clients with no SNI extension are allowed to open TLS connection using global certificate.

# Normal clients: Vhost names - domain names. No TLS certificates are configured
# global certificates will be used.
vhost baloons-for-sale.com {
   ...
}
vhost bnl.com {
   ...
}
vhost pizza-planet.com {
   ...
}
...

# Temporal clients pool for evaluation purposes. Vhost names - some abstract
# strings, not domain names, since domain names are auto generated.
vhost temp-client1 {
   ...
}
vhost temp-client2 {
   ...
}
vhost temp-client3 {
   ...
}
...

# Special clients with own TLS certificates.
vhost alstoybarn.com {
    ...

    tls_certificate /root/certbot/store/cert_rsa.pem;
    tls_certificate_key /root/certbot/store/privkey_rsa.pem;

    tls_certificate /root/certbot/store/cert_ec.pem;
    tls_certificate_key /root/certbot/store/privkey_ec.pem;
}


# We use one master certificate for all vhosts except very specific ones.
# If there is no 'tls_certificate' sertificate in vhost section, master
# certificate is used.
# Some clients - automation scripts (curl) and IoT devices that doesn't set SNI
# in TLS connections, master certificate is used for them.
# Some vhosts - temporal clients, we provide auto generated 3-rd level domain
# names for them. When a new client is added, we just update http_chain rules,
# but never update pool of vhosts in configuration. Thus we use
# `tls_match_any_server_name` directive to use mater key for all the unknown
# server names.

tls_match_any_server_name;
tls_certificate /root/certbot/cert.pem;
tls_certificate_key /root/certbot/privkey.pem;

# Dynamic rules, updated every two days:
http_chain evaluation_clients {
    host == "mrpotato.cdn.com" -> temp-client1;
    host == "linguine.cdn.com" -> temp-client2;
    host == "zurg.cdn.com" -> temp-client3;
    -> block;
}

# Constant rules, almost never updated.
http_chain {
    # Normal clients:
    host == "baloons-for-sale.com" -> baloons-for-sale.com;
    host == "bnl.com" -> bnl.com;
    host == "pizza-planet.com" -> pizza-planet.com;

    # Special clients
    host == "alstoybarn.com" -> alstoybarn.com;

    # Clients on evaluation period
    -> evaluation_clients;
}

Certificate chains

If the server certificate is issued by Authority not known by the clients, chain of intermediate certificates up to root CA should be sent to clients in addition to server certificate.

To do so, just append intermediate certificates to file with server certificate.

cat server.crt intermediate1_cart.crt intermediate1_cart.crt > server_chained.crt

TLS Session Resumption

TempestaFW can resume previously established TLS sessions without storing session state as described in RFC 5077. This allows to save heavy computations on TLS handshake stage and reduce single packet round-trip between server and client. TLS Session ticket extension support is required from a client. Majority of the browsers and TLS libraries support it.

After a new TLS session is established, an encrypted ticket is sent to the client. The client can't decrypt or examine ticket content. The ticket can be sent by client in a new TLS handshake, if it can be successfully decrypted and not expired, server can reuse session state saved in the ticket. In this scenario, called abbreviated handshake, both client and server will reuse master key generated on the previous handshake and resume previous session.

Abbreviated handshakes are less expensive for server and enabled by default on majority of the clients, so the feature is enabled by default in TempestaFW too. But the configuration can be changed for each virtual host.

To reduce number of tickets, encrypted by the same key, TempestaFW uses individual keys for each virtual host and constantly rotates the ticket keys. Key rotation can be synchronised between multiple TempestaFW server, allowing to resume session created on another TempestaFW node. No shared cache is required, all the necessary information is stored inside TLS session ticket.

TLS tickets can be configured in vhost context with the following syntax:

tls_tickets secret="SECRET" lifetime=SECS;

where secret - secret string, used to synchronize key rotation between multiple servers. If not defined, a random value will be used on each node. lifetime - describes both key rotation time and maximum ticket lifetime, default - 3600 (1 hour). When a ticket is received by TempestaFW, it's creation time is evaluated and, if it's already expired, fallback to full handshake is performed.

TLS tickets can be switched off using directive:

tls_tickets off;

Example:

vhost example.com {
    tls_tickets secret="f00)9eR59*_/22" lifetime=7200;
}

Avoiding Virtual Host Confusion

The Virtual Host Confusion article from The Black Hat conference shows that use of shared TLS session caches and session tickets across different virtual hosts and connection reuse may weaken server authentication. Such network-based redirection attacks can lead to cookies and sign-on tokens theft, sessions hijacking, or certificate validation bypass.

In TempestaFW each session ticket is encrypted with a key, unique for each virtual host, contains authentication tag and requested SNI information. Thus ticket issued for one virtual host can't be used to resume session with another virtual host.

More information, tips and common mistakes explanation can be found on Virtual host confusion wiki page.

Zero-downtime certificate update with Certbot

Certbot provides API to automatically get free certificates from Let's Encrypt service.

There is no official documentation to configure certbot with Tempesta FW, so we use Nginx script to initialize configs:

# apt install nginx
# certbot --nginx
# apt purge nginx

We recommend to use webroot plugin with Tempesta FW, for example:

# certbot certonly --key-type ecdsa --elliptic-curve secp256r1 --webroot -w /your/site/root/ --preferred-challenges http -d your.domain.com

Note that ECDSA certificate for secp256r1 curve is explicitly specified. By default certbot generates RSA certificates, which make TLS handshake much slower.

Configure your Tempesta FW to work with the certificate and private key updated by certbot:

tls_certificate /etc/letsencrypt/live/your.domain.com/cert.pem;
tls_certificate_key /etc/letsencrypt/live/your.domain.com/privkey.pem;

To make certbot reload Tempesta FW configuration on certificate update, add following renewal hook to /etc/letsencrypt/renewal/your.domain.com.conf (supposed that you've installed Tempesta FW from packages):

renew_hook = systemctl reload tempesta-fw.service

Finally, check your certbot configuration with

sudo certbot renew --dry-run

If it shows no errors, then you did everything right. Also check the systemd timers to make sure that the certbot automatic renewal was configured properly:

# systemctl list-timers |grep certbot
Mon 2021-07-19 04:17:00 UTC 4h 43min left Sun 2021-07-18 18:34:01 UTC 4h 59min ago snap.certbot.renew.timer     snap.certbot.renew.service

Resources

Clone this wiki locally