]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add a "TLS sessions management" guide
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 18 Feb 2021 13:46:29 +0000 (14:46 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 18 Feb 2021 13:46:29 +0000 (14:46 +0100)
pdns/dnsdistdist/docs/guides/dns-over-https.rst
pdns/dnsdistdist/docs/guides/dns-over-tls.rst
pdns/dnsdistdist/docs/guides/index.rst
pdns/dnsdistdist/docs/guides/tls-sessions-management.rst [new file with mode: 0644]
pdns/dnsdistdist/docs/reference/config.rst

index a5cbac186b848673183792e1ee5ab43ec7b6adbf..be9663e657f3609ee92cb43e03f56ca94d72b3a9 100644 (file)
@@ -42,3 +42,5 @@ To let dnsdist listen for DoH queries over HTTP on localhost at port 8053 add on
   addDOHLocal("127.0.0.1:8053", nil, nil, "/", { reusePort=true })
 
 A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
+
+More information about sessions management can also be found in :doc:`guides/tls-sessions-management`.
index 27b681dd1ae0fd1a2904e6c94d974f05be43a966..c409b94c626fb8ede1a25923a8eef9bcb2c67372 100644 (file)
@@ -18,3 +18,5 @@ In order to support multiple certificates and keys, for example an ECDSA and an
 The certificate chain presented by the server to an incoming client will then be selected based on the algorithms this client advertised support for.
 
 A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
+
+More information about sessions management can also be found in :doc:`guides/tls-sessions-management`.
index 039764c997c200e3c6ae9a78adfcc6a48bb946c0..b7e7fdbc83fc8a8018ba7dc2a24a433922d3cd35 100644 (file)
@@ -15,5 +15,6 @@ These chapters contain several guides and nuggets of information regarding dnsdi
    carbon
    dns-over-tls
    ocsp-stapling
+   tls-sessions-management
 
 
diff --git a/pdns/dnsdistdist/docs/guides/tls-sessions-management.rst b/pdns/dnsdistdist/docs/guides/tls-sessions-management.rst
new file mode 100644 (file)
index 0000000..bc8894e
--- /dev/null
@@ -0,0 +1,56 @@
+TLS Sessions Management
+=======================
+
+TLS sessions
+------------
+
+One of the most costly TLS operation if the negotiation of a new session, since both the client and the server need to generate and agree on cryptographic materials. In order to reduce that cost, TLS implements what is called session resumption, where a client opening a new connection to a server can reuse the cryptographic materials negotiated for a previous TLS session.
+
+The necessary information to resume a session can either be kept on the server's side (sessions) or on the client's one (tickets). Initially only the server-side approach existed, with two drawbacks:
+- the server needs to keep that information at hand, for a client that might never come back;
+- sharing that information between several servers is not easy, especially in setups involving anycast or any kind of cluster without strong session affinity.
+
+Nowadays pretty much all clients support the second option, TLS tickets, where the need information is signed and encrypted by the server before being sent to the client, which is responsible for storing it and sending it back when it wants to establish a new session. That reduces the burden of the server while providing the same benefits.
+
+The server uses Session Ticket Encryption Key (STEK) to sign and encrypt the information sent to the client, making it possible to ensure that it is genuine and has not been tampered when the client provides it later. That STEK can be shared by all dnsdist instances in the same cluster, making it possible for any server to resume a session initially generated by a different server.
+
+Knowing the STEK is all the information needed to be able to decrypt a live TLS session, but also a recorded one, so it is very important to keep that key well-protected. It should never be exchanged in clear-text, and ideally should not be written to persistent storage but be kept in a tmpfs with no swap configured. It should also be regularly rotated to preserve TLS' forward secrecy properties.
+
+Keys management in dnsdist
+--------------------------
+
+By default, dnsdist will generate a new, random STEK at startup and rotate it every 12 hours. It will keep 5 keys in memory, with only the last one marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. The rotation time and the number of keys to keep in memory can be configured via the ``numberOfTicketsKeys`` and ``ticketsKeysRotationDelay`` parameters of the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
+
+It is also possible to manually request a STEK rotation using the :func:`getDOHFrontend` (DoH) and :func:`getTLSContext` (DoT) functions to retrieve the bind object, and calling its ``rotateTicketsKey`` method (:meth:`DOHFrontend.rotateTicketsKey`, :meth:`TLSContext.rotateTicketsKey`).
+
+The default settings should be fine for most deployments, but generating a random key for every dnsdist instance will not allow resuming the session from a different instance in a cluster. In that case it is possible to generate the STEK outside of dnsdist, write it to a file on a non-persistent storage, distribute it to all instances using something like rsync over SSH, and load that file from dnsdist.
+
+For the OpenSSL provider (DoT, DoH), generating a random STEK in a file is a simple as getting 80 cryptographically secure random bytes and writing them to a file::
+
+  dd if=/dev/urandom of=/secure-tmp-fs/tickets.key bs=80 count=1
+
+For the GnuTLS provider (DoT), the operation is the same but requires only 64 cryptographically secure random bytes::
+
+  dd if=/dev/urandom of=/secure-tmp-fs/tickets.key bs=64 count=1
+
+The file can then be loaded at startup by using the ``ticketKeyFile`` parameter of the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
+
+If the file contains several keys, so for example 240 random bytes, dnsdist will load several STEKs, using the last one for encrypting new tickets and all of them to decrypt existing tickets.
+
+In order to rotate the keys at runtime, it is possible to instruct dnsdist to reload the content of the certificates, keys, and STEKs from the same file used at configuration time, for all DoH and DoH binds, by issuing the :func:`reloadAllCertificates` command.
+It can also be done one bind at a time using the :func:`getDOHFrontend` (DoH) and :func:`getTLSContext` (DoT) functions to retrieve the bind object, and calling its ``loadTicketsKeys`` method (:meth:`DOHFrontend.loadTicketsKeys`, :meth:`TLSContext.loadTicketsKeys`).
+
+Since server-side sessions cannot be shared between several instances, and pretty much all clients support tickets anyway, we do recommend disabling the sessions by passing ``numberOfStoredSessions=0`` to the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
+
+Content of the STEK file
+------------------------
+
+It does not really matter for most operations, but for later reference the format of the OpenSSL STEK is:
+- a 16 bytes binary key identifier
+- a 32 bytes AES 256 key
+- a 32 bytes HMAC SHA-2 256 key
+
+For GnuTLS:
+- a 16 bytes binary key identifier
+- a 32 bytes AES 256 key
+- a 16 bytes HMAC SHA-1 key
index cb57882d92bb0dec393234d11d02edc215702851..483d1476cae43e25a285b19606522c51344cbe1f 100644 (file)
@@ -131,7 +131,7 @@ Listen Sockets
   * ``ocspResponses``: list - List of files containing OCSP responses, in the same order than the certificates and keys, that will be used to provide OCSP stapling responses.
   * ``minTLSVersion``: str - Minimum version of the TLS protocol to support. Possible values are 'tls1.0', 'tls1.1', 'tls1.2' and 'tls1.3'. Default is to require at least TLS 1.0.
   * ``numberOfTicketsKeys``: int - The maximum number of tickets keys to keep in memory at the same time. Only one key is marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. Default to 5.
-  * ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. dnsdist supports several tickets keys to be able to decrypt existing sessions after the rotation.
+  * ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. dnsdist supports several tickets keys to be able to decrypt existing sessions after the rotation. See :doc:`guides/tls-sessions-management` for more information.
   * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h).
   * ``sessionTimeout``: int - Set the TLS session lifetime in seconds, this is used both for TLS ticket lifetime and for sessions kept in memory.
   * ``sessionTickets``: bool - Whether session resumption via session tickets is enabled. Default is true, meaning tickets are enabled.
