Browse Source
keystone.common.config is 1200+ lines of super dense, merge-conflict prone, difficult to navigate, and finicky to maintain code. Let's follow nova's lead and break it down into more manageable modules. This patch creates a new Python package, keystone.conf, and moves all of our configuration options into it, mirroring nova's nova.conf package. There are a couple special modules in keystone.conf introduced here as well: - keystone.conf.__init__: This causes all of Keystone options to be registered on import, so consumers of keystone.conf don't have races with config initialization code while trying to use oslo_config.cfg.CONF directly (keystone.conf replaces all uses for oslo_config.cfg.CONF in keystone). - keystone.conf.base: Keystone's [DEFAULT] group options. I'd prefer this to be called 'default.py', but I'm just copying nova's lead here. - keystone.conf.opts: The entry point for oslo.config itself. - keystone.conf.constants: There are a few constants (deprecation messages, default paths, etc) that are used by multiple configuration modules, so they need to live in a common place. Change-Id: Ia3daffe3fef111b42de203762e966cd14d8927e2changes/04/325604/8
157 changed files with 3485 additions and 1539 deletions
@ -0,0 +1,189 @@
|
||||
# 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 logging |
||||
|
||||
from oslo_cache import core as cache |
||||
from oslo_config import cfg |
||||
from oslo_log import log |
||||
import oslo_messaging |
||||
from oslo_middleware import cors |
||||
from osprofiler import opts as profiler |
||||
|
||||
from keystone.conf import assignment |
||||
from keystone.conf import auth |
||||
from keystone.conf import base |
||||
from keystone.conf import catalog |
||||
from keystone.conf import credential |
||||
from keystone.conf import domain_config |
||||
from keystone.conf import endpoint_filter |
||||
from keystone.conf import endpoint_policy |
||||
from keystone.conf import eventlet_server |
||||
from keystone.conf import federation |
||||
from keystone.conf import fernet_tokens |
||||
from keystone.conf import identity |
||||
from keystone.conf import identity_mapping |
||||
from keystone.conf import kvs |
||||
from keystone.conf import ldap |
||||
from keystone.conf import memcache |
||||
from keystone.conf import oauth1 |
||||
from keystone.conf import os_inherit |
||||
from keystone.conf import paste_deploy |
||||
from keystone.conf import policy |
||||
from keystone.conf import resource |
||||
from keystone.conf import revoke |
||||
from keystone.conf import role |
||||
from keystone.conf import saml |
||||
from keystone.conf import shadow_users |
||||
from keystone.conf import signing |
||||
from keystone.conf import token |
||||
from keystone.conf import tokenless_auth |
||||
from keystone.conf import trust |
||||
|
||||
|
||||
CONF = cfg.CONF |
||||
|
||||
|
||||
conf_modules = [ |
||||
assignment, |
||||
auth, |
||||
base, |
||||
catalog, |
||||
credential, |
||||
domain_config, |
||||
endpoint_filter, |
||||
endpoint_policy, |
||||
eventlet_server, |
||||
federation, |
||||
fernet_tokens, |
||||
identity, |
||||
identity_mapping, |
||||
kvs, |
||||
ldap, |
||||
memcache, |
||||
oauth1, |
||||
os_inherit, |
||||
paste_deploy, |
||||
policy, |
||||
resource, |
||||
revoke, |
||||
role, |
||||
saml, |
||||
shadow_users, |
||||
signing, |
||||
token, |
||||
tokenless_auth, |
||||
trust, |
||||
] |
||||
|
||||
|
||||
# Options are registered when keystone.conf is first imported. |
||||
for module in conf_modules: |
||||
module.register_opts(CONF) |
||||
|
||||
|
||||
oslo_messaging.set_transport_defaults(control_exchange='keystone') |
||||
|
||||
|
||||
def set_default_for_default_log_levels(): |
||||
"""Set the default for the default_log_levels option for keystone. |
||||
|
||||
Keystone uses some packages that other OpenStack services don't use that do |
||||
logging. This will set the default_log_levels default level for those |
||||
packages. |
||||
|
||||
This function needs to be called before CONF(). |
||||
|
||||
""" |
||||
extra_log_level_defaults = [ |
||||
'dogpile=INFO', |
||||
'routes=INFO', |
||||
] |
||||
|
||||
log.register_options(CONF) |
||||
log.set_defaults(default_log_levels=log.get_default_log_levels() + |
||||
extra_log_level_defaults) |
||||
|
||||
|
||||
def setup_logging(): |
||||
"""Set up logging for the keystone package.""" |
||||
log.setup(CONF, 'keystone') |
||||
logging.captureWarnings(True) |
||||
|
||||
|
||||
def configure(conf=None): |
||||
if conf is None: |
||||
conf = CONF |
||||
|
||||
conf.register_cli_opt( |
||||
cfg.BoolOpt('standard-threads', default=False, |
||||
help='Do not monkey-patch threading system modules.')) |
||||
conf.register_cli_opt( |
||||
cfg.StrOpt('pydev-debug-host', |
||||
help='Host to connect to for remote debugger.')) |
||||
conf.register_cli_opt( |
||||
cfg.PortOpt('pydev-debug-port', |
||||
help='Port to connect to for remote debugger.')) |
||||
|
||||
for module in conf_modules: |
||||
module.register_opts(conf) |
||||
|
||||
# register any non-default auth methods here (used by extensions, etc) |
||||
auth.setup_authentication() |
||||
|
||||
# add oslo.cache related config options |
||||
cache.configure(conf) |
||||
|
||||
|
||||
def set_external_opts_defaults(): |
||||
"""Update default configuration options for oslo.middleware.""" |
||||
# CORS Defaults |
||||
# TODO(krotscheck): Update with https://review.openstack.org/#/c/285368/ |
||||
cfg.set_defaults(cors.CORS_OPTS, |
||||
allow_headers=['X-Auth-Token', |
||||
'X-Openstack-Request-Id', |
||||
'X-Subject-Token', |
||||
'X-Project-Id', |
||||
'X-Project-Name', |
||||
'X-Project-Domain-Id', |
||||
'X-Project-Domain-Name', |
||||
'X-Domain-Id', |
||||
'X-Domain-Name'], |
||||
expose_headers=['X-Auth-Token', |
||||
'X-Openstack-Request-Id', |
||||
'X-Subject-Token'], |
||||
allow_methods=['GET', |
||||
'PUT', |
||||
'POST', |
||||
'DELETE', |
||||
'PATCH'] |
||||
) |
||||
|
||||
# configure OSprofiler options |
||||
profiler.set_defaults(CONF, enabled=False, trace_sqlalchemy=False) |
||||
|
||||
# Oslo.cache is always enabled by default for request-local caching |
||||
# TODO(morganfainberg): Fix this to not use internal interface when |
||||
# oslo.cache has proper interface to set defaults added. This is is |
||||
# just a bad way to do this. |
||||
opts = cache._opts.list_opts() |
||||
for opt_list in opts: |
||||
if opt_list[0] == 'cache': |
||||
for o in opt_list[1]: |
||||
if o.name == 'enabled': |
||||
o.default = True |
||||
|
||||
|
||||
def set_config_defaults(): |
||||
"""Override all configuration default values for keystone.""" |
||||
set_default_for_default_log_levels() |
||||
set_external_opts_defaults() |
@ -0,0 +1,48 @@
|
||||
# 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. |
||||
|
||||
from oslo_config import cfg |
||||
|
||||
from keystone.conf import utils |
||||
|
||||
|
||||
driver = cfg.StrOpt( |
||||
'driver', |
||||
help=utils.fmt(""" |
||||
Entrypoint for the assignment backend driver in the keystone.assignment |
||||
namespace. Only an SQL driver is supplied. If an assignment driver is not |
||||
specified, the identity driver will choose the assignment driver (driver |
||||
selection based on `[identity]/driver` option is deprecated and will be removed |
||||
in the "O" release). |
||||
""")) |
||||
|
||||
prohibited_implied_role = cfg.ListOpt( |
||||
'prohibited_implied_role', |
||||
default=['admin'], |
||||
help=utils.fmt(""" |
||||
A list of role names which are prohibited from being an implied role. |
||||
""")) |
||||
|
||||
|
||||
GROUP_NAME = __name__.split('.')[-1] |
||||
ALL_OPTS = [ |
||||
driver, |
||||
prohibited_implied_role |
||||
] |
||||
|
||||
|
||||
def register_opts(conf): |
||||
conf.register_opts(ALL_OPTS, group=GROUP_NAME) |
||||
|
||||
|
||||
def list_opts(): |
||||
return {GROUP_NAME: ALL_OPTS} |
@ -0,0 +1,88 @@
|
||||
# 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. |
||||
|
||||
from oslo_config import cfg |
||||
|
||||
from keystone.conf import constants |
||||
from keystone.conf import utils |
||||
|
||||
|
||||
methods = cfg.ListOpt( |
||||
'methods', |
||||
default=constants._DEFAULT_AUTH_METHODS, |
||||
help=utils.fmt(""" |
||||
Allowed authentication methods. |
||||
""")) |
||||
|
||||
password = cfg.StrOpt( # nosec : This is the name of the plugin, not |
||||
'password', # a password that needs to be protected. |
||||
help=utils.fmt(""" |
||||
Entrypoint for the password auth plugin module in the keystone.auth.password |
||||
namespace. |
||||
""")) |
||||
|
||||
token = cfg.StrOpt( |
||||
'token', |
||||
help=utils.fmt(""" |
||||
Entrypoint for the token auth plugin module in the keystone.auth.token |
||||
namespace. |
||||
""")) |
||||
|
||||
# deals with REMOTE_USER authentication |
||||
external = cfg.StrOpt( |
||||
'external', |
||||
help=utils.fmt(""" |
||||
Entrypoint for the external (REMOTE_USER) auth plugin module in the |
||||
keystone.auth.external namespace. Supplied drivers are DefaultDomain and |
||||
Domain. The default driver is DefaultDomain. |
||||
""")) |
||||
|
||||
oauth1 = cfg.StrOpt( |
||||
'oauth1', |
||||
help=utils.fmt(""" |
||||
Entrypoint for the oAuth1.0 auth plugin module in the keystone.auth.oauth1 |
||||
namespace. |
||||
""")) |
||||
|
||||
GROUP_NAME = __name__.split('.')[-1] |
||||
ALL_OPTS = [ |
||||
methods, |
||||
password, |
||||
token, |
||||
external, |
||||
oauth1, |
||||
] |
||||
|
||||
|
||||
def _register_auth_plugin_opt(conf, option): |
||||
conf.register_opt(option, group=GROUP_NAME) |
||||
|
||||
|
||||
def setup_authentication(conf=None): |
||||
"""Register non-default auth methods (used by extensions, etc).""" |
||||
# register any non-default auth methods here (used by extensions, etc) |
||||
if conf is None: |
||||
conf = cfg.CONF |
||||
for method_name in conf.auth.methods: |
||||
if method_name not in constants._DEFAULT_AUTH_METHODS: |
||||
option = cfg.StrOpt(method_name) |
||||
_register_auth_plugin_opt(conf, option) |
||||
|
||||
|
||||
def register_opts(conf): |
||||
conf.register_opts(ALL_OPTS, group=GROUP_NAME) |
||||
|
||||
setup_authentication(conf) |
||||
|
||||
|
||||
def list_opts(): |
||||
return {GROUP_NAME: ALL_OPTS} |
@ -0,0 +1,224 @@
|
||||
# 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. |
||||
|
||||
from oslo_config import cfg |
||||
|
||||
from keystone.conf import utils |
||||
|
||||
|
||||
_DEPRECATE_DII_MSG = utils.fmt(""" |
||||
The option to set domain_id_immutable to false has been deprecated in the M |
||||
release and will be removed in the O release. |
||||
""") |
||||
|
||||
|
||||
admin_token = cfg.StrOpt( |
||||
'admin_token', |
||||
secret=True, |
||||
default=None, |
||||
help=utils.fmt(""" |
||||
A "shared secret" that can be used to bootstrap Keystone. This "token" does not |
||||
represent a user, and carries no explicit authorization. If set to `None`, the |
||||
value is ignored and the `admin_token` log in mechanism is effectively |
||||
disabled. To completely disable `admin_token` in production (highly |
||||
recommended), remove AdminTokenAuthMiddleware from your paste application |
||||
pipelines (for example, in keystone-paste.ini). |
||||
""")) |
||||
|
||||
public_endpoint = cfg.StrOpt( |
||||
'public_endpoint', |
||||
help=utils.fmt(""" |
||||
The base public endpoint URL for Keystone that is advertised to clients (NOTE: |
||||
this does NOT affect how Keystone listens for connections). Defaults to the |
||||
base host URL of the request. E.g. a request to http://server:5000/v3/users |
||||
will default to http://server:5000. You should only need to set this value if |
||||
the base URL contains a path (e.g. /prefix/v3) or the endpoint should be found |
||||
on a different server. |
||||
""")) |
||||
|
||||
admin_endpoint = cfg.StrOpt( |
||||
'admin_endpoint', |
||||
help=utils.fmt(""" |
||||
The base admin endpoint URL for Keystone that is advertised to clients (NOTE: |
||||
this does NOT affect how Keystone listens for connections). Defaults to the |
||||
base host URL of the request. E.g. a request to http://server:35357/v3/users |
||||
will default to http://server:35357. You should only need to set this value if |
||||
the base URL contains a path (e.g. /prefix/v3) or the endpoint should be found |
||||
on a different server. |
||||
""")) |
||||
|
||||
max_project_tree_depth = cfg.IntOpt( |
||||
'max_project_tree_depth', |
||||
default=5, |
||||
help=utils.fmt(""" |
||||
Maximum depth of the project hierarchy, excluding the project acting as a |
||||
domain at the top of the hierarchy. WARNING: setting it to a large value may |
||||
adversely impact performance. |
||||
""")) |
||||
|
||||
max_param_size = cfg.IntOpt( |
||||
'max_param_size', |
||||
default=64, |
||||
help=utils.fmt(""" |
||||
Limit the sizes of user & project ID/names. |
||||
""")) |
||||
|
||||
# we allow tokens to be a bit larger to accommodate PKI |
||||
max_token_size = cfg.IntOpt( |
||||
'max_token_size', |
||||
default=8192, |
||||
help=utils.fmt(""" |
||||
Similar to max_param_size, but provides an exception for token values. |
||||
""")) |
||||
|
||||
member_role_id = cfg.StrOpt( |
||||
'member_role_id', |
||||
default='9fe2ff9ee4384b1894a90878d3e92bab', |
||||
help=utils.fmt(""" |
||||
Similar to the member_role_name option, this represents the default role ID |
||||
used to associate users with their default projects in the v2 API. This will be |
||||
used as the explicit role where one is not specified by the v2 API. |
||||
""")) |
||||
|
||||
member_role_name = cfg.StrOpt( |
||||
'member_role_name', |
||||
default='_member_', |
||||
help=utils.fmt(""" |
||||
This is the role name used in combination with the member_role_id option; see |
||||
that option for more detail. |
||||
""")) |
||||
|
||||
# NOTE(lbragstad/morganfainberg): This value of 10k was measured as having an |
||||
# approximate 30% clock-time savings over the old default of 40k. The passlib |
||||
# default is not static and grows over time to constantly approximate ~300ms of |
||||
# CPU time to hash; this was considered too high. This value still exceeds the |
||||
# glibc default of 5k. |
||||
crypt_strength = cfg.IntOpt( |
||||
'crypt_strength', |
||||
default=10000, |
||||
min=1000, |
||||
max=100000, |
||||
help=utils.fmt(""" |
||||
The value passed as the keyword "rounds" to passlib\'s encrypt method. |
||||
""")) |
||||
|
||||
list_limit = cfg.IntOpt( |
||||
'list_limit', |
||||
help=utils.fmt(""" |
||||
The maximum number of entities that will be returned in a collection, with no |
||||
limit set by default. This global limit may be then overridden for a specific |
||||
driver, by specifying a list_limit in the appropriate section (e.g. |
||||
[assignment]). |
||||
""")) |
||||
|
||||
domain_id_immutable = cfg.BoolOpt( |
||||
'domain_id_immutable', |
||||
default=True, |
||||
deprecated_for_removal=True, |
||||
deprecated_reason=_DEPRECATE_DII_MSG, |
||||
help=utils.fmt(""" |
||||
Set this to false if you want to enable the ability for user, group and project |
||||
entities to be moved between domains by updating their domain_id. Allowing such |
||||
movement is not recommended if the scope of a domain admin is being restricted |
||||
by use of an appropriate policy file (see policy.v3cloudsample as an example). |
||||
This ability is deprecated and will be removed in a future release. |
||||
""")) |
||||
|
||||
strict_password_check = cfg.BoolOpt( |
||||
'strict_password_check', |
||||
default=False, |
||||
help=utils.fmt(""" |
||||
If set to true, strict password length checking is performed for password |
||||
manipulation. If a password exceeds the maximum length, the operation will fail |
||||
with an HTTP 403 Forbidden error. If set to false, passwords are automatically |
||||
truncated to the maximum length. |
||||
""")) |
||||
|
||||
secure_proxy_ssl_header = cfg.StrOpt( |
||||
'secure_proxy_ssl_header', |
||||
default='HTTP_X_FORWARDED_PROTO', |
||||
deprecated_for_removal=True, |
||||
deprecated_reason=utils.fmt(""" |
||||
Use http_proxy_to_wsgi middleware configuration instead. |
||||
"""), |
||||
help=utils.fmt(""" |
||||
The HTTP header used to determine the scheme for the original request, even if |
||||
it was removed by an SSL terminating proxy. |
||||
""")) |
||||
|
||||
insecure_debug = cfg.BoolOpt( |
||||
'insecure_debug', |
||||
default=False, |
||||
help=utils.fmt(""" |
||||
If set to true the server will return information in the response that may |
||||
allow an unauthenticated or authenticated user to get more information than |
||||
normal, such as why authentication failed. This may be useful for debugging but |
||||
is insecure. |
||||
""")) |
||||
|
||||
default_publisher_id = cfg.StrOpt( |
||||
'default_publisher_id', |
||||
help=utils.fmt(""" |
||||
Default publisher_id for outgoing notifications |
||||
""")) |
||||
|
||||
notification_format = cfg.StrOpt( |
||||
'notification_format', |
||||
default='basic', |
||||
choices=['basic', 'cadf'], |
||||
help=utils.fmt(""" |
||||
Define the notification format for Identity Service events. A "basic" |
||||
notification has information about the resource being operated on. A "cadf" |
||||
notification has the same information, as well as information about the |
||||
initiator of the event. |
||||
""")) |
||||
|
||||
notification_opt_out = cfg.MultiStrOpt( |
||||
'notification_opt_out', |
||||
default=[], |
||||
help=utils.fmt(""" |
||||
Define the notification options to opt-out from. The value expected is: |
||||
identity.<resource_type>.<operation>. This field can be set multiple times in |
||||
order to add more notifications to opt-out from. For example: |
||||
notification_opt_out=identity.user.create |
||||
notification_opt_out=identity.authenticate.success |
||||
""")) |
||||
|
||||
|
||||
GROUP_NAME = 'DEFAULT' |
||||
ALL_OPTS = [ |
||||
admin_token, |
||||
public_endpoint, |
||||
admin_endpoint, |
||||
max_project_tree_depth, |
||||
max_param_size, |
||||
max_token_size, |
||||
member_role_id, |
||||
member_role_name, |
||||
crypt_strength, |
||||
list_limit, |
||||
domain_id_immutable, |
||||
strict_password_check, |
||||
secure_proxy_ssl_header, |
||||
insecure_debug, |
||||
default_publisher_id, |
||||
notification_format, |
||||
notification_opt_out, |
||||
] |
||||
|
||||
|
||||
def register_opts(conf): |
||||
conf.register_opts(ALL_OPTS) |
||||
|
||||
|
||||
def list_opts(): |
||||
return {GROUP_NAME: ALL_OPTS} |
@ -0,0 +1,70 @@
|
||||
# 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. |
||||
|
||||
from oslo_config import cfg |
||||
|
||||
from keystone.conf import utils |
||||
|
||||
|
||||
template_file = cfg.StrOpt( |
||||
'template_file', |
||||
default='default_catalog.templates', |
||||
help=utils.fmt(""" |
||||
Catalog template file name for use with the template catalog backend. |
||||
""")) |
||||
|
||||
driver = cfg.StrOpt( |
||||
'driver', |
||||
default='sql', |
||||
help=utils.fmt(""" |
||||
Entrypoint for the catalog backend driver in the keystone.catalog namespace. |
||||
Supplied drivers are kvs, sql, templated, and endpoint_filter.sql |
||||