mirror of
https://github.com/certbot/certbot.git
synced 2026-08-03 03:52:02 +02:00
Turn off session tickets for versions of Nginx that support it (#7092)
* Turn off session tickets for versions of Nginx that support it In line with Mozilla's security recommendations. * Changelog. * Set version before installing config files * lint: remove unused import * windows testfix * another windows testfix? * Testing path of updating src file with old nginx * Fix windows, and make config update tests fail if update doesn't happen
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
*
|
* Turn off session tickets for nginx plugin by default
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ include README.rst
|
|||||||
recursive-include docs *
|
recursive-include docs *
|
||||||
recursive-include certbot_nginx/tests/testdata *
|
recursive-include certbot_nginx/tests/testdata *
|
||||||
include certbot_nginx/options-ssl-nginx.conf
|
include certbot_nginx/options-ssl-nginx.conf
|
||||||
|
include certbot_nginx/options-ssl-nginx-old.conf
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import subprocess
|
|||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
import OpenSSL
|
import OpenSSL
|
||||||
import zope.interface
|
import zope.interface
|
||||||
|
|
||||||
@@ -120,6 +122,14 @@ class NginxConfigurator(common.Installer):
|
|||||||
|
|
||||||
self.reverter.recovery_routine()
|
self.reverter.recovery_routine()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mod_ssl_conf_src(self):
|
||||||
|
"""Full absolute path to SSL configuration file source."""
|
||||||
|
config_filename = "options-ssl-nginx.conf"
|
||||||
|
if self.version < (1, 5, 9):
|
||||||
|
config_filename = "options-ssl-nginx-old.conf"
|
||||||
|
return pkg_resources.resource_filename("certbot_nginx", config_filename)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mod_ssl_conf(self):
|
def mod_ssl_conf(self):
|
||||||
"""Full absolute path to SSL configuration file."""
|
"""Full absolute path to SSL configuration file."""
|
||||||
@@ -130,6 +140,11 @@ class NginxConfigurator(common.Installer):
|
|||||||
"""Full absolute path to digest of updated SSL configuration file."""
|
"""Full absolute path to digest of updated SSL configuration file."""
|
||||||
return os.path.join(self.config.config_dir, constants.UPDATED_MOD_SSL_CONF_DIGEST)
|
return os.path.join(self.config.config_dir, constants.UPDATED_MOD_SSL_CONF_DIGEST)
|
||||||
|
|
||||||
|
def install_ssl_options_conf(self, options_ssl, options_ssl_digest):
|
||||||
|
"""Copy Certbot's SSL options file into the system's config dir if required."""
|
||||||
|
return common.install_version_controlled_file(options_ssl, options_ssl_digest,
|
||||||
|
self.mod_ssl_conf_src, constants.ALL_SSL_OPTIONS_HASHES)
|
||||||
|
|
||||||
# This is called in determine_authenticator and determine_installer
|
# This is called in determine_authenticator and determine_installer
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
"""Prepare the authenticator/installer.
|
"""Prepare the authenticator/installer.
|
||||||
@@ -148,14 +163,14 @@ class NginxConfigurator(common.Installer):
|
|||||||
|
|
||||||
self.parser = parser.NginxParser(self.conf('server-root'))
|
self.parser = parser.NginxParser(self.conf('server-root'))
|
||||||
|
|
||||||
install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
|
|
||||||
|
|
||||||
self.install_ssl_dhparams()
|
|
||||||
|
|
||||||
# Set Version
|
# Set Version
|
||||||
if self.version is None:
|
if self.version is None:
|
||||||
self.version = self.get_version()
|
self.version = self.get_version()
|
||||||
|
|
||||||
|
self.install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
|
||||||
|
|
||||||
|
self.install_ssl_dhparams()
|
||||||
|
|
||||||
# Prevent two Nginx plugins from modifying a config at once
|
# Prevent two Nginx plugins from modifying a config at once
|
||||||
try:
|
try:
|
||||||
util.lock_dir_until_exit(self.conf('server-root'))
|
util.lock_dir_until_exit(self.conf('server-root'))
|
||||||
@@ -1131,12 +1146,6 @@ def nginx_restart(nginx_ctl, nginx_conf):
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def install_ssl_options_conf(options_ssl, options_ssl_digest):
|
|
||||||
"""Copy Certbot's SSL options file into the system's config dir if required."""
|
|
||||||
return common.install_version_controlled_file(options_ssl, options_ssl_digest,
|
|
||||||
constants.MOD_SSL_CONF_SRC, constants.ALL_SSL_OPTIONS_HASHES)
|
|
||||||
|
|
||||||
|
|
||||||
def _determine_default_server_root():
|
def _determine_default_server_root():
|
||||||
if os.environ.get("CERTBOT_DOCS") == "1":
|
if os.environ.get("CERTBOT_DOCS") == "1":
|
||||||
default_server_root = "%s or %s" % (constants.LINUX_SERVER_ROOT,
|
default_server_root = "%s or %s" % (constants.LINUX_SERVER_ROOT,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
"""nginx plugin constants."""
|
"""nginx plugin constants."""
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
|
|
||||||
FREEBSD_DARWIN_SERVER_ROOT = "/usr/local/etc/nginx"
|
FREEBSD_DARWIN_SERVER_ROOT = "/usr/local/etc/nginx"
|
||||||
LINUX_SERVER_ROOT = "/etc/nginx"
|
LINUX_SERVER_ROOT = "/etc/nginx"
|
||||||
|
|
||||||
@@ -21,14 +19,13 @@ CLI_DEFAULTS = dict(
|
|||||||
MOD_SSL_CONF_DEST = "options-ssl-nginx.conf"
|
MOD_SSL_CONF_DEST = "options-ssl-nginx.conf"
|
||||||
"""Name of the mod_ssl config file as saved in `IConfig.config_dir`."""
|
"""Name of the mod_ssl config file as saved in `IConfig.config_dir`."""
|
||||||
|
|
||||||
MOD_SSL_CONF_SRC = pkg_resources.resource_filename(
|
|
||||||
"certbot_nginx", "options-ssl-nginx.conf")
|
|
||||||
"""Path to the nginx mod_ssl config file found in the Certbot
|
|
||||||
distribution."""
|
|
||||||
|
|
||||||
UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
|
UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
|
||||||
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
|
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
|
||||||
|
|
||||||
|
SSL_OPTIONS_HASHES_NEW = [
|
||||||
|
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
|
||||||
|
]
|
||||||
|
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9"""
|
||||||
|
|
||||||
ALL_SSL_OPTIONS_HASHES = [
|
ALL_SSL_OPTIONS_HASHES = [
|
||||||
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
|
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
|
||||||
@@ -37,7 +34,7 @@ ALL_SSL_OPTIONS_HASHES = [
|
|||||||
'7f95624dd95cf5afc708b9f967ee83a24b8025dc7c8d9df2b556bbc64256b3ff',
|
'7f95624dd95cf5afc708b9f967ee83a24b8025dc7c8d9df2b556bbc64256b3ff',
|
||||||
'394732f2bbe3e5e637c3fb5c6e980a1f1b90b01e2e8d6b7cff41dde16e2a756d',
|
'394732f2bbe3e5e637c3fb5c6e980a1f1b90b01e2e8d6b7cff41dde16e2a756d',
|
||||||
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
|
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
|
||||||
]
|
] + SSL_OPTIONS_HASHES_NEW
|
||||||
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
|
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
|
||||||
|
|
||||||
def os_constant(key):
|
def os_constant(key):
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# This file contains important security parameters. If you modify this file
|
||||||
|
# manually, Certbot will be unable to automatically provide future security
|
||||||
|
# updates. Instead, Certbot will print and log an error message with a path to
|
||||||
|
# the up-to-date file that you will need to refer to when manually updating
|
||||||
|
# this file.
|
||||||
|
|
||||||
|
ssl_session_cache shared:le_nginx_SSL:1m;
|
||||||
|
ssl_session_timeout 1440m;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
ssl_session_cache shared:le_nginx_SSL:1m;
|
ssl_session_cache shared:le_nginx_SSL:1m;
|
||||||
ssl_session_timeout 1440m;
|
ssl_session_timeout 1440m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers on;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from certbot import errors
|
|||||||
from certbot.compat import os
|
from certbot.compat import os
|
||||||
from certbot.tests import util as certbot_test_util
|
from certbot.tests import util as certbot_test_util
|
||||||
|
|
||||||
from certbot_nginx import constants
|
|
||||||
from certbot_nginx import obj
|
from certbot_nginx import obj
|
||||||
from certbot_nginx import parser
|
from certbot_nginx import parser
|
||||||
from certbot_nginx.configurator import _redirect_block_for_domain
|
from certbot_nginx.configurator import _redirect_block_for_domain
|
||||||
@@ -883,12 +882,11 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
|||||||
self.config_path, self.config_dir, self.work_dir, self.logs_dir)
|
self.config_path, self.config_dir, self.work_dir, self.logs_dir)
|
||||||
|
|
||||||
def _call(self):
|
def _call(self):
|
||||||
from certbot_nginx.configurator import install_ssl_options_conf
|
self.config.install_ssl_options_conf(self.config.mod_ssl_conf,
|
||||||
install_ssl_options_conf(self.config.mod_ssl_conf, self.config.updated_mod_ssl_conf_digest)
|
self.config.updated_mod_ssl_conf_digest)
|
||||||
|
|
||||||
def _current_ssl_options_hash(self):
|
def _current_ssl_options_hash(self):
|
||||||
from certbot_nginx.constants import MOD_SSL_CONF_SRC
|
return crypto_util.sha256sum(self.config.mod_ssl_conf_src)
|
||||||
return crypto_util.sha256sum(MOD_SSL_CONF_SRC)
|
|
||||||
|
|
||||||
def _assert_current_file(self):
|
def _assert_current_file(self):
|
||||||
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
||||||
@@ -908,13 +906,33 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
|||||||
self._call()
|
self._call()
|
||||||
self._assert_current_file()
|
self._assert_current_file()
|
||||||
|
|
||||||
|
def _mock_hash_except_ssl_conf_src(self, fake_hash):
|
||||||
|
# Write a bad file in place so that update tests fail if no update occurs.
|
||||||
|
# We're going to pretend this file (the currently installed conf file)
|
||||||
|
# actually hashes to `fake_hash` for the update tests.
|
||||||
|
with open(self.config.mod_ssl_conf, "w") as f:
|
||||||
|
f.write("bogus")
|
||||||
|
sha256 = crypto_util.sha256sum
|
||||||
|
def _hash(filename):
|
||||||
|
return sha256(filename) if filename == self.config.mod_ssl_conf_src else fake_hash
|
||||||
|
return _hash
|
||||||
|
|
||||||
def test_prev_file_updates_to_current(self):
|
def test_prev_file_updates_to_current(self):
|
||||||
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
|
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
|
||||||
with mock.patch('certbot.crypto_util.sha256sum') as mock_sha256:
|
with mock.patch('certbot.crypto_util.sha256sum',
|
||||||
mock_sha256.return_value = ALL_SSL_OPTIONS_HASHES[0]
|
new=self._mock_hash_except_ssl_conf_src(ALL_SSL_OPTIONS_HASHES[0])):
|
||||||
self._call()
|
self._call()
|
||||||
self._assert_current_file()
|
self._assert_current_file()
|
||||||
|
|
||||||
|
def test_prev_file_updates_to_current_old_nginx(self):
|
||||||
|
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES, SSL_OPTIONS_HASHES_NEW
|
||||||
|
self.config.version = (1, 5, 8)
|
||||||
|
with mock.patch('certbot.crypto_util.sha256sum',
|
||||||
|
new=self._mock_hash_except_ssl_conf_src(ALL_SSL_OPTIONS_HASHES[0])):
|
||||||
|
self._call()
|
||||||
|
self._assert_current_file()
|
||||||
|
self.assertTrue(self._current_ssl_options_hash() not in SSL_OPTIONS_HASHES_NEW)
|
||||||
|
|
||||||
def test_manually_modified_current_file_does_not_update(self):
|
def test_manually_modified_current_file_does_not_update(self):
|
||||||
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
|
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
|
||||||
mod_ssl_conf.write("a new line for the wrong hash\n")
|
mod_ssl_conf.write("a new line for the wrong hash\n")
|
||||||
@@ -922,7 +940,7 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
|||||||
self._call()
|
self._call()
|
||||||
self.assertFalse(mock_logger.warning.called)
|
self.assertFalse(mock_logger.warning.called)
|
||||||
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
||||||
self.assertEqual(crypto_util.sha256sum(constants.MOD_SSL_CONF_SRC),
|
self.assertEqual(crypto_util.sha256sum(self.config.mod_ssl_conf_src),
|
||||||
self._current_ssl_options_hash())
|
self._current_ssl_options_hash())
|
||||||
self.assertNotEqual(crypto_util.sha256sum(self.config.mod_ssl_conf),
|
self.assertNotEqual(crypto_util.sha256sum(self.config.mod_ssl_conf),
|
||||||
self._current_ssl_options_hash())
|
self._current_ssl_options_hash())
|
||||||
@@ -937,7 +955,7 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
|||||||
self.assertEqual(mock_logger.warning.call_args[0][0],
|
self.assertEqual(mock_logger.warning.call_args[0][0],
|
||||||
"%s has been manually modified; updated file "
|
"%s has been manually modified; updated file "
|
||||||
"saved to %s. We recommend updating %s for security purposes.")
|
"saved to %s. We recommend updating %s for security purposes.")
|
||||||
self.assertEqual(crypto_util.sha256sum(constants.MOD_SSL_CONF_SRC),
|
self.assertEqual(crypto_util.sha256sum(self.config.mod_ssl_conf_src),
|
||||||
self._current_ssl_options_hash())
|
self._current_ssl_options_hash())
|
||||||
# only print warning once
|
# only print warning once
|
||||||
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
||||||
@@ -950,6 +968,16 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
|||||||
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
|
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
|
||||||
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
|
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
|
||||||
|
|
||||||
|
def test_old_nginx_version_uses_old_config(self):
|
||||||
|
self.config.version = (1, 5, 8)
|
||||||
|
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||||
|
"options-ssl-nginx-old.conf")
|
||||||
|
self._call()
|
||||||
|
self._assert_current_file()
|
||||||
|
self.config.version = (1, 5, 9)
|
||||||
|
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||||
|
"options-ssl-nginx.conf")
|
||||||
|
|
||||||
|
|
||||||
class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):
|
class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):
|
||||||
"""Tests for certbot_nginx.configurator._determine_default_server_root."""
|
"""Tests for certbot_nginx.configurator._determine_default_server_root."""
|
||||||
|
|||||||
Reference in New Issue
Block a user