New enhancements proposal

This commit is contained in:
Joona Hoikkala 2018-05-09 23:06:08 +03:00
parent 83ea820525
commit d40f9dc001
No known key found for this signature in database
GPG key ID: 1708DAE66E87A524
5 changed files with 196 additions and 3 deletions

View file

@ -20,6 +20,7 @@ from certbot import util
from certbot.plugins import common
from certbot.plugins.util import path_surgery
from certbot.plugins.enhancements import AutoHSTSEnhancement
from certbot_apache import apache_util
from certbot_apache import augeas_configurator
@ -2156,3 +2157,24 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# to be modified.
return common.install_version_controlled_file(options_ssl, options_ssl_digest,
self.constant("MOD_SSL_CONF_SRC"), constants.ALL_SSL_OPTIONS_HASHES)
def update_autohsts(self, domain):
"""
The actual enhancement update method in installer plugin.
"""
logger.warning("NOOP from update")
def deploy_autohsts(self, lineage):
"""
The actual enhancement deploy method in installer plugin.
"""
logger.warning("NOOP from deploy")
def enable_autohsts(self, lineage):
"""
The actual enhancement enabling method in installer plugin.
"""
logger.warning("NOOP from enable")
AutoHSTSEnhancement.register(ApacheConfigurator)

View file

@ -28,6 +28,7 @@ from certbot import util
from certbot.display import util as display_util
from certbot.plugins import disco as plugins_disco
import certbot.plugins.enhancements as enhancements
import certbot.plugins.selection as plugin_selection
logger = logging.getLogger(__name__)
@ -1201,6 +1202,12 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
" is renewed. This setting does not apply to important TLS configuration"
" updates.")
# Add the new style enhancements
for enh in enhancements.INDEX:
helpful.add(enh["cli_groups"], enh["cli_flag"], action=enh["cli_action"],
dest=enh["cli_dest"], default=enh["cli_flag_default"],
help=enh["cli_help"])
helpful.add_deprecated_argument("--agree-dev-preview", 0)
helpful.add_deprecated_argument("--dialog", 0)

View file

@ -33,6 +33,7 @@ from certbot import updater
from certbot import util
from certbot.display import util as display_util, ops as display_ops
from certbot.plugins import enhancements
from certbot.plugins import disco as plugins_disco
from certbot.plugins import selection as plug_sel
@ -877,7 +878,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.is_supported(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])
@ -906,8 +908,11 @@ def enhance(config, plugins):
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.is_supported(config):
enhancements.enable(lineage, installer, config)
def rollback(config, plugins):

View file

