mirror of
https://github.com/certbot/certbot.git
synced 2026-06-04 06:15:36 -04:00
Merge branch 'master' into certbot-ci-part5
This commit is contained in:
commit
0b42ab0aba
67 changed files with 1129 additions and 195 deletions
38
CHANGELOG.md
38
CHANGELOG.md
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## 0.34.0 - master
|
||||
## 0.35.0 - master
|
||||
|
||||
### Added
|
||||
|
||||
|
|
@ -10,6 +10,24 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
|||
|
||||
### Changed
|
||||
|
||||
*
|
||||
|
||||
### Fixed
|
||||
|
||||
*
|
||||
|
||||
Despite us having broken lockstep, we are continuing to release new versions of
|
||||
all Certbot components during releases for the time being, however, the only
|
||||
package with changes other than its version number was:
|
||||
|
||||
*
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.34.0 - 2019-05-01
|
||||
|
||||
### Changed
|
||||
|
||||
* Apache plugin now tries to restart httpd on Fedora using systemctl if a
|
||||
configuration test error is detected. This has to be done due to the way
|
||||
Fedora now generates the self signed certificate files upon first
|
||||
|
|
@ -22,10 +40,20 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
|||
`malformed` error to be received from the ACME server.
|
||||
* Linode DNS plugin now supports api keys created from their new panel
|
||||
at [cloud.linode.com](https://cloud.linode.com)
|
||||
|
||||
### Fixed
|
||||
|
||||
*
|
||||
* Adding a warning noting that future versions of Certbot will automatically configure the
|
||||
webserver so that all requests redirect to secure HTTPS access. You can control this
|
||||
behavior and disable this warning with the --redirect and --no-redirect flags.
|
||||
* certbot-auto now prints warnings when run as root with insecure file system
|
||||
permissions. If you see these messages, you should fix the problem by
|
||||
following the instructions at
|
||||
https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/,
|
||||
however, these warnings can be disabled as necessary with the flag
|
||||
--no-permissions-check.
|
||||
* `acme` module uses now a POST-as-GET request to retrieve the registration
|
||||
from an ACME v2 server
|
||||
* Convert the tsig algorithm specified in the certbot_dns_rfc2136 configuration file to
|
||||
all uppercase letters before validating. This makes the value in the config case
|
||||
insensitive.
|
||||
|
||||
Despite us having broken lockstep, we are continuing to release new versions of
|
||||
all Certbot components during releases for the time being, however, the only
|
||||
|
|
|
|||
|
|
@ -123,15 +123,6 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
|
|||
"""
|
||||
return self.update_registration(regr, update={'status': 'deactivated'})
|
||||
|
||||
def query_registration(self, regr):
|
||||
"""Query server about registration.
|
||||
|
||||
:param messages.RegistrationResource: Existing Registration
|
||||
Resource.
|
||||
|
||||
"""
|
||||
return self._send_recv_regr(regr, messages.UpdateRegistration())
|
||||
|
||||
def _authzr_from_response(self, response, identifier=None, uri=None):
|
||||
authzr = messages.AuthorizationResource(
|
||||
body=messages.Authorization.from_json(response.json()),
|
||||
|
|
@ -276,6 +267,15 @@ class Client(ClientBase):
|
|||
# pylint: disable=no-member
|
||||
return self._regr_from_response(response)
|
||||
|
||||
def query_registration(self, regr):
|
||||
"""Query server about registration.
|
||||
|
||||
:param messages.RegistrationResource: Existing Registration
|
||||
Resource.
|
||||
|
||||
"""
|
||||
return self._send_recv_regr(regr, messages.UpdateRegistration())
|
||||
|
||||
def agree_to_tos(self, regr):
|
||||
"""Agree to the terms-of-service.
|
||||
|
||||
|
|
@ -603,10 +603,13 @@ class ClientV2(ClientBase):
|
|||
Resource.
|
||||
|
||||
"""
|
||||
self.net.account = regr
|
||||
updated_regr = super(ClientV2, self).query_registration(regr)
|
||||
self.net.account = updated_regr
|
||||
return updated_regr
|
||||
self.net.account = regr # See certbot/certbot#6258
|
||||
# ACME v2 requires to use a POST-as-GET request (POST an empty JWS) here.
|
||||
# This is done by passing None instead of an empty UpdateRegistration to _post().
|
||||
response = self._post(regr.uri, None)
|
||||
self.net.account = self._regr_from_response(response, uri=regr.uri,
|
||||
terms_of_service=regr.terms_of_service)
|
||||
return self.net.account
|
||||
|
||||
def update_registration(self, regr, update=None):
|
||||
"""Update registration.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from setuptools import find_packages
|
|||
from setuptools.command.test import test as TestCommand
|
||||
import sys
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
""" Entry point for Apache Plugin """
|
||||
# Pylint does not like disutils.version when running inside a venv.
|
||||
# See: https://github.com/PyCQA/pylint/issues/73
|
||||
from distutils.version import LooseVersion # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
from certbot import util
|
||||
|
||||
from certbot_apache import configurator
|
||||
from certbot_apache import override_arch
|
||||
from certbot_apache import override_fedora
|
||||
from certbot_apache import override_darwin
|
||||
from certbot_apache import override_debian
|
||||
from certbot_apache import override_centos
|
||||
|
|
@ -16,7 +21,8 @@ OVERRIDE_CLASSES = {
|
|||
"ubuntu": override_debian.DebianConfigurator,
|
||||
"centos": override_centos.CentOSConfigurator,
|
||||
"centos linux": override_centos.CentOSConfigurator,
|
||||
"fedora": override_centos.CentOSConfigurator,
|
||||
"fedora_old": override_centos.CentOSConfigurator,
|
||||
"fedora": override_fedora.FedoraConfigurator,
|
||||
"ol": override_centos.CentOSConfigurator,
|
||||
"red hat enterprise linux server": override_centos.CentOSConfigurator,
|
||||
"rhel": override_centos.CentOSConfigurator,
|
||||
|
|
@ -27,12 +33,19 @@ OVERRIDE_CLASSES = {
|
|||
"suse": override_suse.OpenSUSEConfigurator,
|
||||
}
|
||||
|
||||
|
||||
def get_configurator():
|
||||
""" Get correct configurator class based on the OS fingerprint """
|
||||
os_info = util.get_os_info()
|
||||
os_name, os_version = util.get_os_info()
|
||||
os_name = os_name.lower()
|
||||
override_class = None
|
||||
|
||||
# Special case for older Fedora versions
|
||||
if os_name == 'fedora' and LooseVersion(os_version) < LooseVersion('29'):
|
||||
os_name = 'fedora_old'
|
||||
|
||||
try:
|
||||
override_class = OVERRIDE_CLASSES[os_info[0].lower()]
|
||||
override_class = OVERRIDE_CLASSES[os_name]
|
||||
except KeyError:
|
||||
# OS not found in the list
|
||||
os_like = util.get_systemd_os_like()
|
||||
|
|
@ -45,4 +58,5 @@ def get_configurator():
|
|||
override_class = configurator.ApacheConfigurator
|
||||
return override_class
|
||||
|
||||
|
||||
ENTRYPOINT = get_configurator()
|
||||
|
|
|
|||
98
certbot-apache/certbot_apache/override_fedora.py
Normal file
98
certbot-apache/certbot_apache/override_fedora.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
""" Distribution specific override class for Fedora 29+ """
|
||||
import pkg_resources
|
||||
import zope.interface
|
||||
|
||||
from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot import util
|
||||
|
||||
from certbot_apache import apache_util
|
||||
from certbot_apache import configurator
|
||||
from certbot_apache import parser
|
||||
|
||||
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class FedoraConfigurator(configurator.ApacheConfigurator):
|
||||
"""Fedora 29+ specific ApacheConfigurator override class"""
|
||||
|
||||
OS_DEFAULTS = dict(
|
||||
server_root="/etc/httpd",
|
||||
vhost_root="/etc/httpd/conf.d",
|
||||
vhost_files="*.conf",
|
||||
logs_root="/var/log/httpd",
|
||||
ctl="httpd",
|
||||
version_cmd=['httpd', '-v'],
|
||||
restart_cmd=['apachectl', 'graceful'],
|
||||
restart_cmd_alt=['apachectl', 'restart'],
|
||||
conftest_cmd=['apachectl', 'configtest'],
|
||||
enmod=None,
|
||||
dismod=None,
|
||||
le_vhost_ext="-le-ssl.conf",
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf.d",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
# TODO: eventually newest version of Fedora will need their own config
|
||||
"certbot_apache", "centos-options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def config_test(self):
|
||||
"""
|
||||
Override config_test to mitigate configtest error in vanilla installation
|
||||
of mod_ssl in Fedora. The error is caused by non-existent self-signed
|
||||
certificates referenced by the configuration, that would be autogenerated
|
||||
during the first (re)start of httpd.
|
||||
"""
|
||||
try:
|
||||
super(FedoraConfigurator, self).config_test()
|
||||
except errors.MisconfigurationError:
|
||||
self._try_restart_fedora()
|
||||
|
||||
def get_parser(self):
|
||||
"""Initializes the ApacheParser"""
|
||||
return FedoraParser(
|
||||
self.aug, self.option("server_root"), self.option("vhost_root"),
|
||||
self.version, configurator=self)
|
||||
|
||||
def _try_restart_fedora(self):
|
||||
"""
|
||||
Tries to restart httpd using systemctl to generate the self signed keypair.
|
||||
"""
|
||||
try:
|
||||
util.run_script(['systemctl', 'restart', 'httpd'])
|
||||
except errors.SubprocessError as err:
|
||||
raise errors.MisconfigurationError(str(err))
|
||||
|
||||
# Finish with actual config check to see if systemctl restart helped
|
||||
super(FedoraConfigurator, self).config_test()
|
||||
|
||||
def _prepare_options(self):
|
||||
"""
|
||||
Override the options dictionary initialization to keep using apachectl
|
||||
instead of httpd and so take advantages of this new bash script in newer versions
|
||||
of Fedora to restart httpd.
|
||||
"""
|
||||
super(FedoraConfigurator, self)._prepare_options()
|
||||
self.options["restart_cmd"][0] = 'apachectl'
|
||||
self.options["restart_cmd_alt"][0] = 'apachectl'
|
||||
self.options["conftest_cmd"][0] = 'apachectl'
|
||||
|
||||
|
||||
class FedoraParser(parser.ApacheParser):
|
||||
"""Fedora 29+ specific ApacheParser override class"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Fedora 29+ specific configuration file for Apache
|
||||
self.sysconfig_filep = "/etc/sysconfig/httpd"
|
||||
super(FedoraParser, self).__init__(*args, **kwargs)
|
||||
|
||||
def update_runtime_variables(self):
|
||||
""" Override for update_runtime_variables for custom parsing """
|
||||
# Opportunistic, works if SELinux not enforced
|
||||
super(FedoraParser, self).update_runtime_variables()
|
||||
self._parse_sysconfig_var()
|
||||
|
||||
def _parse_sysconfig_var(self):
|
||||
""" Parses Apache CLI options from Fedora configuration file """
|
||||
defines = apache_util.parse_define_file(self.sysconfig_filep, "OPTIONS")
|
||||
for k in defines:
|
||||
self.variables[k] = defines[k]
|
||||
|
|
@ -43,13 +43,14 @@ class FedoraRestartTest(util.ApacheTest):
|
|||
vhost_root=vhost_root)
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.vhost_path, self.config_dir, self.work_dir,
|
||||
os_info="fedora")
|
||||
os_info="fedora_old")
|
||||
self.vh_truth = get_vh_truth(
|
||||
self.temp_dir, "centos7_apache/apache")
|
||||
|
||||
def _run_fedora_test(self):
|
||||
self.assertIsInstance(self.config, override_centos.CentOSConfigurator)
|
||||
with mock.patch("certbot.util.get_os_info") as mock_info:
|
||||
mock_info.return_value = ["fedora"]
|
||||
mock_info.return_value = ["fedora", "28"]
|
||||
self.config.config_test()
|
||||
|
||||
def test_non_fedora_error(self):
|
||||
|
|
@ -103,8 +104,7 @@ class MultipleVhostsTestCentOS(util.ApacheTest):
|
|||
self.temp_dir, "centos7_apache/apache")
|
||||
|
||||
def test_get_parser(self):
|
||||
self.assertTrue(isinstance(self.config.parser,
|
||||
override_centos.CentOSParser))
|
||||
self.assertIsInstance(self.config.parser, override_centos.CentOSParser)
|
||||
|
||||
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
|
||||
def test_opportunistic_httpd_runtime_parsing(self, mock_get):
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mock
|
|||
from certbot_apache import configurator
|
||||
from certbot_apache import entrypoint
|
||||
|
||||
|
||||
class EntryPointTest(unittest.TestCase):
|
||||
"""Entrypoint tests"""
|
||||
|
||||
|
|
@ -15,7 +16,12 @@ class EntryPointTest(unittest.TestCase):
|
|||
|
||||
with mock.patch("certbot.util.get_os_info") as mock_info:
|
||||
for distro in entrypoint.OVERRIDE_CLASSES:
|
||||
mock_info.return_value = (distro, "whatever")
|
||||
return_value = (distro, "whatever")
|
||||
if distro == 'fedora_old':
|
||||
return_value = ('fedora', '28')
|
||||
elif distro == 'fedora':
|
||||
return_value = ('fedora', '29')
|
||||
mock_info.return_value = return_value
|
||||
self.assertEqual(entrypoint.get_configurator(),
|
||||
entrypoint.OVERRIDE_CLASSES[distro])
|
||||
|
||||
|
|
|
|||
194
certbot-apache/certbot_apache/tests/fedora_test.py
Normal file
194
certbot-apache/certbot_apache/tests/fedora_test.py
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
"""Test for certbot_apache.configurator for Fedora 29+ overrides"""
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
|
||||
from certbot import errors
|
||||
from certbot.compat import os
|
||||
|
||||
from certbot_apache import obj
|
||||
from certbot_apache import override_fedora
|
||||
from certbot_apache.tests import util
|
||||
|
||||
|
||||
def get_vh_truth(temp_dir, config_name):
|
||||
"""Return the ground truth for the specified directory."""
|
||||
prefix = os.path.join(
|
||||
temp_dir, config_name, "httpd/conf.d")
|
||||
|
||||
aug_pre = "/files" + prefix
|
||||
# TODO: eventually, these tests should have a dedicated configuration instead
|
||||
# of reusing the ones from centos_test
|
||||
vh_truth = [
|
||||
obj.VirtualHost(
|
||||
os.path.join(prefix, "centos.example.com.conf"),
|
||||
os.path.join(aug_pre, "centos.example.com.conf/VirtualHost"),
|
||||
{obj.Addr.fromstring("*:80")},
|
||||
False, True, "centos.example.com"),
|
||||
obj.VirtualHost(
|
||||
os.path.join(prefix, "ssl.conf"),
|
||||
os.path.join(aug_pre, "ssl.conf/VirtualHost"),
|
||||
{obj.Addr.fromstring("_default_:443")},
|
||||
True, True, None)
|
||||
]
|
||||
return vh_truth
|
||||
|
||||
|
||||
class FedoraRestartTest(util.ApacheTest):
|
||||
"""Tests for Fedora specific self-signed certificate override"""
|
||||
|
||||
# TODO: eventually, these tests should have a dedicated configuration instead
|
||||
# of reusing the ones from centos_test
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
test_dir = "centos7_apache/apache"
|
||||
config_root = "centos7_apache/apache/httpd"
|
||||
vhost_root = "centos7_apache/apache/httpd/conf.d"
|
||||
super(FedoraRestartTest, self).setUp(test_dir=test_dir,
|
||||
config_root=config_root,
|
||||
vhost_root=vhost_root)
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.vhost_path, self.config_dir, self.work_dir,
|
||||
os_info="fedora")
|
||||
self.vh_truth = get_vh_truth(
|
||||
self.temp_dir, "centos7_apache/apache")
|
||||
|
||||
def _run_fedora_test(self):
|
||||
self.assertIsInstance(self.config, override_fedora.FedoraConfigurator)
|
||||
self.config.config_test()
|
||||
|
||||
def test_fedora_restart_error(self):
|
||||
c_test = "certbot_apache.configurator.ApacheConfigurator.config_test"
|
||||
with mock.patch(c_test) as mock_test:
|
||||
# First call raises error, second doesn't
|
||||
mock_test.side_effect = [errors.MisconfigurationError, '']
|
||||
with mock.patch("certbot.util.run_script") as mock_run:
|
||||
mock_run.side_effect = errors.SubprocessError
|
||||
self.assertRaises(errors.MisconfigurationError,
|
||||
self._run_fedora_test)
|
||||
|
||||
def test_fedora_restart(self):
|
||||
c_test = "certbot_apache.configurator.ApacheConfigurator.config_test"
|
||||
with mock.patch(c_test) as mock_test:
|
||||
with mock.patch("certbot.util.run_script") as mock_run:
|
||||
# First call raises error, second doesn't
|
||||
mock_test.side_effect = [errors.MisconfigurationError, '']
|
||||
self._run_fedora_test()
|
||||
self.assertEqual(mock_test.call_count, 2)
|
||||
self.assertEqual(mock_run.call_args[0][0],
|
||||
['systemctl', 'restart', 'httpd'])
|
||||
|
||||
|
||||
class MultipleVhostsTestFedora(util.ApacheTest):
|
||||
"""Multiple vhost tests for CentOS / RHEL family of distros"""
|
||||
|
||||
_multiprocess_can_split_ = True
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
test_dir = "centos7_apache/apache"
|
||||
config_root = "centos7_apache/apache/httpd"
|
||||
vhost_root = "centos7_apache/apache/httpd/conf.d"
|
||||
super(MultipleVhostsTestFedora, self).setUp(test_dir=test_dir,
|
||||
config_root=config_root,
|
||||
vhost_root=vhost_root)
|
||||
|
||||
self.config = util.get_apache_configurator(
|
||||
self.config_path, self.vhost_path, self.config_dir, self.work_dir,
|
||||
os_info="fedora")
|
||||
self.vh_truth = get_vh_truth(
|
||||
self.temp_dir, "centos7_apache/apache")
|
||||
|
||||
def test_get_parser(self):
|
||||
self.assertIsInstance(self.config.parser, override_fedora.FedoraParser)
|
||||
|
||||
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
|
||||
def test_opportunistic_httpd_runtime_parsing(self, mock_get):
|
||||
define_val = (
|
||||
'Define: TEST1\n'
|
||||
'Define: TEST2\n'
|
||||
'Define: DUMP_RUN_CFG\n'
|
||||
)
|
||||
mod_val = (
|
||||
'Loaded Modules:\n'
|
||||
' mock_module (static)\n'
|
||||
' another_module (static)\n'
|
||||
)
|
||||
def mock_get_cfg(command):
|
||||
"""Mock httpd process stdout"""
|
||||
if command == ['httpd', '-t', '-D', 'DUMP_RUN_CFG']:
|
||||
return define_val
|
||||
elif command == ['httpd', '-t', '-D', 'DUMP_MODULES']:
|
||||
return mod_val
|
||||
return ""
|
||||
mock_get.side_effect = mock_get_cfg
|
||||
self.config.parser.modules = set()
|
||||
self.config.parser.variables = {}
|
||||
|
||||
with mock.patch("certbot.util.get_os_info") as mock_osi:
|
||||
# Make sure we have the have the CentOS httpd constants
|
||||
mock_osi.return_value = ("fedora", "29")
|
||||
self.config.parser.update_runtime_variables()
|
||||
|
||||
self.assertEqual(mock_get.call_count, 3)
|
||||
self.assertEqual(len(self.config.parser.modules), 4)
|
||||
self.assertEqual(len(self.config.parser.variables), 2)
|
||||
self.assertTrue("TEST2" in self.config.parser.variables.keys())
|
||||
self.assertTrue("mod_another.c" in self.config.parser.modules)
|
||||
|
||||
@mock.patch("certbot_apache.configurator.util.run_script")
|
||||
def test_get_version(self, mock_run_script):
|
||||
mock_run_script.return_value = ('', None)
|
||||
self.assertRaises(errors.PluginError, self.config.get_version)
|
||||
self.assertEqual(mock_run_script.call_args[0][0][0], 'httpd')
|
||||
|
||||
def test_get_virtual_hosts(self):
|
||||
"""Make sure all vhosts are being properly found."""
|
||||
vhs = self.config.get_virtual_hosts()
|
||||
self.assertEqual(len(vhs), 2)
|
||||
found = 0
|
||||
|
||||
for vhost in vhs:
|
||||
for centos_truth in self.vh_truth:
|
||||
if vhost == centos_truth:
|
||||
found += 1
|
||||
break
|
||||
else:
|
||||
raise Exception("Missed: %s" % vhost) # pragma: no cover
|
||||
self.assertEqual(found, 2)
|
||||
|
||||
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
|
||||
def test_get_sysconfig_vars(self, mock_cfg):
|
||||
"""Make sure we read the sysconfig OPTIONS variable correctly"""
|
||||
# Return nothing for the process calls
|
||||
mock_cfg.return_value = ""
|
||||
self.config.parser.sysconfig_filep = os.path.realpath(
|
||||
os.path.join(self.config.parser.root, "../sysconfig/httpd"))
|
||||
self.config.parser.variables = {}
|
||||
|
||||
with mock.patch("certbot.util.get_os_info") as mock_osi:
|
||||
# Make sure we have the have the CentOS httpd constants
|
||||
mock_osi.return_value = ("fedora", "29")
|
||||
self.config.parser.update_runtime_variables()
|
||||
|
||||
self.assertTrue("mock_define" in self.config.parser.variables.keys())
|
||||
self.assertTrue("mock_define_too" in self.config.parser.variables.keys())
|
||||
self.assertTrue("mock_value" in self.config.parser.variables.keys())
|
||||
self.assertEqual("TRUE", self.config.parser.variables["mock_value"])
|
||||
self.assertTrue("MOCK_NOSEP" in self.config.parser.variables.keys())
|
||||
self.assertEqual("NOSEP_VAL", self.config.parser.variables["NOSEP_TWO"])
|
||||
|
||||
@mock.patch("certbot_apache.configurator.util.run_script")
|
||||
def test_alt_restart_works(self, mock_run_script):
|
||||
mock_run_script.side_effect = [None, errors.SubprocessError, None]
|
||||
self.config.restart()
|
||||
self.assertEqual(mock_run_script.call_count, 3)
|
||||
|
||||
@mock.patch("certbot_apache.configurator.util.run_script")
|
||||
def test_alt_restart_errors(self, mock_run_script):
|
||||
mock_run_script.side_effect = [None,
|
||||
errors.SubprocessError,
|
||||
errors.SubprocessError]
|
||||
self.assertRaises(errors.MisconfigurationError, self.config.restart)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main() # pragma: no cover
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
|
|||
import sys
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'mock',
|
||||
'python-augeas',
|
||||
'setuptools',
|
||||
|
|
|
|||
146
certbot-auto
146
certbot-auto
|
|
@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
|
|||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="0.33.1"
|
||||
LE_AUTO_VERSION="0.34.0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -45,6 +45,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
-h, --help print this help
|
||||
-n, --non-interactive, --noninteractive run without asking for user input
|
||||
--no-bootstrap do not install OS dependencies
|
||||
--no-permissions-check do not warn about file system permissions
|
||||
--no-self-upgrade do not download updates
|
||||
--os-packages-only install OS dependencies and exit
|
||||
--install-only install certbot, upgrade if needed, and exit
|
||||
|
|
@ -67,6 +68,8 @@ for arg in "$@" ; do
|
|||
# Do not upgrade this script (also prevents client upgrades, because each
|
||||
# copy of the script pins a hash of the python client)
|
||||
NO_SELF_UPGRADE=1;;
|
||||
--no-permissions-check)
|
||||
NO_PERMISSIONS_CHECK=1;;
|
||||
--no-bootstrap)
|
||||
NO_BOOTSTRAP=1;;
|
||||
--help)
|
||||
|
|
@ -172,7 +175,11 @@ SetRootAuthMechanism() {
|
|||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
'')
|
||||
# If we're not running with root, don't check that this script can only
|
||||
# be modified by system users and groups.
|
||||
NO_PERMISSIONS_CHECK=1
|
||||
;;
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
|
|
@ -534,7 +541,7 @@ BootstrapSuseCommon() {
|
|||
# Since Leap 15.0 (and associated Tumbleweed version), python-virtualenv
|
||||
# is a source package, and python2-virtualenv must be used instead.
|
||||
# Also currently python2-setuptools is not a dependency of python2-virtualenv,
|
||||
# while it should be. Installing it explicitly until upstreqm fix.
|
||||
# while it should be. Installing it explicitly until upstream fix.
|
||||
OPENSUSE_VIRTUALENV_PACKAGES="python2-virtualenv python2-setuptools"
|
||||
fi
|
||||
|
||||
|
|
@ -1138,9 +1145,9 @@ requests-toolbelt==0.9.1 \
|
|||
six==1.12.0 \
|
||||
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
|
||||
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
|
||||
urllib3==1.24.1 \
|
||||
--hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \
|
||||
--hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22
|
||||
urllib3==1.24.2 \
|
||||
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
|
||||
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
|
||||
zope.component==4.5 \
|
||||
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
|
||||
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
|
||||
|
|
@ -1218,18 +1225,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.33.1 \
|
||||
--hash=sha256:e2a08467146b7a7ed2c8ca6625b1705d93b51e89866f6ede8a8a262594c18f3f \
|
||||
--hash=sha256:d5203f32c50f3ec5a32df97e4affddbcd288a569678ecb5669adda21cd5ac3d9
|
||||
acme==0.33.1 \
|
||||
--hash=sha256:02467d4b1d246105d6d1ea01822dd9e2eea5bf3a50607523969d8e400d53c07b \
|
||||
--hash=sha256:b38cdb71d0071efe1f1190a744f8f95f3c698b76ac0f5d919bbfe3522e277a82
|
||||
certbot-apache==0.33.1 \
|
||||
--hash=sha256:0d2a463539e6396de2d374de62faba34e1fe40dd8059e3c64dcd5dabaa66887b \
|
||||
--hash=sha256:659db7335d919fee52ae707567994e13c31ed25109c94b246c60c97d21c46f3a
|
||||
certbot-nginx==0.33.1 \
|
||||
--hash=sha256:df9fb86e735eb2668e070f20317e85c37952f3f612fa7f6bbc2c63784b213f28 \
|
||||
--hash=sha256:b3201eee03be74fc743c21c721d3b5586c3323db63e78b68583a6250ad680cff
|
||||
certbot==0.34.0 \
|
||||
--hash=sha256:51dddf2cb1c50a9f8b993090890bf4858d8fadffce38bafcdf6bf585a2040317 \
|
||||
--hash=sha256:e75bdabfd9183bd9842ada42a51070f120d15982e81c490df59dde62e4df2c8b
|
||||
acme==0.34.0 \
|
||||
--hash=sha256:3448024d2c274aebfb9b31b53862576d167626ce2fd1997a78d450c32a292fa3 \
|
||||
--hash=sha256:92478e58f541c5c7c527427a50650005cdede799b78f0a0a65b8093d6368bcfd
|
||||
certbot-apache==0.34.0 \
|
||||
--hash=sha256:79e686f25b63dac17d771d71f791f252774da22125f3f6e0665f4cf791d516fe \
|
||||
--hash=sha256:d5ae09b4801fbac23d5acf64a5ee265108199d2852fbe743e7b6ab06fa08edf6
|
||||
certbot-nginx==0.34.0 \
|
||||
--hash=sha256:868d7dcb59bb2548cb4a2ae187db5da1bfe33aac306b1b844b96ee00a39cac52 \
|
||||
--hash=sha256:d6c728b85c523711ec0dc800f8d4ebbef192fb0ca1ec7914c173207e4aba5194
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -1494,6 +1501,108 @@ else
|
|||
exit 0
|
||||
fi
|
||||
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
# Don't warn about file permissions if the user disabled the check or we
|
||||
# can't find an up-to-date Python.
|
||||
if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
|
||||
# ---------------------------------------------------------------------------
|
||||
cat << "UNLIKELY_EOF" > "$TEMP_DIR/check_permissions.py"
|
||||
"""Verifies certbot-auto cannot be modified by unprivileged users.
|
||||
|
||||
This script takes the path to certbot-auto as its only command line
|
||||
argument. It then checks that the file can only be modified by uid/gid
|
||||
< 1000 and if other users can modify the file, it prints a warning with
|
||||
a suggestion on how to solve the problem.
|
||||
|
||||
Permissions on symlinks in the absolute path of certbot-auto are ignored
|
||||
and only the canonical path to certbot-auto is checked. There could be
|
||||
permissions problems due to the symlinks that are unreported by this
|
||||
script, however, issues like this were not caused by our documentation
|
||||
and are ignored for the sake of simplicity.
|
||||
|
||||
All warnings are printed to stdout rather than stderr so all stderr
|
||||
output from this script can be suppressed to avoid printing messages if
|
||||
this script fails for some reason.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
|
||||
FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
|
||||
|
||||
|
||||
def has_safe_permissions(path):
|
||||
"""Returns True if the given path has secure permissions.
|
||||
|
||||
The permissions are considered safe if the file is only writable by
|
||||
uid/gid < 1000.
|
||||
|
||||
The reason we allow more IDs than 0 is because on some systems such
|
||||
as Debian, system users/groups other than uid/gid 0 are used for the
|
||||
path we recommend in our instructions which is /usr/local/bin. 1000
|
||||
was chosen because on Debian 0-999 is reserved for system IDs[1] and
|
||||
on RHEL either 0-499 or 0-999 is reserved depending on the
|
||||
version[2][3]. Due to these differences across different OSes, this
|
||||
detection isn't perfect so we only determine permissions are
|
||||
insecure when we can be reasonably confident there is a problem
|
||||
regardless of the underlying OS.
|
||||
|
||||
[1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
|
||||
[2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
|
||||
[3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
|
||||
|
||||
:param str path: filesystem path to check
|
||||
:returns: True if the path has secure permissions, otherwise, False
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
# os.stat follows symlinks before obtaining information about a file.
|
||||
stat_result = os.stat(path)
|
||||
if stat_result.st_mode & stat.S_IWOTH:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWGRP and stat_result.st_gid >= 1000:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWUSR and stat_result.st_uid >= 1000:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main(certbot_auto_path):
|
||||
current_path = os.path.realpath(certbot_auto_path)
|
||||
last_path = None
|
||||
permissions_ok = True
|
||||
# This loop makes use of the fact that os.path.dirname('/') == '/'.
|
||||
while current_path != last_path and permissions_ok:
|
||||
permissions_ok = has_safe_permissions(current_path)
|
||||
last_path = current_path
|
||||
current_path = os.path.dirname(current_path)
|
||||
|
||||
if not permissions_ok:
|
||||
print('{0} has insecure permissions!'.format(certbot_auto_path))
|
||||
print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1])
|
||||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
# If the script fails for some reason, don't break certbot-auto.
|
||||
set +e
|
||||
# Suppress unexpected error output and only print the script's output if it
|
||||
# ran successfully.
|
||||
CHECK_PERM_OUT=$("$LE_PYTHON" "$TEMP_DIR/check_permissions.py" "$0" 2>/dev/null)
|
||||
CHECK_PERM_STATUS="$?"
|
||||
set -e
|
||||
if [ "$CHECK_PERM_STATUS" = 0 ]; then
|
||||
error "$CHECK_PERM_OUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SELF_UPGRADE" != 1 ]; then
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -1650,7 +1759,6 @@ if __name__ == '__main__':
|
|||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
if [ "$PYVER" -lt "$MIN_PYVER" ]; then
|
||||
error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
|
||||
elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'certbot',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'cloudflare>=1.5.1',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'mock',
|
||||
'python-digitalocean>=1.11',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -1,20 +1,32 @@
|
|||
import os
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'certbot>=0.34.0',
|
||||
'mock',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
# This package normally depends on dns-lexicon>=3.2.1 to address the
|
||||
# problem described in https://github.com/AnalogJ/lexicon/issues/387,
|
||||
# however, the fix there has been backported to older versions of
|
||||
# lexicon found in various Linux distros. This conditional helps us test
|
||||
# that we've maintained compatibility with these versions of lexicon
|
||||
# which allows us to potentially upgrade our packages in these distros
|
||||
# as necessary.
|
||||
if os.environ.get('CERTBOT_OLDEST') == '1':
|
||||
install_requires.append('dns-lexicon>=2.2.1')
|
||||
else:
|
||||
install_requires.append('dns-lexicon>=3.2.1')
|
||||
|
||||
docs_extras = [
|
||||
'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags
|
||||
'sphinx_rtd_theme',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.1.22',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
# 1.5 is the first version that supports oauth2client>=2.0
|
||||
'google-api-python-client>=1.5',
|
||||
'mock',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
dns-lexicon==2.2.3
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.2.3',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
dns-lexicon==2.7.14
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class Authenticator(dns_common.DNSAuthenticator):
|
|||
def _validate_algorithm(self, credentials):
|
||||
algorithm = credentials.conf('algorithm')
|
||||
if algorithm:
|
||||
if not self.ALGORITHMS.get(algorithm):
|
||||
if not self.ALGORITHMS.get(algorithm.upper()):
|
||||
raise errors.PluginError("Unknown algorithm: {0}.".format(algorithm))
|
||||
|
||||
def _setup_credentials(self):
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthentic
|
|||
|
||||
def test_valid_algorithm_passes(self):
|
||||
config = VALID_CONFIG.copy()
|
||||
config["rfc2136_algorithm"] = "HMAC-SHA512"
|
||||
config["rfc2136_algorithm"] = "HMAC-sha512"
|
||||
dns_test_common.write(config, self.config.rfc2136_credentials)
|
||||
|
||||
self.auth.perform([self.achall])
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dnspython',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'boto3',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'dns-lexicon>=2.1.23',
|
||||
'mock',
|
||||
'setuptools',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.34.0
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
|
|||
import sys
|
||||
|
||||
|
||||
version = '0.34.0.dev0'
|
||||
version = '0.35.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0.dev0',
|
||||
'certbot>=0.34.0',
|
||||
'mock',
|
||||
'PyOpenSSL',
|
||||
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Certbot client."""
|
||||
|
||||
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
|
||||
__version__ = '0.34.0.dev0'
|
||||
__version__ = '0.35.0.dev0'
|
||||
|
|
|
|||
|
|
@ -1089,6 +1089,11 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
help="(certbot-auto only) prevent the certbot-auto script from"
|
||||
" installing OS-level dependencies (default: Prompt to install "
|
||||
" OS-wide dependencies, but exit if the user says 'No')")
|
||||
helpful.add(
|
||||
"automation", "--no-permissions-check", action="store_true",
|
||||
default=flag_default("no_permissions_check"),
|
||||
help="(certbot-auto only) skip the check on the file system"
|
||||
" permissions of the certbot-auto script")
|
||||
helpful.add(
|
||||
["automation", "renew", "certonly", "run"],
|
||||
"-q", "--quiet", dest="quiet", action="store_true",
|
||||
|
|
|
|||
|
|
@ -549,6 +549,11 @@ class Client(object):
|
|||
if ask_redirect:
|
||||
if config_name == "redirect" and config_value is None:
|
||||
config_value = enhancements.ask(enhancement_name)
|
||||
if not config_value:
|
||||
logger.warning("Future versions of Certbot will automatically "
|
||||
"configure the webserver so that all requests redirect to secure "
|
||||
"HTTPS access. You can control this behavior and disable this "
|
||||
"warning with the --redirect and --no-redirect flags.")
|
||||
if config_value:
|
||||
self.apply_enhancement(domains, enhancement_name, option)
|
||||
enhanced = True
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ CLI_DEFAULTS = dict(
|
|||
duplicate=False,
|
||||
os_packages_only=False,
|
||||
no_self_upgrade=False,
|
||||
no_permissions_check=False,
|
||||
no_bootstrap=False,
|
||||
quiet=False,
|
||||
staging=False,
|
||||
|
|
|
|||
|
|
@ -453,6 +453,10 @@ class ParseTest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
for topic in ['all', 'plugins', 'dns-route53']:
|
||||
self.assertFalse('certbot-route53:auth' in self._help_output([help_flag, topic]))
|
||||
|
||||
def test_no_permissions_check_accepted(self):
|
||||
namespace = self.parse(["--no-permissions-check"])
|
||||
self.assertTrue(namespace.no_permissions_check)
|
||||
|
||||
|
||||
class DefaultTest(unittest.TestCase):
|
||||
"""Tests for certbot.cli._Default."""
|
||||
|
|
|
|||
|
|
@ -564,6 +564,21 @@ class EnhanceConfigTest(ClientTestCommon):
|
|||
self.assertEqual(mock_log.warning.call_args[0][1],
|
||||
'redirect')
|
||||
|
||||
@mock.patch("certbot.client.logger")
|
||||
def test_config_set_no_warning_redirect(self, mock_log):
|
||||
self.config.redirect = False
|
||||
self._test_with_already_existing()
|
||||
self.assertFalse(mock_log.warning.called)
|
||||
|
||||
@mock.patch("certbot.client.enhancements.ask")
|
||||
@mock.patch("certbot.client.logger")
|
||||
def test_warn_redirect(self, mock_log, mock_ask):
|
||||
self.config.redirect = None
|
||||
mock_ask.return_value = False
|
||||
self._test_with_already_existing()
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
self.assertTrue("disable" in mock_log.warning.call_args[0][0])
|
||||
|
||||
def test_no_ask_hsts(self):
|
||||
self.config.hsts = True
|
||||
self._test_with_all_supported()
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ def get_os_info(filepath="/etc/os-release"):
|
|||
# Systemd os-release parsing might be viable
|
||||
os_name, os_version = get_systemd_os_info(filepath=filepath)
|
||||
if os_name:
|
||||
return (os_name, os_version)
|
||||
return os_name, os_version
|
||||
|
||||
# Fallback to platform module
|
||||
return get_python_os_info()
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ https://weakdh.org/sysadmin.html
|
|||
These lists may have been derived from Mozilla's recommendations.
|
||||
One of the authors clarified his view of the priorities for various changes as a result of the research at
|
||||
|
||||
https://www.ietf.org/mail-archive/web/tls/current/msg16496.html
|
||||
https://web.archive.org/web/20150526022820/https://www.ietf.org/mail-archive/web/tls/current/msg16496.html
|
||||
|
||||
In particular, he supports ECDHE and also supports the use of the standardized groups in the FF-DHE Internet-Draft mentioned above (which isn't clear from the group's original recommendations).
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ optional arguments:
|
|||
case, and to know when to deprecate support for past
|
||||
Python versions and flags. If you wish to hide this
|
||||
information from the Let's Encrypt server, set this to
|
||||
"". (default: CertbotACMEClient/0.33.1
|
||||
"". (default: CertbotACMEClient/0.34.0
|
||||
(certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX
|
||||
Installer/YYY (SUBCOMMAND; flags: FLAGS)
|
||||
Py/major.minor.patchlevel). The flags encoded in the
|
||||
|
|
@ -171,6 +171,10 @@ automation:
|
|||
from installing OS-level dependencies (default: Prompt
|
||||
to install OS-wide dependencies, but exit if the user
|
||||
says 'No')
|
||||
--no-permissions-check
|
||||
(certbot-auto only) skip the check on the file system
|
||||
permissions of the certbot-auto script (default:
|
||||
False)
|
||||
-q, --quiet Silence all output except errors. Useful for
|
||||
automation via cron. Implies --non-interactive.
|
||||
(default: False)
|
||||
|
|
|
|||
146
letsencrypt-auto
146
letsencrypt-auto
|
|
@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
|
|||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="0.33.1"
|
||||
LE_AUTO_VERSION="0.34.0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -45,6 +45,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
-h, --help print this help
|
||||
-n, --non-interactive, --noninteractive run without asking for user input
|
||||
--no-bootstrap do not install OS dependencies
|
||||
--no-permissions-check do not warn about file system permissions
|
||||
--no-self-upgrade do not download updates
|
||||
--os-packages-only install OS dependencies and exit
|
||||
--install-only install certbot, upgrade if needed, and exit
|
||||
|
|
@ -67,6 +68,8 @@ for arg in "$@" ; do
|
|||
# Do not upgrade this script (also prevents client upgrades, because each
|
||||
# copy of the script pins a hash of the python client)
|
||||
NO_SELF_UPGRADE=1;;
|
||||
--no-permissions-check)
|
||||
NO_PERMISSIONS_CHECK=1;;
|
||||
--no-bootstrap)
|
||||
NO_BOOTSTRAP=1;;
|
||||
--help)
|
||||
|
|
@ -172,7 +175,11 @@ SetRootAuthMechanism() {
|
|||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
'')
|
||||
# If we're not running with root, don't check that this script can only
|
||||
# be modified by system users and groups.
|
||||
NO_PERMISSIONS_CHECK=1
|
||||
;;
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
|
|
@ -534,7 +541,7 @@ BootstrapSuseCommon() {
|
|||
# Since Leap 15.0 (and associated Tumbleweed version), python-virtualenv
|
||||
# is a source package, and python2-virtualenv must be used instead.
|
||||
# Also currently python2-setuptools is not a dependency of python2-virtualenv,
|
||||
# while it should be. Installing it explicitly until upstreqm fix.
|
||||
# while it should be. Installing it explicitly until upstream fix.
|
||||
OPENSUSE_VIRTUALENV_PACKAGES="python2-virtualenv python2-setuptools"
|
||||
fi
|
||||
|
||||
|
|
@ -1138,9 +1145,9 @@ requests-toolbelt==0.9.1 \
|
|||
six==1.12.0 \
|
||||
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
|
||||
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
|
||||
urllib3==1.24.1 \
|
||||
--hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \
|
||||
--hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22
|
||||
urllib3==1.24.2 \
|
||||
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
|
||||
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
|
||||
zope.component==4.5 \
|
||||
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
|
||||
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
|
||||
|
|
@ -1218,18 +1225,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.33.1 \
|
||||
--hash=sha256:e2a08467146b7a7ed2c8ca6625b1705d93b51e89866f6ede8a8a262594c18f3f \
|
||||
--hash=sha256:d5203f32c50f3ec5a32df97e4affddbcd288a569678ecb5669adda21cd5ac3d9
|
||||
acme==0.33.1 \
|
||||
--hash=sha256:02467d4b1d246105d6d1ea01822dd9e2eea5bf3a50607523969d8e400d53c07b \
|
||||
--hash=sha256:b38cdb71d0071efe1f1190a744f8f95f3c698b76ac0f5d919bbfe3522e277a82
|
||||
certbot-apache==0.33.1 \
|
||||
--hash=sha256:0d2a463539e6396de2d374de62faba34e1fe40dd8059e3c64dcd5dabaa66887b \
|
||||
--hash=sha256:659db7335d919fee52ae707567994e13c31ed25109c94b246c60c97d21c46f3a
|
||||
certbot-nginx==0.33.1 \
|
||||
--hash=sha256:df9fb86e735eb2668e070f20317e85c37952f3f612fa7f6bbc2c63784b213f28 \
|
||||
--hash=sha256:b3201eee03be74fc743c21c721d3b5586c3323db63e78b68583a6250ad680cff
|
||||
certbot==0.34.0 \
|
||||
--hash=sha256:51dddf2cb1c50a9f8b993090890bf4858d8fadffce38bafcdf6bf585a2040317 \
|
||||
--hash=sha256:e75bdabfd9183bd9842ada42a51070f120d15982e81c490df59dde62e4df2c8b
|
||||
acme==0.34.0 \
|
||||
--hash=sha256:3448024d2c274aebfb9b31b53862576d167626ce2fd1997a78d450c32a292fa3 \
|
||||
--hash=sha256:92478e58f541c5c7c527427a50650005cdede799b78f0a0a65b8093d6368bcfd
|
||||
certbot-apache==0.34.0 \
|
||||
--hash=sha256:79e686f25b63dac17d771d71f791f252774da22125f3f6e0665f4cf791d516fe \
|
||||
--hash=sha256:d5ae09b4801fbac23d5acf64a5ee265108199d2852fbe743e7b6ab06fa08edf6
|
||||
certbot-nginx==0.34.0 \
|
||||
--hash=sha256:868d7dcb59bb2548cb4a2ae187db5da1bfe33aac306b1b844b96ee00a39cac52 \
|
||||
--hash=sha256:d6c728b85c523711ec0dc800f8d4ebbef192fb0ca1ec7914c173207e4aba5194
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -1494,6 +1501,108 @@ else
|
|||
exit 0
|
||||
fi
|
||||
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
# Don't warn about file permissions if the user disabled the check or we
|
||||
# can't find an up-to-date Python.
|
||||
if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
|
||||
# ---------------------------------------------------------------------------
|
||||
cat << "UNLIKELY_EOF" > "$TEMP_DIR/check_permissions.py"
|
||||
"""Verifies certbot-auto cannot be modified by unprivileged users.
|
||||
|
||||
This script takes the path to certbot-auto as its only command line
|
||||
argument. It then checks that the file can only be modified by uid/gid
|
||||
< 1000 and if other users can modify the file, it prints a warning with
|
||||
a suggestion on how to solve the problem.
|
||||
|
||||
Permissions on symlinks in the absolute path of certbot-auto are ignored
|
||||
and only the canonical path to certbot-auto is checked. There could be
|
||||
permissions problems due to the symlinks that are unreported by this
|
||||
script, however, issues like this were not caused by our documentation
|
||||
and are ignored for the sake of simplicity.
|
||||
|
||||
All warnings are printed to stdout rather than stderr so all stderr
|
||||
output from this script can be suppressed to avoid printing messages if
|
||||
this script fails for some reason.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
|
||||
FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
|
||||
|
||||
|
||||
def has_safe_permissions(path):
|
||||
"""Returns True if the given path has secure permissions.
|
||||
|
||||
The permissions are considered safe if the file is only writable by
|
||||
uid/gid < 1000.
|
||||
|
||||
The reason we allow more IDs than 0 is because on some systems such
|
||||
as Debian, system users/groups other than uid/gid 0 are used for the
|
||||
path we recommend in our instructions which is /usr/local/bin. 1000
|
||||
was chosen because on Debian 0-999 is reserved for system IDs[1] and
|
||||
on RHEL either 0-499 or 0-999 is reserved depending on the
|
||||
version[2][3]. Due to these differences across different OSes, this
|
||||
detection isn't perfect so we only determine permissions are
|
||||
insecure when we can be reasonably confident there is a problem
|
||||
regardless of the underlying OS.
|
||||
|
||||
[1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
|
||||
[2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
|
||||
[3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
|
||||
|
||||
:param str path: filesystem path to check
|
||||
:returns: True if the path has secure permissions, otherwise, False
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
# os.stat follows symlinks before obtaining information about a file.
|
||||
stat_result = os.stat(path)
|
||||
if stat_result.st_mode & stat.S_IWOTH:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWGRP and stat_result.st_gid >= 1000:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWUSR and stat_result.st_uid >= 1000:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main(certbot_auto_path):
|
||||
current_path = os.path.realpath(certbot_auto_path)
|
||||
last_path = None
|
||||
permissions_ok = True
|
||||
# This loop makes use of the fact that os.path.dirname('/') == '/'.
|
||||
while current_path != last_path and permissions_ok:
|
||||
permissions_ok = has_safe_permissions(current_path)
|
||||
last_path = current_path
|
||||
current_path = os.path.dirname(current_path)
|
||||
|
||||
if not permissions_ok:
|
||||
print('{0} has insecure permissions!'.format(certbot_auto_path))
|
||||
print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1])
|
||||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
# If the script fails for some reason, don't break certbot-auto.
|
||||
set +e
|
||||
# Suppress unexpected error output and only print the script's output if it
|
||||
# ran successfully.
|
||||
CHECK_PERM_OUT=$("$LE_PYTHON" "$TEMP_DIR/check_permissions.py" "$0" 2>/dev/null)
|
||||
CHECK_PERM_STATUS="$?"
|
||||
set -e
|
||||
if [ "$CHECK_PERM_STATUS" = 0 ]; then
|
||||
error "$CHECK_PERM_OUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SELF_UPGRADE" != 1 ]; then
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -1650,7 +1759,6 @@ if __name__ == '__main__':
|
|||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
if [ "$PYVER" -lt "$MIN_PYVER" ]; then
|
||||
error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
|
||||
elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlymhBYACgkQTRfJlc2X
|
||||
dfKmDAf/bkoGkWpxgzKjfd7BELnvhZduQ5Y30P2+Kq43jnop56zjZrt53tRsKeOc
|
||||
Rat2Rq3e/rozlo5ie939iF2UPIX8fzEQ/IIyk4Om17dJ9ld25hteX7HWJThUX9+t
|
||||
OtKA0c7jw7nSrCmWjKtGhZoTe2nsMqAtp0LV7kZ7T7Ex0HAxjrYu48wA2h6lgloe
|
||||
65rXyBDVHdVc3FvevUiHKYkt+SONyWuRZpeQ8xn6YSQNDwYzCub3ro1h55GYfOK2
|
||||
65eklH1xVo7TvvR0Wo7l1/hIiK8Gz6ZX5dqDaxHT817zO1cqB4HhkHAl2O3q7TCo
|
||||
JIo1jxMzlttRGJaegwnMTi20KyimyA==
|
||||
=8Gjd
|
||||
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlzKCkUACgkQTRfJlc2X
|
||||
dfL8xwf/Sjxb5LWkbvVem9Mc8w76D4DKECQdUdwJJCPrvgkBy2LAXYmpy4ZEBETV
|
||||
p+QuUk2EuUxBNc81Wdo3PNdoA3eDd8uaxMc/GPCRxSWNH/taqL0Xk7s6Jqhx6rh+
|
||||
tQNnJoTmqgWaUwQkfJXiiwlcvIdFjdOoQgZnP3YJaNVrlIi6rd4mDJ1dU7ik2Qvz
|
||||
pI78mCfHokhvq1tWUFram12z045n4/lZ9uy/auA2VFnAmUvh/18h1VSTEoWJK2vW
|
||||
Xuxv59G1vtG+cC4jzenMho0oVt18hdqQPOaUstzPhS9XxFuyvYMurHusZ4fysnbQ
|
||||
cUofX1hY0jmaGkMHBkfjtJfdbOQXUg==
|
||||
=jqpL
|
||||
-----END PGP SIGNATURE-----
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
|
|||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="0.34.0.dev0"
|
||||
LE_AUTO_VERSION="0.35.0.dev0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -45,6 +45,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
-h, --help print this help
|
||||
-n, --non-interactive, --noninteractive run without asking for user input
|
||||
--no-bootstrap do not install OS dependencies
|
||||
--no-permissions-check do not warn about file system permissions
|
||||
--no-self-upgrade do not download updates
|
||||
--os-packages-only install OS dependencies and exit
|
||||
--install-only install certbot, upgrade if needed, and exit
|
||||
|
|
@ -67,6 +68,8 @@ for arg in "$@" ; do
|
|||
# Do not upgrade this script (also prevents client upgrades, because each
|
||||
# copy of the script pins a hash of the python client)
|
||||
NO_SELF_UPGRADE=1;;
|
||||
--no-permissions-check)
|
||||
NO_PERMISSIONS_CHECK=1;;
|
||||
--no-bootstrap)
|
||||
NO_BOOTSTRAP=1;;
|
||||
--help)
|
||||
|
|
@ -172,7 +175,11 @@ SetRootAuthMechanism() {
|
|||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
'')
|
||||
# If we're not running with root, don't check that this script can only
|
||||
# be modified by system users and groups.
|
||||
NO_PERMISSIONS_CHECK=1
|
||||
;;
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
|
|
@ -1218,18 +1225,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.33.1 \
|
||||
--hash=sha256:e2a08467146b7a7ed2c8ca6625b1705d93b51e89866f6ede8a8a262594c18f3f \
|
||||
--hash=sha256:d5203f32c50f3ec5a32df97e4affddbcd288a569678ecb5669adda21cd5ac3d9
|
||||
acme==0.33.1 \
|
||||
--hash=sha256:02467d4b1d246105d6d1ea01822dd9e2eea5bf3a50607523969d8e400d53c07b \
|
||||
--hash=sha256:b38cdb71d0071efe1f1190a744f8f95f3c698b76ac0f5d919bbfe3522e277a82
|
||||
certbot-apache==0.33.1 \
|
||||
--hash=sha256:0d2a463539e6396de2d374de62faba34e1fe40dd8059e3c64dcd5dabaa66887b \
|
||||
--hash=sha256:659db7335d919fee52ae707567994e13c31ed25109c94b246c60c97d21c46f3a
|
||||
certbot-nginx==0.33.1 \
|
||||
--hash=sha256:df9fb86e735eb2668e070f20317e85c37952f3f612fa7f6bbc2c63784b213f28 \
|
||||
--hash=sha256:b3201eee03be74fc743c21c721d3b5586c3323db63e78b68583a6250ad680cff
|
||||
certbot==0.34.0 \
|
||||
--hash=sha256:51dddf2cb1c50a9f8b993090890bf4858d8fadffce38bafcdf6bf585a2040317 \
|
||||
--hash=sha256:e75bdabfd9183bd9842ada42a51070f120d15982e81c490df59dde62e4df2c8b
|
||||
acme==0.34.0 \
|
||||
--hash=sha256:3448024d2c274aebfb9b31b53862576d167626ce2fd1997a78d450c32a292fa3 \
|
||||
--hash=sha256:92478e58f541c5c7c527427a50650005cdede799b78f0a0a65b8093d6368bcfd
|
||||
certbot-apache==0.34.0 \
|
||||
--hash=sha256:79e686f25b63dac17d771d71f791f252774da22125f3f6e0665f4cf791d516fe \
|
||||
--hash=sha256:d5ae09b4801fbac23d5acf64a5ee265108199d2852fbe743e7b6ab06fa08edf6
|
||||
certbot-nginx==0.34.0 \
|
||||
--hash=sha256:868d7dcb59bb2548cb4a2ae187db5da1bfe33aac306b1b844b96ee00a39cac52 \
|
||||
--hash=sha256:d6c728b85c523711ec0dc800f8d4ebbef192fb0ca1ec7914c173207e4aba5194
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -1494,6 +1501,108 @@ else
|
|||
exit 0
|
||||
fi
|
||||
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
# Don't warn about file permissions if the user disabled the check or we
|
||||
# can't find an up-to-date Python.
|
||||
if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
|
||||
# ---------------------------------------------------------------------------
|
||||
cat << "UNLIKELY_EOF" > "$TEMP_DIR/check_permissions.py"
|
||||
"""Verifies certbot-auto cannot be modified by unprivileged users.
|
||||
|
||||
This script takes the path to certbot-auto as its only command line
|
||||
argument. It then checks that the file can only be modified by uid/gid
|
||||
< 1000 and if other users can modify the file, it prints a warning with
|
||||
a suggestion on how to solve the problem.
|
||||
|
||||
Permissions on symlinks in the absolute path of certbot-auto are ignored
|
||||
and only the canonical path to certbot-auto is checked. There could be
|
||||
permissions problems due to the symlinks that are unreported by this
|
||||
script, however, issues like this were not caused by our documentation
|
||||
and are ignored for the sake of simplicity.
|
||||
|
||||
All warnings are printed to stdout rather than stderr so all stderr
|
||||
output from this script can be suppressed to avoid printing messages if
|
||||
this script fails for some reason.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
|
||||
FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
|
||||
|
||||
|
||||
def has_safe_permissions(path):
|
||||
"""Returns True if the given path has secure permissions.
|
||||
|
||||
The permissions are considered safe if the file is only writable by
|
||||
uid/gid < 1000.
|
||||
|
||||
The reason we allow more IDs than 0 is because on some systems such
|
||||
as Debian, system users/groups other than uid/gid 0 are used for the
|
||||
path we recommend in our instructions which is /usr/local/bin. 1000
|
||||
was chosen because on Debian 0-999 is reserved for system IDs[1] and
|
||||
on RHEL either 0-499 or 0-999 is reserved depending on the
|
||||
version[2][3]. Due to these differences across different OSes, this
|
||||
detection isn't perfect so we only determine permissions are
|
||||
insecure when we can be reasonably confident there is a problem
|
||||
regardless of the underlying OS.
|
||||
|
||||
[1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
|
||||
[2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
|
||||
[3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
|
||||
|
||||
:param str path: filesystem path to check
|
||||
:returns: True if the path has secure permissions, otherwise, False
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
# os.stat follows symlinks before obtaining information about a file.
|
||||
stat_result = os.stat(path)
|
||||
if stat_result.st_mode & stat.S_IWOTH:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWGRP and stat_result.st_gid >= 1000:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWUSR and stat_result.st_uid >= 1000:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main(certbot_auto_path):
|
||||
current_path = os.path.realpath(certbot_auto_path)
|
||||
last_path = None
|
||||
permissions_ok = True
|
||||
# This loop makes use of the fact that os.path.dirname('/') == '/'.
|
||||
while current_path != last_path and permissions_ok:
|
||||
permissions_ok = has_safe_permissions(current_path)
|
||||
last_path = current_path
|
||||
current_path = os.path.dirname(current_path)
|
||||
|
||||
if not permissions_ok:
|
||||
print('{0} has insecure permissions!'.format(certbot_auto_path))
|
||||
print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1])
|
||||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
# If the script fails for some reason, don't break certbot-auto.
|
||||
set +e
|
||||
# Suppress unexpected error output and only print the script's output if it
|
||||
# ran successfully.
|
||||
CHECK_PERM_OUT=$("$LE_PYTHON" "$TEMP_DIR/check_permissions.py" "$0" 2>/dev/null)
|
||||
CHECK_PERM_STATUS="$?"
|
||||
set -e
|
||||
if [ "$CHECK_PERM_STATUS" = 0 ]; then
|
||||
error "$CHECK_PERM_OUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SELF_UPGRADE" != 1 ]; then
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -1650,7 +1759,6 @@ if __name__ == '__main__':
|
|||
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
if [ "$PYVER" -lt "$MIN_PYVER" ]; then
|
||||
error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
|
||||
elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -45,6 +45,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
-h, --help print this help
|
||||
-n, --non-interactive, --noninteractive run without asking for user input
|
||||
--no-bootstrap do not install OS dependencies
|
||||
--no-permissions-check do not warn about file system permissions
|
||||
--no-self-upgrade do not download updates
|
||||
--os-packages-only install OS dependencies and exit
|
||||
--install-only install certbot, upgrade if needed, and exit
|
||||
|
|
@ -67,6 +68,8 @@ for arg in "$@" ; do
|
|||
# Do not upgrade this script (also prevents client upgrades, because each
|
||||
# copy of the script pins a hash of the python client)
|
||||
NO_SELF_UPGRADE=1;;
|
||||
--no-permissions-check)
|
||||
NO_PERMISSIONS_CHECK=1;;
|
||||
--no-bootstrap)
|
||||
NO_BOOTSTRAP=1;;
|
||||
--help)
|
||||
|
|
@ -172,7 +175,11 @@ SetRootAuthMechanism() {
|
|||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
'')
|
||||
# If we're not running with root, don't check that this script can only
|
||||
# be modified by system users and groups.
|
||||
NO_PERMISSIONS_CHECK=1
|
||||
;;
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
|
|
@ -652,6 +659,27 @@ else
|
|||
exit 0
|
||||
fi
|
||||
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
# Don't warn about file permissions if the user disabled the check or we
|
||||
# can't find an up-to-date Python.
|
||||
if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
|
||||
# ---------------------------------------------------------------------------
|
||||
cat << "UNLIKELY_EOF" > "$TEMP_DIR/check_permissions.py"
|
||||
{{ check_permissions.py }}
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
# If the script fails for some reason, don't break certbot-auto.
|
||||
set +e
|
||||
# Suppress unexpected error output and only print the script's output if it
|
||||
# ran successfully.
|
||||
CHECK_PERM_OUT=$("$LE_PYTHON" "$TEMP_DIR/check_permissions.py" "$0" 2>/dev/null)
|
||||
CHECK_PERM_STATUS="$?"
|
||||
set -e
|
||||
if [ "$CHECK_PERM_STATUS" = 0 ]; then
|
||||
error "$CHECK_PERM_OUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SELF_UPGRADE" != 1 ]; then
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -660,7 +688,6 @@ else
|
|||
{{ fetch.py }}
|
||||
UNLIKELY_EOF
|
||||
# ---------------------------------------------------------------------------
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
if [ "$PYVER" -lt "$MIN_PYVER" ]; then
|
||||
error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
|
||||
elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
certbot==0.33.1 \
|
||||
--hash=sha256:e2a08467146b7a7ed2c8ca6625b1705d93b51e89866f6ede8a8a262594c18f3f \
|
||||
--hash=sha256:d5203f32c50f3ec5a32df97e4affddbcd288a569678ecb5669adda21cd5ac3d9
|
||||
acme==0.33.1 \
|
||||
--hash=sha256:02467d4b1d246105d6d1ea01822dd9e2eea5bf3a50607523969d8e400d53c07b \
|
||||
--hash=sha256:b38cdb71d0071efe1f1190a744f8f95f3c698b76ac0f5d919bbfe3522e277a82
|
||||
certbot-apache==0.33.1 \
|
||||
--hash=sha256:0d2a463539e6396de2d374de62faba34e1fe40dd8059e3c64dcd5dabaa66887b \
|
||||
--hash=sha256:659db7335d919fee52ae707567994e13c31ed25109c94b246c60c97d21c46f3a
|
||||
certbot-nginx==0.33.1 \
|
||||
--hash=sha256:df9fb86e735eb2668e070f20317e85c37952f3f612fa7f6bbc2c63784b213f28 \
|
||||
--hash=sha256:b3201eee03be74fc743c21c721d3b5586c3323db63e78b68583a6250ad680cff
|
||||
certbot==0.34.0 \
|
||||
--hash=sha256:51dddf2cb1c50a9f8b993090890bf4858d8fadffce38bafcdf6bf585a2040317 \
|
||||
--hash=sha256:e75bdabfd9183bd9842ada42a51070f120d15982e81c490df59dde62e4df2c8b
|
||||
acme==0.34.0 \
|
||||
--hash=sha256:3448024d2c274aebfb9b31b53862576d167626ce2fd1997a78d450c32a292fa3 \
|
||||
--hash=sha256:92478e58f541c5c7c527427a50650005cdede799b78f0a0a65b8093d6368bcfd
|
||||
certbot-apache==0.34.0 \
|
||||
--hash=sha256:79e686f25b63dac17d771d71f791f252774da22125f3f6e0665f4cf791d516fe \
|
||||
--hash=sha256:d5ae09b4801fbac23d5acf64a5ee265108199d2852fbe743e7b6ab06fa08edf6
|
||||
certbot-nginx==0.34.0 \
|
||||
--hash=sha256:868d7dcb59bb2548cb4a2ae187db5da1bfe33aac306b1b844b96ee00a39cac52 \
|
||||
--hash=sha256:d6c728b85c523711ec0dc800f8d4ebbef192fb0ca1ec7914c173207e4aba5194
|
||||
|
|
|
|||
81
letsencrypt-auto-source/pieces/check_permissions.py
Normal file
81
letsencrypt-auto-source/pieces/check_permissions.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
"""Verifies certbot-auto cannot be modified by unprivileged users.
|
||||
|
||||
This script takes the path to certbot-auto as its only command line
|
||||
argument. It then checks that the file can only be modified by uid/gid
|
||||
< 1000 and if other users can modify the file, it prints a warning with
|
||||
a suggestion on how to solve the problem.
|
||||
|
||||
Permissions on symlinks in the absolute path of certbot-auto are ignored
|
||||
and only the canonical path to certbot-auto is checked. There could be
|
||||
permissions problems due to the symlinks that are unreported by this
|
||||
script, however, issues like this were not caused by our documentation
|
||||
and are ignored for the sake of simplicity.
|
||||
|
||||
All warnings are printed to stdout rather than stderr so all stderr
|
||||
output from this script can be suppressed to avoid printing messages if
|
||||
this script fails for some reason.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
|
||||
FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
|
||||
|
||||
|
||||
def has_safe_permissions(path):
|
||||
"""Returns True if the given path has secure permissions.
|
||||
|
||||
The permissions are considered safe if the file is only writable by
|
||||
uid/gid < 1000.
|
||||
|
||||
The reason we allow more IDs than 0 is because on some systems such
|
||||
as Debian, system users/groups other than uid/gid 0 are used for the
|
||||
path we recommend in our instructions which is /usr/local/bin. 1000
|
||||
was chosen because on Debian 0-999 is reserved for system IDs[1] and
|
||||
on RHEL either 0-499 or 0-999 is reserved depending on the
|
||||
version[2][3]. Due to these differences across different OSes, this
|
||||
detection isn't perfect so we only determine permissions are
|
||||
insecure when we can be reasonably confident there is a problem
|
||||
regardless of the underlying OS.
|
||||
|
||||
[1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
|
||||
[2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
|
||||
[3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
|
||||
|
||||
:param str path: filesystem path to check
|
||||
:returns: True if the path has secure permissions, otherwise, False
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
# os.stat follows symlinks before obtaining information about a file.
|
||||
stat_result = os.stat(path)
|
||||
if stat_result.st_mode & stat.S_IWOTH:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWGRP and stat_result.st_gid >= 1000:
|
||||
return False
|
||||
if stat_result.st_mode & stat.S_IWUSR and stat_result.st_uid >= 1000:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main(certbot_auto_path):
|
||||
current_path = os.path.realpath(certbot_auto_path)
|
||||
last_path = None
|
||||
permissions_ok = True
|
||||
# This loop makes use of the fact that os.path.dirname('/') == '/'.
|
||||
while current_path != last_path and permissions_ok:
|
||||
permissions_ok = has_safe_permissions(current_path)
|
||||
last_path = current_path
|
||||
current_path = os.path.dirname(current_path)
|
||||
|
||||
if not permissions_ok:
|
||||
print('{0} has insecure permissions!'.format(certbot_auto_path))
|
||||
print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1])
|
||||
|
|
@ -217,7 +217,12 @@ def _write_requirements(dest_file, requirements, conflicts):
|
|||
# To generate this, do (with docker and package hashin installed):
|
||||
# ```
|
||||
# letsencrypt-auto-source/rebuild_dependencies.py \\
|
||||
# letsencrypt-auto-sources/pieces/dependency-requirements.txt
|
||||
# letsencrypt-auto-source/pieces/dependency-requirements.txt
|
||||
# ```
|
||||
# If you want to update a single dependency, run commands similar to these:
|
||||
# ```
|
||||
# pip install hashin
|
||||
# hashin -r dependency-requirements.txt cryptography==1.5.2
|
||||
# ```
|
||||
''')
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
|
|||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from json import dumps
|
||||
from os import chmod, environ, makedirs
|
||||
from os import chmod, environ, makedirs, stat
|
||||
from os.path import abspath, dirname, exists, join
|
||||
import re
|
||||
from shutil import copy, rmtree
|
||||
import socket
|
||||
import ssl
|
||||
from stat import S_IRUSR, S_IXUSR
|
||||
from stat import S_IMODE, S_IRUSR, S_IWUSR, S_IXUSR, S_IWGRP, S_IWOTH
|
||||
from subprocess import CalledProcessError, Popen, PIPE
|
||||
import sys
|
||||
from tempfile import mkdtemp
|
||||
|
|
@ -192,7 +192,7 @@ def install_le_auto(contents, install_path):
|
|||
chmod(install_path, S_IRUSR | S_IXUSR)
|
||||
|
||||
|
||||
def run_le_auto(le_auto_path, venv_dir, base_url, **kwargs):
|
||||
def run_le_auto(le_auto_path, venv_dir, base_url=None, le_auto_args_str='--version', **kwargs):
|
||||
"""Run the prebuilt version of letsencrypt-auto, returning stdout and
|
||||
stderr strings.
|
||||
|
||||
|
|
@ -201,13 +201,17 @@ def run_le_auto(le_auto_path, venv_dir, base_url, **kwargs):
|
|||
"""
|
||||
env = environ.copy()
|
||||
d = dict(VENV_PATH=venv_dir,
|
||||
# URL to PyPI-style JSON that tell us the latest released version
|
||||
# of LE:
|
||||
LE_AUTO_JSON_URL=base_url + 'certbot/json',
|
||||
# URL to dir containing letsencrypt-auto and letsencrypt-auto.sig:
|
||||
LE_AUTO_DIR_TEMPLATE=base_url + '%s/',
|
||||
# The public key corresponding to signing.key:
|
||||
LE_AUTO_PUBLIC_KEY="""-----BEGIN PUBLIC KEY-----
|
||||
NO_CERT_VERIFY='1',
|
||||
**kwargs)
|
||||
|
||||
if base_url is not None:
|
||||
# URL to PyPI-style JSON that tell us the latest released version
|
||||
# of LE:
|
||||
d['LE_AUTO_JSON_URL'] = base_url + 'certbot/json'
|
||||
# URL to dir containing letsencrypt-auto and letsencrypt-auto.sig:
|
||||
d['LE_AUTO_DIR_TEMPLATE'] = base_url + '%s/'
|
||||
# The public key corresponding to signing.key:
|
||||
d['LE_AUTO_PUBLIC_KEY'] = """-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMoSzLYQ7E1sdSOkwelg
|
||||
tzKIh2qi3bpXuYtcfFC0XrvWig071NwIj+dZiT0OLZ2hPispEH0B7ISuuWg1ll7G
|
||||
hFW0VdbxL6JdGzS2ShNWkX9hE9z+j8VqwDPOBn3ZHm03qwpYkBDwQib3KqOdYbTT
|
||||
|
|
@ -215,12 +219,12 @@ uUtJmmGcuk3a9Aq/sCT6DdfmTSdP5asdQYwIcaQreDrOosaS84DTWI3IU+UYJVgl
|
|||
LsIVPBuy9IcgHidUQ96hJnoPsDCWsHwX62495QKEarauyKQrJzFes0EY95orDM47
|
||||
Z5o/NDiQB11m91yNB0MmPYY9QSbnOA9j7IaaC97AwRLuwXY+/R2ablTcxurWou68
|
||||
iQIDAQAB
|
||||
-----END PUBLIC KEY-----""",
|
||||
NO_CERT_VERIFY='1',
|
||||
**kwargs)
|
||||
-----END PUBLIC KEY-----"""
|
||||
|
||||
env.update(d)
|
||||
|
||||
return out_and_err(
|
||||
le_auto_path + ' --version',
|
||||
le_auto_path + ' ' + le_auto_args_str,
|
||||
shell=True,
|
||||
env=env)
|
||||
|
||||
|
|
@ -240,6 +244,12 @@ def set_le_script_version(venv_dir, version):
|
|||
chmod(letsencrypt_path, S_IRUSR | S_IXUSR)
|
||||
|
||||
|
||||
def sudo_chmod(path, mode):
|
||||
"""Runs `sudo chmod mode path`."""
|
||||
mode = oct(mode).replace('o', '')
|
||||
out_and_err(['sudo', 'chmod', mode, path])
|
||||
|
||||
|
||||
class AutoTests(TestCase):
|
||||
"""Test the major branch points of letsencrypt-auto:
|
||||
|
||||
|
|
@ -395,3 +405,95 @@ class AutoTests(TestCase):
|
|||
else:
|
||||
self.fail("Pip didn't detect a bad hash and stop the "
|
||||
"installation.")
|
||||
|
||||
def test_permissions_warnings(self):
|
||||
"""Make sure letsencrypt-auto properly warns about permissions problems."""
|
||||
# This test assumes that only the parent of the directory containing
|
||||
# letsencrypt-auto (usually /tmp) may have permissions letsencrypt-auto
|
||||
# considers insecure.
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
le_auto_path = abspath(le_auto_path)
|
||||
le_auto_dir = dirname(le_auto_path)
|
||||
le_auto_dir_parent = dirname(le_auto_dir)
|
||||
install_le_auto(self.NEW_LE_AUTO, le_auto_path)
|
||||
|
||||
run_letsencrypt_auto = partial(
|
||||
run_le_auto, le_auto_path, venv_dir,
|
||||
le_auto_args_str='--install-only --no-self-upgrade',
|
||||
PIP_FIND_LINKS=join(tests_dir(), 'fake-letsencrypt', 'dist'))
|
||||
# Run letsencrypt-auto once with current permissions to avoid
|
||||
# potential problems when the script tries to write to temporary
|
||||
# directories.
|
||||
run_letsencrypt_auto()
|
||||
|
||||
le_auto_dir_mode = stat(le_auto_dir).st_mode
|
||||
le_auto_dir_parent_mode = S_IMODE(stat(le_auto_dir_parent).st_mode)
|
||||
try:
|
||||
# Make letsencrypt-auto happy with the current permissions
|
||||
chmod(le_auto_dir, S_IRUSR | S_IXUSR)
|
||||
sudo_chmod(le_auto_dir_parent, 0o755)
|
||||
|
||||
self._test_permissions_warnings_about_path(le_auto_path, run_letsencrypt_auto)
|
||||
self._test_permissions_warnings_about_path(le_auto_dir, run_letsencrypt_auto)
|
||||
finally:
|
||||
chmod(le_auto_dir, le_auto_dir_mode)
|
||||
sudo_chmod(le_auto_dir_parent, le_auto_dir_parent_mode)
|
||||
|
||||
def _test_permissions_warnings_about_path(self, path, run_le_auto_func):
|
||||
# Test that there are no problems with the current permissions
|
||||
out, _ = run_le_auto_func()
|
||||
self.assertFalse('insecure permissions' in out)
|
||||
|
||||
stat_result = stat(path)
|
||||
original_mode = stat_result.st_mode
|
||||
|
||||
# Test world permissions
|
||||
chmod(path, original_mode | S_IWOTH)
|
||||
out, _ = run_le_auto_func()
|
||||
self.assertTrue('insecure permissions' in out)
|
||||
|
||||
# Test group permissions
|
||||
if stat_result.st_gid >= 1000:
|
||||
chmod(path, original_mode | S_IWGRP)
|
||||
out, _ = run_le_auto_func()
|
||||
self.assertTrue('insecure permissions' in out)
|
||||
|
||||
# Test owner permissions
|
||||
if stat_result.st_uid >= 1000:
|
||||
chmod(path, original_mode | S_IWUSR)
|
||||
out, _ = run_le_auto_func()
|
||||
self.assertTrue('insecure permissions' in out)
|
||||
|
||||
# Test that permissions were properly restored
|
||||
chmod(path, original_mode)
|
||||
out, _ = run_le_auto_func()
|
||||
self.assertFalse('insecure permissions' in out)
|
||||
|
||||
def test_disabled_permissions_warnings(self):
|
||||
"""Make sure that letsencrypt-auto permissions warnings can be disabled."""
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
le_auto_path = abspath(le_auto_path)
|
||||
install_le_auto(self.NEW_LE_AUTO, le_auto_path)
|
||||
|
||||
le_auto_args_str='--install-only --no-self-upgrade'
|
||||
pip_links=join(tests_dir(), 'fake-letsencrypt', 'dist')
|
||||
out, _ = run_le_auto(le_auto_path, venv_dir,
|
||||
le_auto_args_str=le_auto_args_str,
|
||||
PIP_FIND_LINKS=pip_links)
|
||||
self.assertTrue('insecure permissions' in out)
|
||||
|
||||
# Test that warnings are disabled when the script isn't run as
|
||||
# root.
|
||||
out, _ = run_le_auto(le_auto_path, venv_dir,
|
||||
le_auto_args_str=le_auto_args_str,
|
||||
LE_AUTO_SUDO='',
|
||||
PIP_FIND_LINKS=pip_links)
|
||||
self.assertFalse('insecure permissions' in out)
|
||||
|
||||
# Test that --no-permissions-check disables warnings.
|
||||
le_auto_args_str += ' --no-permissions-check'
|
||||
out, _ = run_le_auto(
|
||||
le_auto_path, venv_dir,
|
||||
le_auto_args_str=le_auto_args_str,
|
||||
PIP_FIND_LINKS=pip_links)
|
||||
self.assertFalse('insecure permissions' in out)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ PROFILE = cl_args.aws_profile
|
|||
|
||||
# Globals
|
||||
#-------------------------------------------------------------------------------
|
||||
BOULDER_AMI = 'ami-5f490b35' # premade shared boulder AMI 14.04LTS us-east-1
|
||||
BOULDER_AMI = 'ami-072a9534772bec854' # premade shared boulder AMI 18.04LTS us-east-1
|
||||
LOGDIR = "" #points to logging / working directory
|
||||
# boto3/AWS api globals
|
||||
AWS_SESSION = None
|
||||
|
|
@ -290,8 +290,7 @@ def deploy_script(scriptpath, *args):
|
|||
|
||||
def run_boulder():
|
||||
with cd('$GOPATH/src/github.com/letsencrypt/boulder'):
|
||||
run('go run cmd/rabbitmq-setup/main.go -server amqp://localhost')
|
||||
run('nohup ./start.py >& /dev/null < /dev/null &')
|
||||
run('sudo docker-compose up -d')
|
||||
|
||||
def config_and_launch_boulder(instance):
|
||||
execute(deploy_script, 'scripts/boulder_config.sh')
|
||||
|
|
|
|||
|
|
@ -1,32 +1,24 @@
|
|||
#!/bin/bash -x
|
||||
|
||||
# Configures and Launches Boulder Server installed on
|
||||
# us-east-1 ami-5f490b35 bouldertestserver (boulder commit 8b433f54dab)
|
||||
# us-east-1 ami-072a9534772bec854 bouldertestserver3 (boulder commit b24fe7c3ea4)
|
||||
|
||||
# fetch instance data from EC2 metadata service
|
||||
public_host=$(curl -s http://169.254.169.254/2014-11-05/meta-data/public-hostname)
|
||||
public_ip=$(curl -s http://169.254.169.254/2014-11-05/meta-data/public-ipv4)
|
||||
private_ip=$(curl -s http://169.254.169.254/2014-11-05/meta-data/local-ipv4)
|
||||
|
||||
# get local DNS resolver for VPC
|
||||
resolver_ip=$(grep nameserver /etc/resolv.conf |cut -d" " -f2 |head -1)
|
||||
# set to public DNS resolver
|
||||
resolver_ip=8.8.8.8
|
||||
resolver=$resolver_ip':53'
|
||||
|
||||
# modifies integration testing boulder setup for local AWS VPC network
|
||||
# connections instead of localhost
|
||||
cd $GOPATH/src/github.com/letsencrypt/boulder
|
||||
# configure boulder to receive outside connection on 4000
|
||||
sed -i '/listenAddress/ s/127.0.0.1:4000/'$private_ip':4000/' ./test/boulder-config.json
|
||||
sed -i '/baseURL/ s/127.0.0.1:4000/'$private_ip':4000/' ./test/boulder-config.json
|
||||
# change test ports to real
|
||||
sed -i '/httpPort/ s/5002/80/' ./test/boulder-config.json
|
||||
sed -i '/httpsPort/ s/5001/443/' ./test/boulder-config.json
|
||||
sed -i '/tlsPort/ s/5001/443/' ./test/boulder-config.json
|
||||
# set local dns resolver
|
||||
sed -i '/dnsResolver/ s/127.0.0.1:8053/'$resolver'/' ./test/boulder-config.json
|
||||
|
||||
# start rabbitMQ
|
||||
#go run cmd/rabbitmq-setup/main.go -server amqp://localhost
|
||||
# start acme services
|
||||
#nohup ./start.py >& /dev/null < /dev/null &
|
||||
#./start.py
|
||||
sed -i '/httpPort/ s/5002/80/' ./test/config/va.json
|
||||
sed -i '/httpsPort/ s/5001/443/' ./test/config/va.json
|
||||
sed -i '/tlsPort/ s/5001/443/' ./test/config/va.json
|
||||
# set dns resolver
|
||||
sed -i 's/"127.0.0.1:8053",/"'$resolver'"/' ./test/config/va.json
|
||||
sed -i 's/"127.0.0.1:8054"//' ./test/config/va.json
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ set -eo pipefail
|
|||
#private_ip=$(curl -s http://169.254.169.254/2014-11-05/meta-data/local-ipv4)
|
||||
|
||||
cd letsencrypt
|
||||
export PATH="$PWD/letsencrypt-auto-source:$PATH"
|
||||
LE_AUTO_DIR="/usr/local/bin"
|
||||
LE_AUTO_PATH="$LE_AUTO_DIR/letsencrypt-auto"
|
||||
sudo cp letsencrypt-auto-source/letsencrypt-auto "$LE_AUTO_PATH"
|
||||
sudo chown root "$LE_AUTO_PATH"
|
||||
sudo chmod 0755 "$LE_AUTO_PATH"
|
||||
export PATH="$LE_AUTO_DIR:$PATH"
|
||||
|
||||
letsencrypt-auto --os-packages-only --debug --version
|
||||
|
||||
# Create a venv-like layout at the old virtual environment path to test that a
|
||||
|
|
@ -35,3 +41,9 @@ if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBC
|
|||
echo "letsencrypt-auto not included in help output!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1)
|
||||
if [ -n "$OUTPUT" ]; then
|
||||
echo letsencrypt-auto produced unexpected output!
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ targets:
|
|||
type: ubuntu
|
||||
virt: hvm
|
||||
user: admin
|
||||
- ami: ami-116d857a
|
||||
- ami: ami-077bf3962f29d3fa4
|
||||
name: debian8.1
|
||||
type: ubuntu
|
||||
virt: hvm
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ SetVersion() {
|
|||
|
||||
SetVersion "$version"
|
||||
|
||||
# Unset CERTBOT_OLDEST to prevent wheels from being built improperly due to
|
||||
# conditionals like the one found in certbot-dns-dnsimple's setup.py file.
|
||||
unset CERTBOT_OLDEST
|
||||
echo "Preparing sdists and wheels"
|
||||
for pkg_dir in . $SUBPKGS_NO_CERTBOT
|
||||
do
|
||||
|
|
|
|||
Loading…
Reference in a new issue