mirror of
https://github.com/certbot/certbot.git
synced 2026-01-23 07:20:55 +03:00
Update method to make server SSL ready
This commit is contained in:
@@ -19,7 +19,6 @@ from letsencrypt.client import le_util
|
||||
from letsencrypt.client import reverter
|
||||
|
||||
from letsencrypt.client.plugins.nginx import dvsni
|
||||
from letsencrypt.client.plugins.nginx import obj
|
||||
from letsencrypt.client.plugins.nginx import parser
|
||||
|
||||
|
||||
@@ -165,7 +164,8 @@ class NginxConfigurator(object):
|
||||
#######################
|
||||
def choose_vhost(self, target_name):
|
||||
"""Chooses a virtual host based on the given domain name. NOTE: This
|
||||
makes the vhost SSL-enabled if it isn't already.
|
||||
makes the vhost SSL-enabled if it isn't already. Follows Nginx's server
|
||||
block selection rules but prefers blocks that are already SSL.
|
||||
|
||||
.. todo:: This should maybe return list if no obvious answer
|
||||
is presented.
|
||||
@@ -200,7 +200,7 @@ class NginxConfigurator(object):
|
||||
if vhost is not None:
|
||||
self.assoc[target_name] = vhost
|
||||
if not vhost.ssl:
|
||||
vhost = self._make_vhost_ssl(vhost)
|
||||
self._make_server_ssl(vhost.filep, vhost.names)
|
||||
|
||||
return vhost
|
||||
|
||||
@@ -276,83 +276,23 @@ class NginxConfigurator(object):
|
||||
|
||||
return all_names
|
||||
|
||||
def _make_vhost_ssl(self, nonssl_vhost): # pylint: disable=too-many-locals
|
||||
"""Makes an ssl_vhost version of a nonssl_vhost.
|
||||
def _make_server_ssl(self, filename, names):
|
||||
"""Makes a server SSL based on server_name and filename by adding
|
||||
a 'listen 443 ssl' directive to the server block.
|
||||
|
||||
Duplicates vhost and adds default ssl options
|
||||
New vhost will reside as (nonssl_vhost.path) + ``IConfig.le_vhost_ext``
|
||||
.. todo:: Maybe this should create a new block instead of modifying
|
||||
the existing one?
|
||||
|
||||
.. note:: This function saves the configuration
|
||||
|
||||
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
|
||||
:type nonssl_vhost:
|
||||
:class:`~letsencrypt.client.plugins.nginx.obj.VirtualHost`
|
||||
|
||||
:returns: SSL vhost
|
||||
:rtype: :class:`~letsencrypt.client.plugins.nginx.obj.VirtualHost`
|
||||
:param str filename: The absolute filename of the config file.
|
||||
:param set names: The server names of the block to add SSL in
|
||||
|
||||
"""
|
||||
avail_fp = nonssl_vhost.filep
|
||||
# Get filepath of new ssl_vhost
|
||||
if avail_fp.endswith(".conf"):
|
||||
ssl_fp = avail_fp[:-(len(".conf"))] + self.config.le_vhost_ext
|
||||
else:
|
||||
ssl_fp = avail_fp + self.config.le_vhost_ext
|
||||
|
||||
# First register the creation so that it is properly removed if
|
||||
# configuration is rolled back
|
||||
self.reverter.register_file_creation(False, ssl_fp)
|
||||
|
||||
try:
|
||||
with open(avail_fp, "r") as orig_file:
|
||||
with open(ssl_fp, "w") as new_file:
|
||||
new_file.write("<IfModule mod_ssl.c>\n")
|
||||
for line in orig_file:
|
||||
new_file.write(line)
|
||||
new_file.write("</IfModule>\n")
|
||||
except IOError:
|
||||
logging.fatal("Error writing/reading to file in _make_vhost_ssl")
|
||||
sys.exit(49)
|
||||
|
||||
self.aug.load()
|
||||
|
||||
ssl_addrs = set()
|
||||
|
||||
# change address to address:443
|
||||
addr_match = "/files%s//* [label()=~regexp('%s')]/arg"
|
||||
ssl_addr_p = self.aug.match(
|
||||
addr_match % (ssl_fp, parser.case_i("VirtualHost")))
|
||||
|
||||
for addr in ssl_addr_p:
|
||||
old_addr = obj.Addr.fromstring(
|
||||
str(self.aug.get(addr)))
|
||||
ssl_addr = old_addr.get_addr_obj("443")
|
||||
self.aug.set(addr, str(ssl_addr))
|
||||
ssl_addrs.add(ssl_addr)
|
||||
|
||||
# Add directives
|
||||
vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" %
|
||||
(ssl_fp, parser.case_i("VirtualHost")))
|
||||
if len(vh_p) != 1:
|
||||
logging.error("Error: should only be one vhost in %s", avail_fp)
|
||||
sys.exit(1)
|
||||
|
||||
self.parser.add_dir(vh_p[0], "SSLCertificateFile",
|
||||
"/etc/ssl/certs/ssl-cert-snakeoil.pem")
|
||||
self.parser.add_dir(vh_p[0], "SSLCertificateKeyFile",
|
||||
"/etc/ssl/private/ssl-cert-snakeoil.key")
|
||||
self.parser.add_dir(vh_p[0], "Include", self.parser.loc["ssl_options"])
|
||||
|
||||
# Log actions and create save notes
|
||||
logging.info("Created an SSL vhost at %s", ssl_fp)
|
||||
self.save_notes += "Created ssl vhost at %s\n" % ssl_fp
|
||||
self.save()
|
||||
|
||||
# We know the length is one because of the assertion above
|
||||
ssl_vhost = self._create_vhost(vh_p[0])
|
||||
self.vhosts.append(ssl_vhost)
|
||||
|
||||
return ssl_vhost
|
||||
self.parser.add_server_directives(
|
||||
filename, names,
|
||||
[['listen', '443 ssl'],
|
||||
['ssl_certificate', '/etc/ssl/certs/ssl-cert-snakeoil.pem'],
|
||||
['ssl_key', '/etc/ssl/private/ssl-cert-snakeoil.key'],
|
||||
['include', self.parser.loc["ssl_options"]]])
|
||||
|
||||
def get_all_certs_keys(self):
|
||||
"""Find all existing keys, certs from configuration.
|
||||
@@ -490,12 +430,12 @@ class NginxConfigurator(object):
|
||||
|
||||
nginx_version = tuple([int(i) for i in version_matches[0].split(".")])
|
||||
|
||||
# nginx <= 0.7.14 has an incompatible SSL configuration format
|
||||
# nginx < 0.8.21 doesn't use default_server
|
||||
if (nginx_version[0] == 0 and
|
||||
(nginx_version[1] < 7 or
|
||||
(nginx_version[1] == 7 and nginx_version[2] < 15))):
|
||||
(nginx_version[1] < 8 or
|
||||
(nginx_version[1] == 8 and nginx_version[2] < 21))):
|
||||
raise errors.LetsEncryptConfiguratorError(
|
||||
"Nginx version not supported")
|
||||
"Nginx version must be 0.8.21+")
|
||||
|
||||
return nginx_version
|
||||
|
||||
|
||||
@@ -103,19 +103,15 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filep, addrs, ssl, enabled, names=None):
|
||||
def __init__(self, filep, addrs, ssl, enabled, names):
|
||||
# pylint: disable=too-many-arguments
|
||||
"""Initialize a VH."""
|
||||
self.filep = filep
|
||||
self.addrs = addrs
|
||||
self.names = set() if names is None else set(names)
|
||||
self.names = names
|
||||
self.ssl = ssl
|
||||
self.enabled = enabled
|
||||
|
||||
def add_name(self, name):
|
||||
"""Add name to vhost."""
|
||||
self.names.add(name)
|
||||
|
||||
def __str__(self):
|
||||
addr_str = ", ".join(str(addr) for addr in self.addrs)
|
||||
return ("file: %s\n"
|
||||
|
||||
@@ -1,27 +1,8 @@
|
||||
ssl_session_cache shared:SSL:1m; # 1MB is ~4000 sessions, if it fills old sessions are dropped
|
||||
ssl_session_timeout 1440m; # Reuse sessions for 24hrs
|
||||
ssl_session_cache shared:SSL:1m;
|
||||
ssl_session_timeout 1440m;
|
||||
|
||||
# Redirect all traffic to SSL
|
||||
server {
|
||||
listen 80 default;
|
||||
server_name www.example.com example.com;
|
||||
access_log off;
|
||||
error_log off;
|
||||
return 301 https://example.com$request_uri;
|
||||
}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
server {
|
||||
listen 443 ssl default_server;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /path/to/bundle.crt;
|
||||
ssl_certificate_key /path/to/private.key;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
# Using list of ciphers from "Bulletproof SSL and TLS"
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 EDH-RSA-DES-CBC3-SHA";
|
||||
|
||||
# Normal stuff below here
|
||||
}
|
||||
# Using list of ciphers from "Bulletproof SSL and TLS"
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 EDH-RSA-DES-CBC3-SHA";
|
||||
|
||||
@@ -264,6 +264,30 @@ class NginxParser(object):
|
||||
except IOError:
|
||||
logging.error("Could not open file for writing: %s" % filename)
|
||||
|
||||
def add_server_directives(self, filename, names, directives):
|
||||
"""Adds directives to a server block whose server_name set is 'names'.
|
||||
|
||||
:param str filename: The absolute filename of the config file
|
||||
:param str names: The server_name to match
|
||||
:param list directives: The directives to add
|
||||
|
||||
"""
|
||||
if len(names) == 0:
|
||||
# Nothing to identify blocks with
|
||||
return False
|
||||
|
||||
def has_server_names(entry):
|
||||
# Checks if a server block has the given names
|
||||
# TODO: Make this work if some of the names are in included files
|
||||
server_names = set()
|
||||
for item in entry:
|
||||
if item[0] == 'server_name':
|
||||
server_names.update((' ').split(item[1]))
|
||||
return server_names == names
|
||||
|
||||
do_for_subarray(self.parsed[filename], lambda x: has_server_names(x),
|
||||
lambda x: x.extend(directives))
|
||||
|
||||
|
||||
def do_for_subarray(entry, condition, func):
|
||||
"""Executes a function for a subarray of a nested array if it matches
|
||||
@@ -291,7 +315,7 @@ def get_best_match(target_name, names):
|
||||
longest wildcard ending with * > regex).
|
||||
|
||||
:param str target_name: The name to match
|
||||
:param list names: The candidate server names
|
||||
:param set names: The candidate server names
|
||||
:returns: Tuple of (type of match, the name that matched)
|
||||
:rtype: tuple
|
||||
|
||||
|
||||
Reference in New Issue
Block a user