¡@

Home 

OpenStack Study: openssl.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright 2012 OpenStack Foundation

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

#

import os

from keystone.common import environment

from keystone.common import utils

from keystone import config

from keystone.openstack.common import log

LOG = log.getLogger(__name__)

CONF = config.CONF

PUBLIC_DIR_PERMS = 0o755 # -rwxr-xr-x

PRIVATE_DIR_PERMS = 0o750 # -rwxr-x---

PUBLIC_FILE_PERMS = 0o644 # -rw-r--r--

PRIVATE_FILE_PERMS = 0o640 # -rw-r-----

**** CubicPower OpenStack Study ****

def file_exists(file_path):

    return os.path.exists(file_path)

**** CubicPower OpenStack Study ****

class BaseCertificateConfigure(object):

"""Create a certificate signing environment.

This is based on a config section and reasonable OpenSSL

**** CubicPower OpenStack Study ****

    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.request_file_name = os.path.join(self.conf_dir, "req.pem")

        self.ssl_dictionary = {'conf_dir': self.conf_dir,

                               'ca_cert': conf_obj.ca_certs,

                               'default_md': 'default',

                               'ssl_config': self.ssl_config_file_name,

                               'ca_private_key': conf_obj.ca_key,

                               'request_file': self.request_file_name,

                               '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}

        try:

            # OpenSSL 1.0 and newer support default_md = default, olders do not

            openssl_ver = environment.subprocess.Popen(

                ['openssl', 'version'],

                stdout=environment.subprocess.PIPE).stdout.read()

            if "OpenSSL 0." in openssl_ver:

                self.ssl_dictionary['default_md'] = 'sha1'

        except OSError:

            LOG.warn('Failed to invoke ``openssl version``, '

                     'assuming is v1.0 or newer')

        self.ssl_dictionary.update(kwargs)

**** CubicPower OpenStack Study ****

    def exec_command(self, command):

        to_exec = []

        for cmd_part in command:

            to_exec.append(cmd_part % self.ssl_dictionary)

        LOG.info(' '.join(to_exec))

        environment.subprocess.check_call(to_exec)

**** CubicPower OpenStack Study ****

    def build_ssl_config_file(self):

        utils.make_dirs(os.path.dirname(self.ssl_config_file_name),

                        mode=PUBLIC_DIR_PERMS,

                        user=self.use_keystone_user,

                        group=self.use_keystone_group, log=LOG)

        if not file_exists(self.ssl_config_file_name):

            ssl_config_file = open(self.ssl_config_file_name, 'w')

            ssl_config_file.write(self.sslconfig % self.ssl_dictionary)

            ssl_config_file.close()

        utils.set_permissions(self.ssl_config_file_name,

                              mode=PRIVATE_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

        index_file_name = os.path.join(self.conf_dir, 'index.txt')

        if not file_exists(index_file_name):

            index_file = open(index_file_name, 'w')

            index_file.write('')

            index_file.close()

        utils.set_permissions(index_file_name,

                              mode=PRIVATE_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

        serial_file_name = os.path.join(self.conf_dir, 'serial')

        if not file_exists(serial_file_name):

            index_file = open(serial_file_name, 'w')

            index_file.write('01')

            index_file.close()

        utils.set_permissions(serial_file_name,

                              mode=PRIVATE_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

**** CubicPower OpenStack Study ****

    def build_ca_cert(self):

        ca_key_file = self.ssl_dictionary['ca_private_key']

        utils.make_dirs(os.path.dirname(ca_key_file),

                        mode=PRIVATE_DIR_PERMS,

                        user=self.use_keystone_user,

                        group=self.use_keystone_group, log=LOG)

        if not file_exists(ca_key_file):

            self.exec_command(['openssl', 'genrsa',

                               '-out', '%(ca_private_key)s',

                               '%(key_size)d'])

        utils.set_permissions(ca_key_file,

                              mode=PRIVATE_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

        ca_cert = self.ssl_dictionary['ca_cert']

        utils.make_dirs(os.path.dirname(ca_cert),

                        mode=PUBLIC_DIR_PERMS,

                        user=self.use_keystone_user,

                        group=self.use_keystone_group, log=LOG)

        if not file_exists(ca_cert):

            self.exec_command(['openssl', 'req', '-new', '-x509',

                               '-extensions', 'v3_ca',

                               '-key', '%(ca_private_key)s',

                               '-out', '%(ca_cert)s',

                               '-days', '%(valid_days)d',

                               '-config', '%(ssl_config)s',

                               '-subj', '%(cert_subject)s'])

        utils.set_permissions(ca_cert,

                              mode=PUBLIC_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

**** CubicPower OpenStack Study ****

    def build_private_key(self):

        signing_keyfile = self.ssl_dictionary['signing_key']

        utils.make_dirs(os.path.dirname(signing_keyfile),

                        mode=PRIVATE_DIR_PERMS,

                        user=self.use_keystone_user,

                        group=self.use_keystone_group, log=LOG)

        if not file_exists(signing_keyfile):

            self.exec_command(['openssl', 'genrsa', '-out', '%(signing_key)s',

                               '%(key_size)d'])

        utils.set_permissions(signing_keyfile,

                              mode=PRIVATE_FILE_PERMS,

                              user=self.use_keystone_user,

                              group=self.use_keystone_group, log=LOG)

**** CubicPower OpenStack Study ****

    def build_signing_cert(self):

        signing_cert = self.ssl_dictionary['signing_cert']

        utils.make_dirs(os.path.dirname(signing_cert),

                        mode=PUBLIC_DIR_PERMS,

                        user=self.use_keystone_user,

                        group=self.use_keystone_group, log=LOG)

        if not file_exists(signing_cert):

            self.exec_command(['openssl', 'req', '-key', '%(signing_key)s',

                               '-new', '-out', '%(request_file)s',

                               '-config', '%(ssl_config)s',

                               '-subj', '%(cert_subject)s'])

            self.exec_command(['openssl', 'ca', '-batch',

                               '-out', '%(signing_cert)s',

                               '-config', '%(ssl_config)s',

                               '-days', '%(valid_days)dd',

                               '-cert', '%(ca_cert)s',

                               '-keyfile', '%(ca_private_key)s',

                               '-infiles', '%(request_file)s'])

**** CubicPower OpenStack Study ****

    def run(self):

        self.build_ssl_config_file()

        self.build_ca_cert()

        self.build_private_key()

        self.build_signing_cert()

**** CubicPower OpenStack Study ****

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

**** CubicPower OpenStack Study ****

    def __init__(self, keystone_user, keystone_group):

        super(ConfigurePKI, self).__init__(CONF.signing,

                                           keystone_user, keystone_group)

**** CubicPower OpenStack Study ****

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.

"""

