mirror of
https://github.com/certbot/certbot.git
synced 2026-08-02 16:12:09 +02:00
Gradually increasing HSTS max-age (#5912)
This PR adds the functionality to enhance Apache configuration to include HTTP Strict Transport Security header with a low initial max-age value. The max-age value will get increased on every (scheduled) run of certbot renew regardless of the certificate actually getting renewed, if the last increase took place longer than ten hours ago. The increase steps are visible in constants.AUTOHSTS_STEPS. Upon the first actual renewal after reaching the maximum increase step, the max-age value will be made "permanent" and will get value of one year. To achieve accurate VirtualHost discovery on subsequent runs, a comment with unique id string will be added to each enhanced VirtualHost. * AutoHSTS code rebased on master * Fixes to match the changes in master * Make linter happy with metaclass registration * Address small review comments * Use new enhancement interfaces * New style enhancement changes * Do not allow --hsts and --auto-hsts simultaneuously * MyPy annotation fixes and added test * Change oldest requrements to point to local certbot core version * Enable new style enhancements for run and install verbs * Test refactor * New test class for main.install tests * Move a test to a correct test class
This commit is contained in:
committed by
Brad Warren
parent
a875246a4b
commit
3877af6619
+37
-7
@@ -36,7 +36,7 @@ from certbot import util
|
||||
from certbot.display import util as display_util, ops as display_ops
|
||||
from certbot.plugins import disco as plugins_disco
|
||||
from certbot.plugins import selection as plug_sel
|
||||
|
||||
from certbot.plugins import enhancements
|
||||
|
||||
USER_CANCELLED = ("User chose to cancel the operation and may "
|
||||
"reinvoke the client.")
|
||||
@@ -750,8 +750,8 @@ def _install_cert(config, le_client, domains, lineage=None):
|
||||
:param le_client: Client object
|
||||
:type le_client: client.Client
|
||||
|
||||
:param plugins: List of domains
|
||||
:type plugins: `list` of `str`
|
||||
:param domains: List of domains
|
||||
:type domains: `list` of `str`
|
||||
|
||||
:param lineage: Certificate lineage object. Defaults to `None`
|
||||
:type lineage: storage.RenewableCert
|
||||
@@ -789,11 +789,19 @@ def install(config, plugins):
|
||||
except errors.PluginSelectionError as e:
|
||||
return str(e)
|
||||
|
||||
if not enhancements.are_supported(config, installer):
|
||||
raise errors.NotSupportedError("One ore more of the requested enhancements "
|
||||
"are not supported by the selected installer")
|
||||
# If cert-path is defined, populate missing (ie. not overridden) values.
|
||||
# Unfortunately this can't be done in argument parser, as certificate
|
||||
# manager needs the access to renewal directory paths
|
||||
if config.certname:
|
||||
config = _populate_from_certname(config)
|
||||
elif enhancements.are_requested(config):
|
||||
# Preflight config check
|
||||
raise errors.ConfigurationError("One or more of the requested enhancements "
|
||||
"require --cert-name to be provided")
|
||||
|
||||
if config.key_path and config.cert_path:
|
||||
_check_certificate_and_key(config)
|
||||
domains, _ = _find_domains_or_certname(config, installer)
|
||||
@@ -804,6 +812,11 @@ def install(config, plugins):
|
||||
"If your certificate is managed by Certbot, please use --cert-name "
|
||||
"to define which certificate you would like to install.")
|
||||
|
||||
if enhancements.are_requested(config):
|
||||
# In the case where we don't have certname, we have errored out already
|
||||
lineage = cert_manager.lineage_for_certname(config, config.certname)
|
||||
enhancements.enable(lineage, domains, installer, config)
|
||||
|
||||
def _populate_from_certname(config):
|
||||
"""Helper function for install to populate missing config values from lineage
|
||||
defined by --cert-name."""
|
||||
@@ -881,7 +894,8 @@ def enhance(config, plugins):
|
||||
"""
|
||||
supported_enhancements = ["hsts", "redirect", "uir", "staple"]
|
||||
# Check that at least one enhancement was requested on command line
|
||||
if not any([getattr(config, enh) for enh in supported_enhancements]):
|
||||
oldstyle_enh = any([getattr(config, enh) for enh in supported_enhancements])
|
||||
if not enhancements.are_requested(config) and not oldstyle_enh:
|
||||
msg = ("Please specify one or more enhancement types to configure. To list "
|
||||
"the available enhancement types, run:\n\n%s --help enhance\n")
|
||||
logger.warning(msg, sys.argv[0])
|
||||
@@ -892,6 +906,10 @@ def enhance(config, plugins):
|
||||
except errors.PluginSelectionError as e:
|
||||
return str(e)
|
||||
|
||||
if not enhancements.are_supported(config, installer):
|
||||
raise errors.NotSupportedError("One ore more of the requested enhancements "
|
||||
"are not supported by the selected installer")
|
||||
|
||||
certname_question = ("Which certificate would you like to use to enhance "
|
||||
"your configuration?")
|
||||
config.certname = cert_manager.get_certnames(
|
||||
@@ -907,11 +925,15 @@ def enhance(config, plugins):
|
||||
if not domains:
|
||||
raise errors.Error("User cancelled the domain selection. No domains "
|
||||
"defined, exiting.")
|
||||
|
||||
lineage = cert_manager.lineage_for_certname(config, config.certname)
|
||||
if not config.chain_path:
|
||||
lineage = cert_manager.lineage_for_certname(config, config.certname)
|
||||
config.chain_path = lineage.chain_path
|
||||
le_client = _init_le_client(config, authenticator=None, installer=installer)
|
||||
le_client.enhance_config(domains, config.chain_path, ask_redirect=False)
|
||||
if oldstyle_enh:
|
||||
le_client = _init_le_client(config, authenticator=None, installer=installer)
|
||||
le_client.enhance_config(domains, config.chain_path, ask_redirect=False)
|
||||
if enhancements.are_requested(config):
|
||||
enhancements.enable(lineage, domains, installer, config)
|
||||
|
||||
|
||||
def rollback(config, plugins):
|
||||
@@ -1073,6 +1095,11 @@ def run(config, plugins): # pylint: disable=too-many-branches,too-many-locals
|
||||
except errors.PluginSelectionError as e:
|
||||
return str(e)
|
||||
|
||||
# Preflight check for enhancement support by the selected installer
|
||||
if not enhancements.are_supported(config, installer):
|
||||
raise errors.NotSupportedError("One ore more of the requested enhancements "
|
||||
"are not supported by the selected installer")
|
||||
|
||||
# TODO: Handle errors from _init_le_client?
|
||||
le_client = _init_le_client(config, authenticator, installer)
|
||||
|
||||
@@ -1091,6 +1118,9 @@ def run(config, plugins): # pylint: disable=too-many-branches,too-many-locals
|
||||
|
||||
_install_cert(config, le_client, domains, new_lineage)
|
||||
|
||||
if enhancements.are_requested(config) and new_lineage:
|
||||
enhancements.enable(new_lineage, domains, installer, config)
|
||||
|
||||
if lineage is None or not should_get_cert:
|
||||
display_ops.success_installation(domains)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user