@ -0,0 +1,109 @@
import abc
import six
from certbot import errors
def is_supported(config):
"""Checks if one or more of the requested enhancements are supported by
the enhancement interfaces."""
supported = []
for enh in INDEX:
if hasattr(config, enh["cli_dest"]):
supported.append(getattr(config, enh["cli_dest"]))
return bool(supported)
def enable(lineage, installer, config):
"""
Run enable method for each requested enhancement that is supported.
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:param installer: Installer object
:type installer: interfaces.IInstaller
:param config: Configuration.
:type config: :class:`certbot.interfaces.IConfig`
"""
for enh in INDEX:
if hasattr(config, enh["cli_dest"]) and getattr(config, enh["cli_dest"]):
if not isinstance(installer, enh["class"]):
msg = ("Requested enhancement {} not supported by selected "
"installer").format(enh["name"])
raise errors.NotSupportedError(msg)
# Run the enable function
getattr(installer, enh["enable_function"])(lineage)
@six.add_metaclass(abc.ABCMeta)
class AutoHSTSEnhancement(object):
"""Example enhancement interface class for AutoHSTS"""
@abc.abstractmethod
def update_autohsts(self, domain, *args, **kwargs):
"""As updater function, takes the same parameters as
interfaces.GenericUpdater.generic_updates
"""
@abc.abstractmethod
def deploy_autohsts(self, lineage, *args, **kwargs):
"""As renewer function, takes the same parameters as
interfaces.RenewDeployer
"""
@abc.abstractmethod
def enable_autohsts(self, lineage, *args, **kwargs):
"""Installer function, uses lineage as a parameter.
"""
@six.add_metaclass(abc.ABCMeta)
class OCSPPrefetchEnhancement(object):
"""Example enhancement interface class for OCSP prefetch"""
@abc.abstractmethod
def update_ocsp_prefetch(self, domain, *args, **kwargs):
"""As updater function, takes the same parameters as
interfaces.GenericUpdater.generic_updates
"""
@abc.abstractmethod
def deploy_ocsp_prefetch(self, lineage, *args, **kwargs):
"""As renewer function, takes the same parameters as
interfaces.RenewDeployer
"""
@abc.abstractmethod
def enable_ocsp_prefetch(self, lineage, *args, **kwargs):
"""Installer function, uses lineage as a parameter."""
INDEX = [
{
"name": "AutoHSTS",
"cli_help": "Gradually increasing max-age value for HTTP Strict Transport "+
"Security security header",
"cli_flag": "--autohsts",
"cli_flag_default": None,
"cli_groups": ["security", "enhance"],
"cli_dest": "auto_hsts",
"cli_action": "store_true",
"class": AutoHSTSEnhancement,
"updater_function": "update_autohsts",
"deployer_function": "deploy_autohsts",
"enable_function": "enable_autohsts"
},
{
"name": "OCSP Prefetch",
"cli_help": "Prefetch OCSP responses within scheduled run with renew verb",
"cli_flag": "--ocspprefetch",
"cli_flag_default": None,
"cli_groups": ["security", "enhance"],
"cli_dest": "ocsp_prefetch",
"cli_action": "store_true",
"class": OCSPPrefetchEnhancement,
"updater_function": "update_ocsp_prefetch",
"deployer_function": None,
"enable_function": "enable_ocsp_prefetch"
}
]

View file

@ -5,6 +5,7 @@ from certbot import errors
from certbot import interfaces
from certbot.plugins import selection as plug_sel
import certbot.plugins.enhancements as enhancements
logger = logging.getLogger(__name__)
@ -30,6 +31,7 @@ def run_generic_updaters(config, plugins, lineage):
logger.warning("Could not choose appropriate plugin for updaters: %s", e)
return
_run_updaters(lineage, installer, config)
_run_enhancement_updaters(lineage, installer, config)
def run_renewal_deployer(lineage, installer, config):
"""Helper function to run deployer interface method if supported by the used
@ -47,6 +49,7 @@ def run_renewal_deployer(lineage, installer, config):
if not config.disable_renew_updates and isinstance(installer,
interfaces.RenewDeployer):
installer.renew_deploy(lineage)
_run_enhancement_deployers(lineage, installer, config)
def _run_updaters(lineage, installer, config):
"""Helper function to run the updater interface methods if supported by the
@ -65,3 +68,50 @@ def _run_updaters(lineage, installer, config):
if not config.disable_renew_updates:
if isinstance(installer, interfaces.GenericUpdater):
installer.generic_updates(domain)
def _run_enhancement_updaters(lineage, installer, config):
"""Iterates through known enhancement interfaces. If the installer implements
an enhancement interface and the enhance interface has an updater method, the
updater method gets run.
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:param installer: Installer object
:type installer: interfaces.IInstaller
:param config: Configuration object
:type config: interfaces.IConfig
"""
if config.disable_renew_updates:
return
for enh in enhancements.INDEX:
if isinstance(installer, enh["class"]) and enh["updater_function"]:
upd_func = getattr(installer, enh["updater_function"])
for domain in lineage.names():
upd_func(domain)
else:
continue
def _run_enhancement_deployers(lineage, installer, config):
"""Iterates through known enhancement interfaces. If the installer implements
an enhancement interface and the enhance interface has an deployer method, the
deployer method gets run.
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:param installer: Installer object
:type installer: interfaces.IInstaller
:param config: Configuration object
:type config: interfaces.IConfig
"""
if config.disable_renew_updates:
return
for enh in enhancements.INDEX:
if isinstance(installer, enh["class"]) and enh["deployer_function"]:
getattr(installer, enh["deployer_function"])(lineage)