**** CubicPower OpenStack Study ****

    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

[ CA_default ]

new_certs_dir     = $dir

serial            = $dir/serial

database          = $dir/index.txt

default_days      = 365

default_md        = %(default_md)s

preserve          = no

email_in_dn       = no

nameopt           = default_ca

certopt           = default_ca

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       = 2048 # Size of keys

default_keyfile    = key.pem # name of generated keys

string_mask        = utf8only # permitted characters

distinguished_name = req_distinguished_name

req_extensions     = v3_req

x509_extensions = v3_ca

[ req_distinguished_name ]

countryName                 = Country Name (2 letter code)

countryName_min             = 2

countryName_max             = 2

stateOrProvinceName         = State or Province Name (full name)

localityName                = Locality Name (city, district)

0.organizationName          = Organization Name (company)

organizationalUnitName      = Organizational Unit Name (department, division)

commonName                  = Common Name (hostname, IP, or your name)

commonName_max              = 64

emailAddress                = Email Address

emailAddress_max            = 64

[ v3_ca ]

basicConstraints       = CA:TRUE

subjectKeyIdentifier   = hash

authorityKeyIdentifier = keyid:always,issuer

[ v3_req ]

basicConstraints     = CA:FALSE

keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ usr_cert ]

basicConstraints       = CA:FALSE

subjectKeyIdentifier   = hash

authorityKeyIdentifier = keyid:always

"""