1
0
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:
yan
2015-04-10 11:45:05 -07:00
parent 7b72262811
commit 2a9c707dbd
4 changed files with 53 additions and 112 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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";

View File

@@ -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