Removed the deprecated pki_setup command
bp removed-as-of-pike Change-Id: Ib39d21ed547e3be7a3a2c333a7193f990043a80b
This commit is contained in:
parent
30faacc5d0
commit
928d23db02
@ -949,29 +949,6 @@ If your certificate directory path is different from the default
|
||||
section of the configuration file.
|
||||
|
||||
|
||||
Generating a Signing Certificate using ``pki_setup``
|
||||
----------------------------------------------------
|
||||
|
||||
``keystone-manage pki_setup`` is a development tool. We recommend that you do
|
||||
not use ``keystone-manage pki_setup`` in a production environment. In
|
||||
production, an external CA should be used instead. This is because the CA
|
||||
secret key should generally be kept apart from the token signing secret keys so
|
||||
that a compromise of a node does not lead to an attacker being able to generate
|
||||
valid signed keystone tokens. This is a low probability attack vector, as
|
||||
compromise of a keystone service machine's filesystem security almost certainly
|
||||
means the attacker will be able to gain direct access to the token backend.
|
||||
|
||||
When using the ``keystone-manage pki_setup`` to generate the certificates, the
|
||||
following configuration options in the ``[signing]`` section are used:
|
||||
|
||||
* ``ca_key`` - Default is ``/etc/keystone/ssl/private/cakey.pem``
|
||||
* ``key_size`` - Default is ``2048``
|
||||
* ``valid_days`` - Default is ``3650``
|
||||
|
||||
If ``keystone-manage pki_setup`` is not used then these options don't need to
|
||||
be set.
|
||||
|
||||
|
||||
Service Catalog
|
||||
===============
|
||||
|
||||
|
@ -22,6 +22,5 @@ Available commands:
|
||||
* ``mapping_populate``: Prepare domain-specific LDAP backend.
|
||||
* ``mapping_purge``: Purge the identity mapping table.
|
||||
* ``mapping_engine``: Test your federation mapping rules.
|
||||
* ``pki_setup``: Initialize the certificates used to sign revocation lists. **deprecated**
|
||||
* ``saml_idp_metadata``: Generate identity provider metadata.
|
||||
* ``token_flush``: Purge expired tokens.
|
||||
|
@ -30,7 +30,6 @@ import pbr.version
|
||||
from keystone.cmd import doctor
|
||||
from keystone.common import driver_hints
|
||||
from keystone.common import fernet_utils
|
||||
from keystone.common import openssl
|
||||
from keystone.common import sql
|
||||
from keystone.common.sql import upgrades
|
||||
from keystone.common import utils
|
||||
@ -582,44 +581,6 @@ class BasePermissionsSetup(BaseApp):
|
||||
return keystone_user_id, keystone_group_id
|
||||
|
||||
|
||||
class BaseCertificateSetup(BasePermissionsSetup):
|
||||
"""Provides common options for certificate setup."""
|
||||
|
||||
@classmethod
|
||||
def add_argument_parser(cls, subparsers):
|
||||
parser = super(BaseCertificateSetup,
|
||||
cls).add_argument_parser(subparsers)
|
||||
parser.add_argument('--rebuild', default=False, action='store_true',
|
||||
help=('Rebuild certificate files: erase previous '
|
||||
'files and regenerate them.'))
|
||||
return parser
|
||||
|
||||
|
||||
class PKISetup(BaseCertificateSetup):
|
||||
"""Setup keys and certificates for signing and verifying revocation lists.
|
||||
|
||||
This is NOT intended for production use, see Keystone Configuration
|
||||
documentation for details. As of the Mitaka release, this command has
|
||||
been DEPRECATED and may be removed in the 'O' release.
|
||||
"""
|
||||
|
||||
name = 'pki_setup'
|
||||
|
||||
@classmethod
|
||||
def main(cls):
|
||||
versionutils.report_deprecated_feature(
|
||||
LOG,
|
||||
"keystone-manage pki_setup is deprecated as of Mitaka in "
|
||||
"favor of not using PKI tokens and may be removed in 'O' "
|
||||
"release.")
|
||||
LOG.warning('keystone-manage pki_setup is not recommended for '
|
||||
'production use.')
|
||||
keystone_user_id, keystone_group_id = cls.get_user_group()
|
||||
conf_pki = openssl.ConfigurePKI(keystone_user_id, keystone_group_id,
|
||||
rebuild=CONF.command.rebuild)
|
||||
conf_pki.run()
|
||||
|
||||
|
||||
class FernetSetup(BasePermissionsSetup):
|
||||
"""Setup a key repository for Fernet tokens.
|
||||
|
||||
@ -1336,7 +1297,6 @@ CMDS = [
|
||||
MappingPopulate,
|
||||
MappingPurge,
|
||||
MappingEngineTester,
|
||||
PKISetup,
|
||||
SamlIdentityProviderMetadata,
|
||||
TokenFlush,
|
||||
]
|
||||
|
@ -1,324 +0,0 @@
|
||||
# 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
|
||||
import subprocess # nosec : see comments in the code below
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from keystone.common import utils
|
||||
import keystone.conf
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
CONF = keystone.conf.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-----
|
||||
|
||||
|
||||
def file_exists(file_path):
|
||||
return os.path.exists(file_path)
|
||||
|
||||
|
||||
class BaseCertificateConfigure(object):
|
||||
"""Create a certificate signing environment.
|
||||
|
||||
This is based on a config section and reasonable OpenSSL defaults.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, conf_obj, keystone_user,
|
||||
keystone_group, rebuild, **kwargs):
|
||||
self.conf_dir = os.path.dirname(conf_obj.ca_certs)
|
||||
self.use_keystone_user = keystone_user
|
||||
self.use_keystone_group = keystone_group
|
||||
self.rebuild = rebuild
|
||||
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,
|
||||
# older versions do not
|
||||
openssl_ver = subprocess.check_output( # nosec : the arguments
|
||||
# are hardcoded and just check the openssl version
|
||||
['openssl', 'version'])
|
||||
if b'OpenSSL 0.' in openssl_ver:
|
||||
self.ssl_dictionary['default_md'] = 'sha1'
|
||||
except subprocess.CalledProcessError:
|
||||
LOG.warning('Failed to invoke ``openssl version``, '
|
||||
'assuming is v1.0 or newer')
|
||||
self.ssl_dictionary.update(kwargs)
|
||||
|
||||
def exec_command(self, command):
|
||||
to_exec = [part % self.ssl_dictionary for part in command]
|
||||
LOG.info('Running command - %s', ' '.join(to_exec))
|
||||
try:
|
||||
# NOTE(shaleh): use check_output instead of the simpler
|
||||
# `check_call()` in order to log any output from an error.
|
||||
subprocess.check_output( # nosec : the arguments being passed
|
||||
# in are defined in this file and trusted to build CAs, keys
|
||||
# and certs
|
||||
to_exec,
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
msg = ("Command %(to_exec)s exited with %(retcode)s - "
|
||||
"%(output)s)")
|
||||
LOG.error(msg,
|
||||
{'to_exec': to_exec,
|
||||
'retcode': e.returncode,
|
||||
'output': e.output})
|
||||
raise
|
||||
|
||||
def clean_up_existing_files(self):
|
||||
files_to_clean = [self.ssl_dictionary['ca_private_key'],
|
||||
self.ssl_dictionary['ca_cert'],
|
||||
self.ssl_dictionary['signing_key'],
|
||||
self.ssl_dictionary['signing_cert'],
|
||||
]
|
||||
|
||||
existing_files = []
|
||||
|
||||
for file_path in files_to_clean:
|
||||
if file_exists(file_path):
|
||||
if self.rebuild:
|
||||
# The file exists but the user wants to rebuild it, so blow
|
||||
# it away
|
||||
try:
|
||||
os.remove(file_path)
|
||||
except OSError as exc:
|
||||
msg = ("Failed to remove file %(file_path)r: "
|
||||
"%(error)s")
|
||||
LOG.error(msg,
|
||||
{'file_path': file_path,
|
||||
'error': exc.strerror})
|
||||
raise
|
||||
else:
|
||||
existing_files.append(file_path)
|
||||
|
||||
return existing_files
|
||||
|
||||
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):
|
||||
with open(self.ssl_config_file_name, 'w') as ssl_config_file:
|
||||
ssl_config_file.write(self.sslconfig % self.ssl_dictionary)
|
||||
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):
|
||||
with open(index_file_name, 'w') as index_file:
|
||||
index_file.write('')
|
||||
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):
|
||||
with open(serial_file_name, 'w') as index_file:
|
||||
index_file.write('01')
|
||||
utils.set_permissions(serial_file_name,
|
||||
mode=PRIVATE_FILE_PERMS,
|
||||
user=self.use_keystone_user,
|
||||
group=self.use_keystone_group, log=LOG)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)d',
|
||||
'-cert', '%(ca_cert)s',
|
||||
'-keyfile', '%(ca_private_key)s',
|
||||
'-infiles', '%(request_file)s'])
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
existing_files = self.clean_up_existing_files()
|
||||
except OSError:
|
||||
print('An error occurred when rebuilding cert files.')
|
||||
return
|
||||
if existing_files:
|
||||
print('The following cert files already exist, use --rebuild to '
|
||||
'remove the existing files before regenerating:')
|
||||
for f in existing_files:
|
||||
print('%s already exists' % f)
|
||||
return
|
||||
|
||||
self.build_ssl_config_file()
|
||||
self.build_ca_cert()
|
||||
self.build_private_key()
|
||||
self.build_signing_cert()
|
||||
|
||||
|
||||
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, rebuild=False):
|
||||
super(ConfigurePKI, self).__init__(CONF.signing, keystone_user,
|
||||
keystone_group, rebuild=rebuild)
|
||||
|
||||
|
||||
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
|
||||
"""
|
@ -11,14 +11,23 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import versionutils
|
||||
|
||||
from keystone.conf import constants
|
||||
from keystone.conf import utils
|
||||
|
||||
|
||||
_DEPRECATED_MSG = utils.fmt("""
|
||||
`keystone-manage pki_setup` was deprecated in Mitaka and removed in Pike.
|
||||
These options remain for backwards compatibility.
|
||||
""")
|
||||
|
||||
certfile = cfg.StrOpt(
|
||||
'certfile',
|
||||
default=constants._CERTFILE,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
Absolute path to the public certificate file to use for signing responses to
|
||||
revocation lists requests. Set this together with `[signing] keyfile`. For
|
||||
@ -29,6 +38,9 @@ pki_setup` to generate self-signed certificates.
|
||||
keyfile = cfg.StrOpt(
|
||||
'keyfile',
|
||||
default=constants._KEYFILE,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
Absolute path to the private key file to use for signing responses to
|
||||
revocation lists requests. Set this together with `[signing] certfile`.
|
||||
@ -36,6 +48,9 @@ revocation lists requests. Set this together with `[signing] certfile`.
|
||||
|
||||
ca_certs = cfg.StrOpt(
|
||||
'ca_certs',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
default='/etc/keystone/ssl/certs/ca.pem',
|
||||
help=utils.fmt("""
|
||||
Absolute path to the public certificate authority (CA) file to use when
|
||||
@ -48,6 +63,9 @@ you are requesting revocation lists in a non-production environment. Use a
|
||||
ca_key = cfg.StrOpt(
|
||||
'ca_key',
|
||||
default='/etc/keystone/ssl/private/cakey.pem',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
Absolute path to the private certificate authority (CA) key file to use when
|
||||
creating self-signed certificates with `keystone-manage pki_setup`. Set this
|
||||
@ -60,6 +78,9 @@ key_size = cfg.IntOpt(
|
||||
'key_size',
|
||||
default=2048,
|
||||
min=1024,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
Key size (in bits) to use when generating a self-signed token signing
|
||||
certificate. There is no reason to set this option unless you are requesting
|
||||
@ -70,6 +91,9 @@ issued from a trusted certificate authority instead.
|
||||
valid_days = cfg.IntOpt(
|
||||
'valid_days',
|
||||
default=3650,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
The validity period (in days) to use when generating a self-signed token
|
||||
signing certificate. There is no reason to set this option unless you are
|
||||
@ -80,6 +104,9 @@ requesting revocation lists in a non-production environment. Use a
|
||||
cert_subject = cfg.StrOpt(
|
||||
'cert_subject',
|
||||
default=('/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com'),
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_DEPRECATED_MSG,
|
||||
deprecated_since=versionutils.deprecated.PIKE,
|
||||
help=utils.fmt("""
|
||||
The certificate subject to use when generating a self-signed token signing
|
||||
certificate. There is no reason to set this option unless you are requesting
|
||||
|
@ -1,183 +0,0 @@
|
||||
# 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
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
import mock
|
||||
from six.moves import http_client
|
||||
from testtools import matchers
|
||||
|
||||
from keystone.common import openssl
|
||||
from keystone.tests import unit
|
||||
from keystone.tests.unit import ksfixtures
|
||||
from keystone.tests.unit import rest
|
||||
|
||||
|
||||
SSLDIR = unit.dirs.tmp('ssl')
|
||||
CONF = unit.CONF
|
||||
|
||||
|
||||
CERTDIR = os.path.join(SSLDIR, 'certs')
|
||||
KEYDIR = os.path.join(SSLDIR, 'private')
|
||||
|
||||
|
||||
class CertSetupTestCase(rest.RestfulTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CertSetupTestCase, self).setUp()
|
||||
|
||||
def cleanup_ssldir():
|
||||
try:
|
||||
shutil.rmtree(SSLDIR)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
self.addCleanup(cleanup_ssldir)
|
||||
|
||||
def config_overrides(self):
|
||||
super(CertSetupTestCase, self).config_overrides()
|
||||
ca_certs = os.path.join(CERTDIR, 'ca.pem')
|
||||
ca_key = os.path.join(CERTDIR, 'cakey.pem')
|
||||
|
||||
self.config_fixture.config(
|
||||
group='signing',
|
||||
certfile=os.path.join(CERTDIR, 'signing_cert.pem'),
|
||||
ca_certs=ca_certs,
|
||||
ca_key=ca_key,
|
||||
keyfile=os.path.join(KEYDIR, 'signing_key.pem'))
|
||||
self.config_fixture.config(group='token', provider='fernet')
|
||||
self.useFixture(
|
||||
ksfixtures.KeyRepository(
|
||||
self.config_fixture,
|
||||
'fernet_tokens',
|
||||
CONF.fernet_tokens.max_active_keys
|
||||
)
|
||||
)
|
||||
|
||||
def test_create_pki_certs(self, rebuild=False):
|
||||
pki = openssl.ConfigurePKI(None, None, rebuild=rebuild)
|
||||
pki.run()
|
||||
self.assertTrue(os.path.exists(CONF.signing.certfile))
|
||||
self.assertTrue(os.path.exists(CONF.signing.ca_certs))
|
||||
self.assertTrue(os.path.exists(CONF.signing.keyfile))
|
||||
|
||||
def test_fetch_signing_cert(self, rebuild=False):
|
||||
pki = openssl.ConfigurePKI(None, None, rebuild=rebuild)
|
||||
pki.run()
|
||||
|
||||
# NOTE(jamielennox): Use request directly because certificate
|
||||
# requests don't have some of the normal information
|
||||
signing_resp = self.request(self.public_app,
|
||||
'/v2.0/certificates/signing',
|
||||
method='GET',
|
||||
expected_status=http_client.OK)
|
||||
|
||||
cacert_resp = self.request(self.public_app,
|
||||
'/v2.0/certificates/ca',
|
||||
method='GET',
|
||||
expected_status=http_client.OK)
|
||||
|
||||
with open(CONF.signing.certfile) as f:
|
||||
self.assertEqual(f.read(), signing_resp.text)
|
||||
|
||||
with open(CONF.signing.ca_certs) as f:
|
||||
self.assertEqual(f.read(), cacert_resp.text)
|
||||
|
||||
# NOTE(jamielennox): This is weird behaviour that we need to enforce.
|
||||
# It doesn't matter what you ask for it's always going to give text
|
||||
# with a text/html content_type.
|
||||
|
||||
for path in ['/v2.0/certificates/signing', '/v2.0/certificates/ca']:
|
||||
for accept in [None, 'text/html', 'application/json', 'text/xml']:
|
||||
headers = {'Accept': accept} if accept else {}
|
||||
resp = self.request(self.public_app, path, method='GET',
|
||||
expected_status=http_client.OK,
|
||||
headers=headers)
|
||||
|
||||
self.assertEqual('text/html', resp.content_type)
|
||||
|
||||
def test_fetch_signing_cert_when_rebuild(self):
|
||||
pki = openssl.ConfigurePKI(None, None)
|
||||
pki.run()
|
||||
self.test_fetch_signing_cert(rebuild=True)
|
||||
|
||||
def test_failure(self):
|
||||
for path in ['/v2.0/certificates/signing', '/v2.0/certificates/ca']:
|
||||
self.request(self.public_app, path, method='GET',
|
||||
expected_status=http_client.INTERNAL_SERVER_ERROR)
|
||||
|
||||
def test_pki_certs_rebuild(self):
|
||||
self.test_create_pki_certs()
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file1 = f.read()
|
||||
|
||||
self.test_create_pki_certs(rebuild=True)
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file2 = f.read()
|
||||
|
||||
self.assertNotEqual(cert_file1, cert_file2)
|
||||
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_rebuild_pki_certs_remove_error(self, mock_remove):
|
||||
self.test_create_pki_certs()
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file1 = f.read()
|
||||
|
||||
mock_remove.side_effect = OSError()
|
||||
self.test_create_pki_certs(rebuild=True)
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file2 = f.read()
|
||||
|
||||
self.assertEqual(cert_file1, cert_file2)
|
||||
|
||||
def test_create_pki_certs_twice_without_rebuild(self):
|
||||
self.test_create_pki_certs()
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file1 = f.read()
|
||||
|
||||
self.test_create_pki_certs()
|
||||
with open(CONF.signing.certfile) as f:
|
||||
cert_file2 = f.read()
|
||||
|
||||
self.assertEqual(cert_file1, cert_file2)
|
||||
|
||||
|
||||
class TestExecCommand(unit.TestCase):
|
||||
|
||||
@mock.patch.object(subprocess.Popen, 'poll')
|
||||
def test_running_a_successful_command(self, mock_poll):
|
||||
mock_poll.return_value = 0
|
||||
|
||||
ssl = openssl.ConfigurePKI('keystone_user', 'keystone_group')
|
||||
ssl.exec_command(['ls'])
|
||||
|
||||
@mock.patch.object(subprocess, 'check_output')
|
||||
def test_running_an_invalid_command(self, mock_check_output):
|
||||
cmd = ['ls']
|
||||
|
||||
output = 'this is the output string'
|
||||
|
||||
error = subprocess.CalledProcessError(returncode=1,
|
||||
cmd=cmd,
|
||||
output=output)
|
||||
mock_check_output.side_effect = error
|
||||
|
||||
ssl = openssl.ConfigurePKI('keystone_user', 'keystone_group')
|
||||
e = self.assertRaises(subprocess.CalledProcessError,
|
||||
ssl.exec_command,
|
||||
cmd)
|
||||
self.assertThat(e.output, matchers.Equals(output))
|
@ -31,3 +31,8 @@ other:
|
||||
The ``keystone.common.ldap`` module was removed from the code tree. It was
|
||||
deprecated in the Newton release in favor of using
|
||||
``keystone.identity.backends.ldap.common`` which has the same functionality.
|
||||
- >
|
||||
[`blueprint removed-as-of-pike <https://blueprints.launchpad.net/keystone/+spec/removed-as-of-pike>`_]
|
||||
The ``keystone-manage pki_setup`` was added to aid developer setup by hiding the sometimes cryptic
|
||||
openssl commands. This is no longer needed since keystone no longer supports PKI tokens and can no
|
||||
longer serve SSL. This was deprecated in the Mitaka release.
|
||||
|
Loading…
Reference in New Issue
Block a user