summaryrefslogtreecommitdiffstats
path: root/keystone/common
diff options
context:
space:
mode:
authorJamie Lennox <jlennox@redhat.com>2013-04-04 17:44:01 +1000
committerJamie Lennox <jlennox@redhat.com>2013-04-11 14:41:15 +1000
commit28ef9cdcc6073c2f6600d30b401dcbce81afd4df (patch)
tree954fa9f9dce47b8b320ceb3fca3f6c8a83855c9d /keystone/common
parentcbac77110ee1d7b9abc5a23f973dab27e8b32015 (diff)
Generate HTTPS certificates with ssl_setup.
Extracts common OpenSSL functionality from pki_setup and adds a new cli command ssl_setup which re-uses this base to generate SSL certificates for https. Change-Id: Ia34827583bcdfbd871133250681010e642271f07 Fixes: bug 1155361
Diffstat (limited to 'keystone/common')
-rw-r--r--keystone/common/config.py20
-rw-r--r--keystone/common/openssl.py173
2 files changed, 119 insertions, 74 deletions
diff --git a/keystone/common/config.py b/keystone/common/config.py
index f749300d..a4fa4901 100644
--- a/keystone/common/config.py
+++ b/keystone/common/config.py
@@ -217,10 +217,20 @@ def configure():
# ssl
register_bool('enable', group='ssl', default=False)
- register_str('certfile', group='ssl', default=None)
- register_str('keyfile', group='ssl', default=None)
- register_str('ca_certs', group='ssl', default=None)
+ register_str('certfile', group='ssl',
+ default="/etc/keystone/ssl/certs/keystone.pem")
+ register_str('keyfile', group='ssl',
+ default="/etc/keystone/ssl/private/keystonekey.pem")
+ register_str('ca_certs', group='ssl',
+ default="/etc/keystone/ssl/certs/ca.pem")
+ register_str('ca_key', group='ssl',
+ default="/etc/keystone/ssl/certs/cakey.pem")
register_bool('cert_required', group='ssl', default=False)
+ register_int('key_size', group='ssl', default=1024)
+ register_int('valid_days', group='ssl', default=3650)
+ register_str('ca_password', group='ssl', default=None)
+ register_str('cert_subject', group='ssl',
+ default='/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost')
# signing
register_str(
@@ -237,9 +247,13 @@ def configure():
'ca_certs',
group='signing',
default="/etc/keystone/ssl/certs/ca.pem")
+ register_str('ca_key', group='signing',
+ default="/etc/keystone/ssl/certs/cakey.pem")
register_int('key_size', group='signing', default=1024)
register_int('valid_days', group='signing', default=3650)
register_str('ca_password', group='signing', default=None)
+ register_str('cert_subject', group='signing',
+ default='/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com')
# sql
register_str('connection', group='sql', secret=True,
diff --git a/keystone/common/openssl.py b/keystone/common/openssl.py
index d4dc3af0..dd31fb71 100644
--- a/keystone/common/openssl.py
+++ b/keystone/common/openssl.py
@@ -29,41 +29,34 @@ DIR_PERMS = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
stat.S_IROTH | stat.S_IXOTH)
CERT_PERMS = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
PRIV_PERMS = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
-DEFAULT_SUBJECT = '/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com'
def file_exists(file_path):
return os.path.exists(file_path)
-class ConfigurePKI(object):
- """Generate files for PKI signing using OpenSSL.
-
- Signed tokens require a private key and signing certificate which itself
- must be signed by a CA. This class generates them with workable defaults
- if each of the files are not present
-
- """
+class BaseCertificateConfigure(object):
+ """Create a certificate signing environment from a config section
+ and reasonable OpenSSL defaults"""
- def __init__(self, keystone_user, keystone_group, **kw):
- self.conf_dir = os.path.dirname(CONF.signing.ca_certs)
+ def __init__(self, conf_obj, keystone_user, keystone_group, **kwargs):
+ self.conf_dir = os.path.dirname(conf_obj.ca_certs)
self.use_keystone_user = keystone_user
self.use_keystone_group = keystone_group
self.ssl_config_file_name = os.path.join(self.conf_dir, "openssl.conf")
- self.ca_key_file = os.path.join(self.conf_dir, "cakey.pem")
self.request_file_name = os.path.join(self.conf_dir, "req.pem")
self.ssl_dictionary = {'conf_dir': self.conf_dir,
- 'ca_cert': CONF.signing.ca_certs,
+ 'ca_cert': conf_obj.ca_certs,
'ssl_config': self.ssl_config_file_name,
- 'ca_private_key': self.ca_key_file,
- 'ca_cert_cn': 'hostname',
+ 'ca_private_key': conf_obj.ca_key,
'request_file': self.request_file_name,
- 'signing_key': CONF.signing.keyfile,
- 'signing_cert': CONF.signing.certfile,
- 'default_subject': DEFAULT_SUBJECT,
- 'key_size': int(CONF.signing.key_size),
- 'valid_days': int(CONF.signing.valid_days),
- 'ca_password': CONF.signing.ca_password}
+ 'signing_key': conf_obj.keyfile,
+ 'signing_cert': conf_obj.certfile,
+ 'key_size': int(conf_obj.key_size),
+ 'valid_days': int(conf_obj.valid_days),
+ 'cert_subject': conf_obj.cert_subject,
+ 'ca_password': conf_obj.ca_password}
+ self.ssl_dictionary.update(kwargs)
def _make_dirs(self, file_name):
dir = os.path.dirname(file_name)
@@ -106,20 +99,25 @@ class ConfigurePKI(object):
self._set_permissions(self.ssl_config_file_name, PRIV_PERMS)
def build_ca_cert(self):
- if not file_exists(CONF.signing.ca_certs):
- if not os.path.exists(self.ca_key_file):
- self._make_dirs(self.ca_key_file)
- self.exec_command('openssl genrsa -out %(ca_private_key)s '
- '%(key_size)d -config %(ssl_config)s')
- self._set_permissions(self.ssl_dictionary['ca_private_key'],
- stat.S_IRUSR)
+ ca_key_file = self.ssl_dictionary['ca_private_key']
+ ca_cert = self.ssl_dictionary['ca_cert']
+
+ if not file_exists(ca_key_file):
+ self._make_dirs(ca_key_file)
+ self.exec_command('openssl genrsa -out %(ca_private_key)s '
+ '%(key_size)d')
+ self._set_permissions(self.ssl_dictionary['ca_private_key'],
+ stat.S_IRUSR)
+
+ if not file_exists(ca_cert):
+ self._make_dirs(ca_cert)
self.exec_command('openssl req -new -x509 -extensions v3_ca '
'-passin pass:%(ca_password)s '
'-key %(ca_private_key)s -out %(ca_cert)s '
'-days %(valid_days)d '
'-config %(ssl_config)s '
- '-subj %(default_subject)s')
- self._set_permissions(self.ssl_dictionary['ca_cert'], CERT_PERMS)
+ '-subj %(cert_subject)s')
+ self._set_permissions(ca_cert, CERT_PERMS)
def build_private_key(self):
signing_keyfile = self.ssl_dictionary['signing_key']
@@ -128,19 +126,23 @@ class ConfigurePKI(object):
self._make_dirs(signing_keyfile)
self.exec_command('openssl genrsa -out %(signing_key)s '
- '%(key_size)d '
- '-config %(ssl_config)s')
+ '%(key_size)d ')
self._set_permissions(os.path.dirname(signing_keyfile), PRIV_PERMS)
self._set_permissions(signing_keyfile, stat.S_IRUSR)
def build_signing_cert(self):
- if not file_exists(CONF.signing.certfile):
- self._make_dirs(CONF.signing.certfile)
+ signing_cert = self.ssl_dictionary['signing_cert']
+
+ if not file_exists(signing_cert):
+ self._make_dirs(signing_cert)
+
self.exec_command('openssl req -key %(signing_key)s -new -nodes '
'-out %(request_file)s -config %(ssl_config)s '
- '-subj %(default_subject)s')
+ '-subj %(cert_subject)s')
+
self.exec_command('openssl ca -batch -out %(signing_cert)s '
- '-config %(ssl_config)s '
+ '-config %(ssl_config)s -days %(valid_days)dd '
+ '-cert %(ca_cert)s -keyfile %(ca_private_key)s '
'-infiles %(request_file)s')
def run(self):
@@ -149,13 +151,41 @@ class ConfigurePKI(object):
self.build_private_key()
self.build_signing_cert()
- sslconfig = """
+
+class ConfigurePKI(BaseCertificateConfigure):
+ """Generate files for PKI signing using OpenSSL.
+
+ Signed tokens require a private key and signing certificate which itself
+ must be signed by a CA. This class generates them with workable defaults
+ if each of the files are not present
+
+ """
+
+ def __init__(self, keystone_user, keystone_group):
+ super(ConfigurePKI, self).__init__(CONF.signing,
+ keystone_user, keystone_group)
+
+
+class ConfigureSSL(BaseCertificateConfigure):
+ """Generate files for HTTPS using OpenSSL.
+
+ Creates a public/private key and certificates. If a CA is not given
+ one will be generated using provided arguments.
+ """
+
+ def __init__(self, keystone_user, keystone_group):
+ super(ConfigureSSL, self).__init__(CONF.ssl,
+ keystone_user, keystone_group)
+
+
+BaseCertificateConfigure.sslconfig = """
# OpenSSL configuration file.
#
# Establish working directory.
dir = %(conf_dir)s
+
[ ca ]
default_ca = CA_default
@@ -163,55 +193,56 @@ default_ca = CA_default
new_certs_dir = $dir
serial = $dir/serial
database = $dir/index.txt
-certificate = %(ca_cert)s
-private_key = %(ca_private_key)s
default_days = 365
-default_md = md5
+default_md = sha1
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
-policy = policy_match
-[ policy_match ]
-countryName = match
-stateOrProvinceName = match
-organizationName = match
+policy = policy_anything
+x509_extensions = usr_cert
+unique_subject = no
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
-default_bits = 1024 # Size of keys
-default_keyfile = key.pem # name of generated keys
-default_md = md5 # message digest algorithm
+default_bits = 1024 # Size of keys
+default_keyfile = key.pem # name of generated keys
+default_md = default # message digest algorithm
string_mask = nombstr # permitted characters
-distinguished_name = req_distinguished_name
-req_extensions = v3_req
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
[ req_distinguished_name ]
-0.organizationName = Organization Name (company)
-organizationalUnitName = Organizational Unit Name (department, division)
-emailAddress = Email Address
-emailAddress_max = 40
-localityName = Locality Name (city, district)
-stateOrProvinceName = State or Province Name (full name)
-countryName = Country Name (2 letter code)
-countryName_min = 2
-countryName_max = 2
-commonName = Common Name (hostname, IP, or your name)
-commonName_max = 64
-# Default values for the above, for consistency and less typing.
-0.organizationName_default = Openstack, Inc
-localityName_default = Undefined
-stateOrProvinceName_default = Undefined
-countryName_default = US
-commonName_default = %(ca_cert_cn)s
+0.organizationName = Organization Name (company)
+organizationalUnitName = Organizational Unit Name (department, division)
+emailAddress = Email Address
+emailAddress_max = 40
+localityName = Locality Name (city, district)
+stateOrProvinceName = State or Province Name (full name)
+countryName = Country Name (2 letter code)
+countryName_min = 2
+countryName_max = 2
+commonName = Common Name (hostname, IP, or your name)
+commonName_max = 64
[ v3_ca ]
-basicConstraints = CA:TRUE
-subjectKeyIdentifier = hash
+basicConstraints = CA:TRUE
+subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
-basicConstraints = CA:FALSE
-subjectKeyIdentifier = hash"""
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+
+[ usr_cert ]
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+"""