Experimental support for Let's Encrypt.

see #50
This commit is contained in:
Antoine Nguyen
2016-09-21 17:30:04 +02:00
parent 81b32d21ad
commit 7c22bbe5f0
4 changed files with 100 additions and 22 deletions

View File

@@ -39,3 +39,26 @@ By default, the following components are installed:
If you want more information about the installation process, add the
``--debug`` option to your command line.
Let's Encrypt certificate
-------------------------
.. warning::
Please note this option requires the hostname you're using to be
valid (ie. it can be resolved with a DNS query) and to match the
server you're installing Modoboa on.
If you want to generate a valid certificate using `Let's Encrypt
<https://letsencrypt.org/>`_, edit the ``installer.cfg`` file and
modify the following settings::
[certificate]
generate = true
type = letsencrypt
[letsencrypt]
email = admin@example.com
Change the ``email`` setting to a valid value since it will be used
for account recovery.

View File

@@ -1,3 +1,11 @@
[certificate]
generate = true
# Choose between self-signed or letsencrypt
type = letsencrypt
[letsencrypt]
email = admin@example.com
[database]
# Select database engine : postgres or mysql
engine = postgres

View File

@@ -11,7 +11,27 @@ class CertificateBackend(object):
def __init__(self, config):
"""Set path to certificates."""
self.config = config
if not config.has_option("general", "tls_key_file"):
def overwrite_existing_certificate(self):
"""Check if certificate already exists."""
if os.path.exists(self.config.get("general", "tls_key_file")):
if not self.config.getboolean("general", "force"):
answer = utils.user_input(
"Overwrite the existing SSL certificate? (y/N) ")
if not answer.lower().startswith("y"):
return False
return True
class SelfSignedCertificate(CertificateBackend):
"""Create a self signed certificate."""
def __init__(self, *args, **kwargs):
"""Sanity checks."""
super(SelfSignedCertificate, self).__init__(*args, **kwargs)
if self.config.has_option("general", "tls_key_file"):
# Compatibility
return
for base_dir in ["/etc/pki/tls", "/etc/ssl"]:
if os.path.exists(base_dir):
self.config.set(
@@ -22,20 +42,10 @@ class CertificateBackend(object):
"{}/certs/%(hostname)s.cert".format(base_dir))
return
raise RuntimeError("Cannot find a directory to store certificate")
else:
return
class SelfSignedCertificate(CertificateBackend):
"""Create a self signed certificate."""
def create(self):
"""Create a certificate."""
if os.path.exists(self.config.get("general", "tls_key_file")):
if not self.config.getboolean("general", "force"):
answer = utils.user_input(
"Overwrite the existing SSL certificate? (y/N) ")
if not answer.lower().startswith("y"):
if not self.overwrite_existing_certificate():
return
utils.printcolor(
"Generating new self-signed certificate", utils.YELLOW)
@@ -48,6 +58,40 @@ class SelfSignedCertificate(CertificateBackend):
)
class LetsEncryptCertificate(CertificateBackend):
"""Create a certificate using letsencrypt."""
def create(self):
"""Create a certificate."""
utils.printcolor(
"Generating new certificate using letsencrypt", utils.YELLOW)
hostname = self.config.get("general", "hostname")
utils.exec_cmd(
"wget https://dl.eff.org/certbot-auto; chmod a+x certbot-auto",
cwd="/opt")
webroot = os.path.join(
self.config.get("modoboa", "instance_path"),
"sitestatic/.well-known")
utils.exec_cmd(
"/opt/certbot-auto certonly -n --standalone -d {} "
"-m {} --agree-tos".format(
webroot, hostname, self.config.get("letsencrypt", "email")))
self.config.set("general", "tls_cert_file", (
"/etc/letsencrypt/live/{}/fullchain.pem".format(hostname)))
self.config.set("general", "tls_key_file", (
"/etc/letsencrypt/live/{}/privkey.pem".format(hostname)))
with open("/etc/cron.d/letsencrypt", "w") as fp:
fp.write("0 */12 * * * root /opt/certbot-auto renew "
"--quiet --no-self-upgrade && "
"service nginx reload && "
"service postfix reload && "
"service dovecot reload")
def get_backend(config):
"""Return the appropriate backend."""
if not config.getboolean("certificate", "generate"):
return None
if config.get("certificate", "type") == "letsencrypt":
return LetsEncryptCertificate(config)
return SelfSignedCertificate(config)

7
run.py
View File

@@ -39,7 +39,8 @@ def main():
.format(args.hostname), utils.BLUE)
components = []
for section in config.sections():
if section in ["general", "database", "mysql", "postgres"]:
if section in ["general", "database", "mysql", "postgres",
"certificate", "letsencrypt"]:
continue
if (config.has_option(section, "enabled") and
not config.getboolean(section, "enabled")):
@@ -56,7 +57,9 @@ def main():
"and come back later ;)", utils.BLUE)
utils.printcolor("Starting...", utils.GREEN)
package.backend.install("sudo")
ssl.get_backend(config).create()
ssl_backend = ssl.get_backend(config)
if ssl_backend:
ssl_backend.create()
scripts.install("modoboa", config)
scripts.install("postfix", config)
scripts.install("amavis", config)