@@ -171,7 +171,7 @@ Listen Sockets
   * ``ciphers``: str - The TLS ciphers to use. The exact format depends on the provider used. When the OpenSSL provider is used, ciphers for TLS 1.3 must be specified via ``ciphersTLS13``.
   * ``ciphersTLS13``: str - The ciphers to use for TLS 1.3, when the OpenSSL provider is used. When the GnuTLS provider is used, ``ciphers`` applies regardless of the TLS protocol and this setting is not used.
   * ``numberOfTicketsKeys``: int - The maximum number of tickets keys to keep in memory at the same time, if the provider supports it (GnuTLS doesn't, OpenSSL does). Only one key is marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. Default to 5.
-  * ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. The OpenSSL provider supports several tickets keys to be able to decrypt existing sessions after the rotation, while the GnuTLS provider only supports one key.
+  * ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. The OpenSSL provider supports several tickets keys to be able to decrypt existing sessions after the rotation, while the GnuTLS provider only supports one key. See :doc:`guides/tls-sessions-management` for more information.
   * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h).
   * ``sessionTimeout``: int - Set the TLS session lifetime in seconds, this is used both for TLS ticket lifetime and for sessions kept in memory.
   * ``sessionTickets``: bool - Whether session resumption via session tickets is enabled. Default is true, meaning tickets are enabled.
@@ -1491,6 +1491,7 @@ DOHFrontend
   .. method:: DOHFrontend:loadTicketsKeys(ticketsKeysFile)
 
      Load new tickets keys from the selected file, replacing the existing ones. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. dnsdist supports several tickets keys to be able to decrypt existing sessions after the rotation.
+     See :doc:`guides/tls-sessions-management` for more information.
 
     :param str ticketsKeysFile: The path to a file from where TLS tickets keys should be loaded.
 
@@ -1535,6 +1536,7 @@ TLSContext
   .. method:: TLSContext:loadTicketsKeys(ticketsKeysFile)
 
      Load new tickets keys from the selected file, replacing the existing ones. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. The OpenSSL provider supports several tickets keys to be able to decrypt existing sessions after the rotation, while the GnuTLS provider only supports one key.
+     See :doc:`guides/tls-sessions-management` for more information.
 
     :param str ticketsKeysFile: The path to a file from where TLS tickets keys should be loaded.