From d1330efe41c4939098fd37c5746c68919fe166b7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 30 Apr 2019 10:45:03 -0700 Subject: [PATCH] Print warning when certbot-auto has insecure permissions. (#6995) This PR attempts to better inform people about the problem identified at https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/. I was hesitant to add the flag --no-permissions-check, however, if there's some obscure distro out there (or custom user setup) that has a strange users and groups, I didn't want us to either: Have to put out a bug fix release Refuse to fix the problem and let them deal with warnings on every run * add check_permissions.py * Update letsencrypt-auto.template. * build letsencrypt-auto * Add test_permissions_warnings to auto_test * Allow uid/gid < 1000. * Add --no-permissions-check to Certbot. * Add --no-permissions-check to certbot-auto. * Add test farm test that letsencrypt-auto is quiet. As a bonus, this new test will catch problems like the one that the caused 0.33.1 point release. * Update CHANGELOG about permissions check. * Update permissions comment. * Fix symlink handling. * Use a better default in auto_test.py. --- CHANGELOG.md | 6 + certbot/cli.py | 5 + certbot/constants.py | 1 + certbot/tests/cli_test.py | 4 + letsencrypt-auto-source/letsencrypt-auto | 112 ++++++++++++++- .../letsencrypt-auto.template | 31 ++++- .../pieces/check_permissions.py | 81 +++++++++++ letsencrypt-auto-source/tests/auto_test.py | 130 ++++++++++++++++-- ...st_letsencrypt_auto_certonly_standalone.sh | 14 +- 9 files changed, 365 insertions(+), 19 deletions(-) create mode 100644 letsencrypt-auto-source/pieces/check_permissions.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d80f1baa5..275913bbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * 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. ### Fixed diff --git a/certbot/cli.py b/certbot/cli.py index 96f58caf7..866b64aa6 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -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", diff --git a/certbot/constants.py b/certbot/constants.py index c23effe2d..5b268e157 100644 --- a/certbot/constants.py +++ b/certbot/constants.py @@ -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, diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 592bd1be7..8259d4040 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -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.""" diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 15305da39..ce57ca682 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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 @@ -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 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index a5a29c483..21db0f908 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -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 diff --git a/letsencrypt-auto-source/pieces/check_permissions.py b/letsencrypt-auto-source/pieces/check_permissions.py new file mode 100644 index 000000000..ba55e6d97 --- /dev/null +++ b/letsencrypt-auto-source/pieces/check_permissions.py @@ -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]) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 16c478f20..9c823fb55 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -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) diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index 901d01e4a..035512ef7 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -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