Merge branch 'release/0.1.1'
This commit is contained in:
commit
7c51c9896c
|
@ -19,6 +19,7 @@ pip-log.txt
|
|||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
htmlcov
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
@ -39,8 +40,9 @@ Scripts
|
|||
|
||||
# LE HAProxy dev stuff
|
||||
working
|
||||
.vagrant
|
||||
.vagrant*
|
||||
certbot.log
|
||||
|
||||
# tmp files:
|
||||
*.swp
|
||||
|
||||
|
|
49
README.rst
49
README.rst
|
@ -3,12 +3,37 @@ HAProxy plugin for Certbot
|
|||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
This is a certbot plugin for using certbot in combination with a HAProxy setup.
|
||||
Its advantage over using the standalone certbot is that it automatically places
|
||||
certificates in the correct directory and restarts HAProxy afterwards. It should
|
||||
also enable you to very easily do automatic certificate renewal.
|
||||
|
||||
Furthermore, you can configure HAProxy to handle Boulder's authentication using
|
||||
the HAProxy authenticator of this plugin.
|
||||
|
||||
It was created for use with `Greenhost`_'s share hosting environment and can be
|
||||
useful to you in the following cases:
|
||||
|
||||
- If you use HAProxy and have several domains for which you want to enable Let's
|
||||
Encrypt certificates
|
||||
- If you yourself have a shared hosting platform that uses HAProxy to redirect
|
||||
to your client's websites
|
||||
- Actually any case in which you want to automatically restart HAProxy after you
|
||||
request a new certificate.
|
||||
|
||||
.. _Greenhost: https://greenhost.net
|
||||
|
||||
Please read the installation instructions on how to configure HAProxy.
|
||||
|
||||
Installing: Requirements
|
||||
------------------------
|
||||
|
||||
Currently this plugin has been tested on Debian Jessie, but it will most likely
|
||||
work on Ubuntu 14.04+ too. If you are running Debian Wheezy, you may need to
|
||||
take additional steps during the installation.
|
||||
take additional steps during the installation. Thus, the requirements are:
|
||||
|
||||
- Debian Jessie (or higher) or Ubuntu Trusty (or higher).
|
||||
- Python 2.7 (2.6 is supported by certbot and our goal is to be compatible but
|
||||
|
@ -421,3 +446,25 @@ run:
|
|||
|
||||
Since pip is part of ``python-setuptools``, you need to have it installed before
|
||||
you can update.
|
||||
|
||||
Making a `.deb` debian package
|
||||
------------------------------
|
||||
Requirements:
|
||||
|
||||
- python stdeb: pip install --upgrade stdeb
|
||||
- dh clean: apt-get install dh-make
|
||||
|
||||
Run the following commands in your vagrant machine:
|
||||
|
||||
```
|
||||
apt-file update
|
||||
python setup.py sdist
|
||||
# py2dsc has a problem with vbox mounted folders
|
||||
mv dist/certbot-haproxy-<version>.tar.gz ~
|
||||
cd ~
|
||||
py2dsc certbot-haproxy-<version>.tar.gz
|
||||
cd deb_dist/certbot-haproxy-<version>
|
||||
# NOTE: Not signed, no signed changes (with -uc and -us)
|
||||
# NOTE: Add the package to the ghtools repo
|
||||
dpkg-buildpackage -rfakeroot -uc -us
|
||||
```
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
Be sure to replace `$USER` with the user that will be running the lehaproxy
|
||||
installer.
|
||||
"""
|
||||
from builtins import str
|
||||
from past.builtins import basestring
|
||||
import logging
|
||||
import os
|
||||
import glob
|
||||
|
@ -134,7 +136,7 @@ class HAProxyInstaller(common.Plugin):
|
|||
" returns letsencrypt certificates. Defaults to the value"
|
||||
" 'h2ppy h2cker fake CA' that is used by the local boulder."
|
||||
),
|
||||
type=unicode,
|
||||
type=str,
|
||||
default=u'Let\'s Encrypt Authority X3'
|
||||
)
|
||||
add(
|
||||
|
@ -464,7 +466,7 @@ class HAProxyInstaller(common.Plugin):
|
|||
|
||||
# Write all new files and changes:
|
||||
for filepath, contents in \
|
||||
self.new_crt_files.items() + self.crt_files.items():
|
||||
list(self.new_crt_files.items()) + list(self.crt_files.items()):
|
||||
|
||||
# Make sure directory of filepath exists
|
||||
path = os.path.dirname(os.path.abspath(filepath))
|
||||
|
@ -523,7 +525,7 @@ class HAProxyInstaller(common.Plugin):
|
|||
contents = pem.read()
|
||||
if self._cert_key_check(contents, filepath):
|
||||
yield (filepath, filepath, self.conf("haproxy-config"))
|
||||
except IOError, err:
|
||||
except IOError as err:
|
||||
logger.error(
|
||||
"Can't access \"%s\", reason:\n %s",
|
||||
filepath,
|
||||
|
@ -544,7 +546,7 @@ class HAProxyInstaller(common.Plugin):
|
|||
except TypeError:
|
||||
logger.warn("Could not read certificate, wrong type (not PEM)")
|
||||
# Documentation says it raises "Error"
|
||||
except Exception, err: # pylint: disable=broad-except
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
logger.error("Unexpected error! %s", err)
|
||||
|
||||
if issuer == self.conf('haproxy-ca-common-name') and key.check():
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Certbot HAProxy Tests"""
|
||||
from __future__ import print_function
|
||||
import unittest
|
||||
|
||||
|
||||
|
@ -6,11 +7,8 @@ def load_tests(loader, tests, pattern=None):
|
|||
"""Find all python files in the tests folder"""
|
||||
if pattern is None:
|
||||
pattern = 'test_*.py'
|
||||
print "loader: ", loader
|
||||
print("loader: ", loader)
|
||||
|
||||
suite = loader.discover('certbot_haproxy/tests', pattern=pattern)
|
||||
suite.addTests(tests)
|
||||
return suite
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import unittest
|
||||
import mock
|
||||
import os
|
||||
|
||||
from certbot_haproxy.authenticator import HAProxyAuthenticator
|
||||
from acme import challenges
|
||||
|
||||
class TestAuthenticator(unittest.TestCase):
|
||||
|
||||
test_domain = 'le.wtf'
|
||||
|
||||
"""Test the relevant functions of the certbot_haproxy installer"""
|
||||
|
||||
def setUp(self):
|
||||
mock_le_config = mock.MagicMock(
|
||||
# TODO: Don't know what we need here
|
||||
)
|
||||
self.authenticator = HAProxyAuthenticator(
|
||||
config=mock_le_config, name="authenticator")
|
||||
|
||||
def test_more_info(self):
|
||||
info = self.authenticator.more_info()
|
||||
self.assertIsInstance(info, str)
|
||||
|
||||
@mock.patch("certbot_haproxy.authenticator.logger")
|
||||
@mock.patch("certbot.util.logger")
|
||||
def test_add_parser_arguments(self, util_logger, certbot_logger):
|
||||
"""Weak test taken from apache plugin tests"""
|
||||
self.authenticator.add_parser_arguments(mock.MagicMock())
|
||||
self.assertEqual(certbot_logger.error.call_count, 0)
|
||||
self.assertEqual(util_logger.error.call_count, 0)
|
||||
|
||||
def test_supported_challenges(self):
|
||||
chal = self.authenticator.supported_challenges
|
||||
self.assertIsInstance(chal, list)
|
||||
self.assertTrue(challenges.HTTP01 in chal)
|
|
@ -1,4 +1,5 @@
|
|||
"""Test installer functions"""
|
||||
from past.builtins import basestring
|
||||
import unittest
|
||||
import mock
|
||||
import os
|
||||
|
@ -15,6 +16,9 @@ def _conf(self, var):
|
|||
|
||||
@mock.patch("certbot_haproxy.installer.HAProxyInstaller.conf", new=_conf)
|
||||
class TestInstaller(unittest.TestCase):
|
||||
|
||||
test_domain = 'le.wtf'
|
||||
|
||||
"""Test the relevant functions of the certbot_haproxy installer"""
|
||||
|
||||
def setUp(self):
|
||||
|
@ -72,7 +76,7 @@ class TestInstaller(unittest.TestCase):
|
|||
from OpenSSL import crypto
|
||||
self.installer.new_crt_files = {}
|
||||
self.installer._fall_back_cert()
|
||||
key = self.installer.new_crt_files.keys()[0]
|
||||
key = list(self.installer.new_crt_files.keys())[0]
|
||||
cert = self.installer.new_crt_files[key]
|
||||
self.assertIsInstance(key, str)
|
||||
self.assertIsInstance(cert, str)
|
||||
|
@ -83,7 +87,6 @@ class TestInstaller(unittest.TestCase):
|
|||
def test_deploy_cert_save(self):
|
||||
"""Deploy and save a certificate and rollback after that"""
|
||||
# Variables for test:
|
||||
domain = 'le.wtf'
|
||||
crt_dir = os.path.join(self.temp_dir, self.test_dir, "deploy_test")
|
||||
base = os.path.join(self.temp_dir, self.test_dir, "deploy_cert")
|
||||
key_path = os.path.join(base, "privkey.pem")
|
||||
|
@ -99,37 +102,70 @@ class TestInstaller(unittest.TestCase):
|
|||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.installer.deploy_cert,
|
||||
domain, 'no-cert', 'no-key')
|
||||
self.test_domain, 'no-cert', 'no-key')
|
||||
|
||||
# Arguments for several tests
|
||||
all_args = [
|
||||
(domain, cert_path, key_path),
|
||||
(domain, cert_path, key_path, chain_path),
|
||||
(domain, None, key_path, None, fullchain_path),
|
||||
(self.test_domain, cert_path, key_path),
|
||||
(self.test_domain, cert_path, key_path, chain_path),
|
||||
(self.test_domain, None, key_path, None, fullchain_path),
|
||||
]
|
||||
|
||||
# Run deploy and save with all types of args
|
||||
for args in all_args:
|
||||
# Deploy with only key and cert
|
||||
self.installer.deploy_cert(*args)
|
||||
|
||||
try:
|
||||
self.installer.view_config_changes()
|
||||
except ReverterError:
|
||||
self.fail("Reverter failed")
|
||||
except PluginError:
|
||||
self.fail("Reverter failed with PluginError")
|
||||
|
||||
self.installer.save()
|
||||
# Check if le.wtf.pem is created
|
||||
pem = os.path.join(crt_dir, domain) + self.installer.crt_postfix
|
||||
pem = os.path.join(crt_dir, self.test_domain) \
|
||||
+ self.installer.crt_postfix
|
||||
self.assertTrue(os.path.isfile(pem))
|
||||
# Roll back pem creation
|
||||
self.installer.rollback_checkpoints()
|
||||
# Check if file was removed again
|
||||
self.assertFalse(os.path.isfile(pem))
|
||||
|
||||
# Try to revert:
|
||||
try:
|
||||
self.installer.recovery_routine()
|
||||
except PluginError:
|
||||
self.fail("Recovery routine didn't work")
|
||||
|
||||
# fail without key
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.installer.deploy_cert,
|
||||
self.test_domain, cert_path, None)
|
||||
|
||||
# Run twice (should update instead of create)
|
||||
args = (self.test_domain, cert_path, key_path)
|
||||
self.installer.deploy_cert(*args)
|
||||
self.installer.save()
|
||||
self.installer.deploy_cert(*args)
|
||||
self.installer.save()
|
||||
|
||||
|
||||
def test_enhancement(self):
|
||||
""" Currently no enhancements are supported, we should see that """
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.installer.enhance,
|
||||
self.test_domain,
|
||||
"non-existent-enhancement")
|
||||
|
||||
|
||||
@mock.patch("certbot_haproxy.installer.logger")
|
||||
@mock.patch("certbot.util.logger")
|
||||
def test_config_test(self, util_logger, certbot_logger):
|
||||
"""Test config_test function with a faulty and a valid cfg file"""
|
||||
# Check with current config file
|
||||
self.installer.config_test()
|
||||
self.assertEqual(certbot_logger.error.call_count, 0)
|
||||
self.assertEqual(util_logger.error.call_count, 0)
|
||||
|
||||
# Check with bad config file
|
||||
self.installer.config.haproxy_config = os.path.join(
|
||||
self.temp_dir, self.test_dir, "haproxy_bad.cfg")
|
||||
|
@ -145,3 +181,26 @@ class TestInstaller(unittest.TestCase):
|
|||
errors.MisconfigurationError,
|
||||
self.installer.config_test
|
||||
)
|
||||
|
||||
def test_more_info(self):
|
||||
ret = self.installer.more_info()
|
||||
self.assertIsInstance(ret, basestring)
|
||||
|
||||
@mock.patch('certbot.util.exe_exists', return_value=False)
|
||||
def test_failed_service_command(self, mock_exe_exists):
|
||||
""" Fail on service manager command """
|
||||
self.assertRaises(errors.NoInstallationError, self.installer.prepare)
|
||||
mock_exe_exists.assert_called_once()
|
||||
|
||||
@mock.patch('subprocess.check_output',
|
||||
return_value='not-really-a-version-number')
|
||||
def test_no_version_number(self, mock_check_output):
|
||||
""" Fail on version command """
|
||||
self.assertRaises(errors.NoInstallationError, self.installer.prepare)
|
||||
|
||||
@mock.patch('subprocess.check_output',
|
||||
return_value='HA-Proxy version 1.4.8 2014/10/31')
|
||||
def test_wrong_version_number(self, mock_check_output):
|
||||
""" Supply a too low version number for HAproxy """
|
||||
self.assertRaises(errors.NotSupportedError, self.installer.prepare)
|
||||
mock_check_output.assert_called_once()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
Utility functions.
|
||||
"""
|
||||
from builtins import object
|
||||
|
||||
from OpenSSL import crypto
|
||||
import socket
|
||||
|
|
|
@ -69,6 +69,6 @@ index 7a8d348..746dee8 100644
|
|||
{
|
||||
- "module": "/usr/local/lib/libpkcs11-proxy.so",
|
||||
+ "module": "/usr/lib/softhsm/libsofthsm.so",
|
||||
"tokenLabel": "token_label",
|
||||
"tokenLabel": "intermediate",
|
||||
"pin": "5678",
|
||||
"privateKeyLabel": "key_label"
|
||||
"privateKeyLabel": "intermediate_key"
|
||||
|
|
|
@ -5,7 +5,9 @@ dpkg-reconfigure -f noninteractive tzdata
|
|||
export DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
# Install go 1.5
|
||||
wget -q https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz
|
||||
if [ ! -f go1.5.linux-amd64.tar.gz ]; then
|
||||
wget -q https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz
|
||||
fi
|
||||
tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz
|
||||
|
||||
# Set GOROOT and GOPATH so that GO knows where it is and where it can install
|
||||
|
@ -118,7 +120,7 @@ server {
|
|||
}
|
||||
EOF
|
||||
|
||||
ln -s /etc/nginx/sites-available/wfe /etc/nginx/sites-enabled/wfe
|
||||
ln -fs /etc/nginx/sites-available/wfe /etc/nginx/sites-enabled/wfe
|
||||
rm -rfv /etc/nginx/sites-enabled/default
|
||||
systemctl restart nginx
|
||||
|
||||
|
|
5
setup.py
5
setup.py
|
@ -3,7 +3,7 @@ import sys
|
|||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
own_version = '0.1.1'
|
||||
certbot_version = '0.8.1'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
|
@ -15,6 +15,7 @@ install_requires = [
|
|||
'setuptools>=1.0',
|
||||
'zope.component',
|
||||
'zope.interface',
|
||||
'future',
|
||||
]
|
||||
|
||||
if sys.version_info < (2, 7):
|
||||
|
@ -42,7 +43,7 @@ haproxy_installer = 'certbot_haproxy.installer:HAProxyInstaller'
|
|||
|
||||
setup(
|
||||
name='certbot-haproxy',
|
||||
version=certbot_version,
|
||||
version=own_version,
|
||||
description="HAProxy plugin for Certbot",
|
||||
long_description=long_description,
|
||||
url='https://code.greenhost.net/open/certbot-haproxy',
|
||||
|
|
Reference in New Issue