Replace use of admin_token with Keystone bootstrap

Stop the use of the admin_token and use the bootstrap process
to initialize Keystone instead.  Fortunately the implementation
of the bootstrap process is both idempotent when it needs to be
and it can be safely called on an existing deployment.

Subsequently we can migrate by just removing the admin_token
from the configuration and create new credentials for use by
the charm with a call to ``keystone-manage bootstrap``.

Remove configuration templates for versions prior to Mitaka, by
doing this we need to move any configuration initially defined
prior to Miataka forward to the ``templates/mitaka`` folder.

A side effect of this migration is that newly bootstrapped
deployments will get their ``default`` domain created with a
literal ID of ``default``.  Prior to this change third party
software making assumptions about that being the case may have
had issues.

Closes-Bug: #1859844
Closes-Bug: #1837113
Related-Bug: #1774733
Closes-Bug: #1648719
Closes-Bug: #1578678
Func-Test-Pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/191
Change-Id: I23940720c24527ee34149f035c3bdf9ff54812c9
This commit is contained in:
Frode Nordahl 2020-03-09 15:06:09 +01:00
parent 3765c0b123
commit 0a02c30fe5
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
21 changed files with 391 additions and 759 deletions

View File

@ -82,12 +82,6 @@ options:
Admin password. To be used *for testing only*. Randomly generated by
default. To retreive generated password,
juju run --unit keystone/0 leader-get admin_passwd
admin-token:
type: string
default: None
description: |
Admin token. If set, this token will be used for all services instead of
being generated per service.
admin-role:
type: string
default: 'Admin'

View File

@ -175,12 +175,11 @@ class KeystoneContext(context.OSContextGenerator):
def __call__(self):
from keystone_utils import (
api_port, set_admin_token, endpoint_url, resolve_address,
api_port, endpoint_url, resolve_address,
PUBLIC, ADMIN, ADMIN_DOMAIN,
snap_install_requested, get_api_version,
)
ctxt = {}
ctxt['token'] = set_admin_token(config('admin-token'))
ctxt['api_version'] = get_api_version()
ctxt['admin_role'] = config('admin-role')
if ctxt['api_version'] > 2:
@ -191,6 +190,9 @@ class KeystoneContext(context.OSContextGenerator):
leader_get(attribute='admin_domain_id')
ctxt['default_domain_id'] = \
leader_get(attribute='default_domain_id')
# This is required prior to system-scope being implemented (Queens)
ctxt['transitional_charm_user_id'] = leader_get(
attribute='transitional_charm_user_id')
ctxt['admin_port'] = determine_api_port(api_port('keystone-admin'),
singlenode_mode=True)
ctxt['public_port'] = determine_api_port(api_port('keystone-public'),

View File

@ -85,6 +85,7 @@ from keystone_context import fernet_enabled
from keystone_utils import (
add_service_to_keystone,
bootstrap_keystone,
ensure_all_service_accounts_protected_for_pci_dss_options,
add_credentials_to_keystone,
determine_packages,
@ -370,6 +371,7 @@ def update_all_fid_backends():
update_keystone_fid_service_provider(relation_id=rid)
@restart_on_change(restart_map(), restart_functions=restart_function_map())
def leader_init_db_if_ready(use_current_context=False):
""" Initialise the keystone db if it is ready and mark it as initialised.
@ -393,6 +395,7 @@ def leader_init_db_if_ready(use_current_context=False):
return
migrate_database()
bootstrap_keystone(configs=CONFIGS)
ensure_initial_admin(config)
if CompareOpenStackReleases(
os_release('keystone')) >= 'liberty':
@ -705,6 +708,12 @@ def upgrade_charm():
status_set('maintenance', 'Regenerating configuration files')
CONFIGS.write_all()
# We no longer use the admin_token and need to ensure the charm has
# credentials. This call is idempotent and safe to run on existing
# deployments.
if is_leader():
bootstrap_keystone(configs=CONFIGS)
# See LP bug 1519035
leader_init_db_if_ready()

40
hooks/keystone_types.py Normal file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env python2
# Copyright 2020 Canonical Ltd
#
# 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.
# NOTE(fnordahl): This file needs to remain Python2 as it is used both by the
# charm code which is Python3 and the special ``manager.py`` script that is in
# place to support both Python2 and Python3 systems with the same codebase.
#
# The need for jumping through these hoops come from classic charms being
# deployed without any form of Python environment with direct dependencies.
# Subsequently we live at the grace of whatever dependencies our payload has
# in the running system. This may change underneath us as we upgrade between
# UCA pockets and across series.
import collections
CharmCredentials = collections.namedtuple(
'CharmCredentials',
(
'username',
'password',
'system_scope',
'project_name', # For V2 and pre system scope compatibility
'project_domain_name', # For Mitaka -> Pike (pre system scope)
'user_domain_name', # For Mitaka -> Pike (pre system scope)
),
)

View File

@ -129,6 +129,8 @@ import keystone_context
import uds_comms as uds
import keystone_types
TEMPLATES = 'templates/'
# removed from original: charm-helper-sh
@ -178,7 +180,6 @@ if snap_install_requested():
KEYSTONE_LOGGER_CONF = "{}/logging.conf".format(SNAP_COMMON_KEYSTONE_DIR)
SNAP_LIB_DIR = '{}/lib'.format(SNAP_COMMON_DIR)
STORED_PASSWD = "{}/keystone.passwd".format(SNAP_LIB_DIR)
STORED_TOKEN = "{}/keystone.token".format(SNAP_LIB_DIR)
STORED_ADMIN_DOMAIN_ID = ("{}/keystone.admin_domain_id"
"".format(SNAP_LIB_DIR))
STORED_DEFAULT_DOMAIN_ID = ("{}/keystone.default_domain_id"
@ -196,7 +197,6 @@ else:
KEYSTONE_LOGGER_CONF = "/etc/keystone/logging.conf"
KEYSTONE_CONF_DIR = os.path.dirname(KEYSTONE_CONF)
STORED_PASSWD = "/var/lib/keystone/keystone.passwd"
STORED_TOKEN = "/var/lib/keystone/keystone.token"
STORED_ADMIN_DOMAIN_ID = "/var/lib/keystone/keystone.admin_domain_id"
STORED_DEFAULT_DOMAIN_ID = "/var/lib/keystone/keystone.default_domain_id"
SERVICE_PASSWD_PATH = '/var/lib/keystone/services.passwd'
@ -212,6 +212,7 @@ APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf'
MEMCACHED_CONF = '/etc/memcached.conf'
CHARM_USER = '_charm-keystone-admin'
CLUSTER_RES = 'grp_ks_vips'
ADMIN_DOMAIN = 'admin_domain'
ADMIN_PROJECT = 'admin'
@ -772,6 +773,10 @@ def do_openstack_upgrade(configs):
if is_elected_leader(CLUSTER_RES):
if is_db_ready():
migrate_database()
# After an OpenStack upgrade we re-run bootstrap to make sure role
# assignments are up to date. One example is the system role
# assignment support that first appeared at Queens.
bootstrap_keystone(configs=configs)
else:
log("Database not ready - deferring to shared-db relation",
level=INFO)
@ -821,6 +826,94 @@ def migrate_database():
leader_set({'db-initialised': True})
stop_manager_instance()
def is_bootstrapped():
"""Determines whether Keystone has been bootstrapped.
:returns: True when Keystone bootstrap has been run, False otherwise.
:rtype: bool
"""
return (
leader_get('keystone-bootstrapped') is True and
leader_get('{}_passwd'.format(CHARM_USER)) is not None
)
def bootstrap_keystone(configs=None):
"""Runs ``keystone-manage bootstrap`` to bootstrap keystone.
The bootstrap command is designed to be idempotent when it needs to be,
i.e. if nothing has changed it will do nothing. It is also safe to run
the bootstrap command on a already deployed Keystone.
The bootstrap command creates resources in the ``default`` domain. It
assigns a system-scoped role to the created user and as such the charm can
use it to manage any domains resources.
For successful operation of the ``keystoneclient`` used by the charm, we
must create initial endpoints at bootstrap time. For HA deployments these
will be replaced as soon as HA configuration is complete.
:param configs: Registered configs
:type configs: Optional[Dict]
"""
log('Bootstrapping keystone.', level=INFO)
status_set('maintenance', 'Bootstrapping keystone')
# NOTE: The bootstrap process is necessary for the charm to be able to
# talk to Keystone. We will still rely on ``ensure_initial_admin`` to
# maintain Keystone's endpoints and the rest of the CRUD.
api_suffix = get_api_suffix()
charm_password = leader_get('{}_passwd'.format(CHARM_USER)) or pwgen(64)
subprocess.check_call((
'keystone-manage', 'bootstrap',
'--bootstrap-username', CHARM_USER,
'--bootstrap-password', charm_password,
'--bootstrap-project-name', ADMIN_PROJECT,
'--bootstrap-role-name', config('admin-role'),
'--bootstrap-service-name', 'keystone',
'--bootstrap-admin-url', endpoint_url(
resolve_address(ADMIN),
config('admin-port'),
api_suffix),
'--bootstrap-public-url', endpoint_url(
resolve_address(PUBLIC),
config('service-port'),
api_suffix),
'--bootstrap-internal-url', endpoint_url(
resolve_address(INTERNAL),
config('service-port'),
api_suffix),
'--bootstrap-region-id', config('region').split()[0]),
)
# TODO: we should consider to add --immutable-roles for supported releases
# and/or make it configurable. Saving for a future change as this one is
# big enough as-is.
leader_set({
'keystone-bootstrapped': True,
'{}_passwd'.format(CHARM_USER): charm_password,
})
cmp_release = CompareOpenStackReleases(os_release('keystone'))
if configs and cmp_release < 'queens':
# For Mitaka through Pike we need to work around the lack of support
# for system scope by having a special bootstrap version of the
# policy.json that ensures the charm has access to retrieve the user ID
# created for the charm in the bootstrap process.
#
# As soon as the user ID is retrieved it will be stored in leader
# storage which will be picked up by a context and subsequently written
# to the runtime policy.json.
#
# NOTE: Remove this and the associated policy change as soon as
# support for Mitaka -> Pike is removed.
manager = get_manager()
transitional_charm_user_id = manager.resolve_user_id(
CHARM_USER, user_domain='default')
leader_set({
'transitional_charm_user_id': transitional_charm_user_id,
})
configs.write_all()
# OLD
@ -850,41 +943,30 @@ def get_local_endpoint(api_suffix=None):
return local_endpoint
def set_admin_token(admin_token='None'):
"""Set admin token according to deployment config or use a randomly
generated token if none is specified (default).
"""
if admin_token != 'None':
log('Configuring Keystone to use a pre-configured admin token.')
token = admin_token
else:
log('Configuring Keystone to use a random admin token.')
if os.path.isfile(STORED_TOKEN):
msg = 'Loading a previously generated' \
' admin token from %s' % STORED_TOKEN
log(msg)
with open(STORED_TOKEN, 'r') as f:
token = f.read().strip()
else:
token = pwgen(length=64)
with open(STORED_TOKEN, 'w') as out:
out.write('%s\n' % token)
return(token)
def get_charm_credentials():
"""Retrieve credentials for use by charm when managing identity CRUD.
The bootstrap process creates a user for the charm in the default domain
and assigns a system level role. Subsequently the charm authenticates with
a system-scoped token so it can manage all domain's resources.
def get_admin_token():
"""Temporary utility to grab the admin token as configured in
keystone.conf
:returns: CharmCredentials with username, password and defaults for scoping
:rtype: collections.namedtuple[str,str,str,str,str,str]
:raises: RuntimeError
"""
with open(KEYSTONE_CONF, 'r') as f:
for l in f.readlines():
if l.split(' ')[0] == 'admin_token':
try:
return l.split('=')[1].strip()
except Exception:
error_out('Could not parse admin_token line from %s' %
KEYSTONE_CONF)
error_out('Could not find admin_token line in %s' % KEYSTONE_CONF)
charm_password = leader_get('{}_passwd'.format(CHARM_USER))
if charm_password is None:
raise RuntimeError('Leader unit has not provided credentials required '
'for speaking with Keystone yet.')
return keystone_types.CharmCredentials(
CHARM_USER,
charm_password,
'all',
ADMIN_PROJECT, # For V2 and pre system scope compatibility
'default', # For Mitaka -> Pike (pre system scope)
'default', # For Mitaka -> Pike (pre system scope)
)
def is_service_present(service_name, service_type):
@ -950,7 +1032,14 @@ def create_endpoint_template_v2(manager, region, service, publicurl, adminurl,
else:
# delete endpoint and recreate if endpoint urls need updating.
log("Updating endpoint template with new endpoint urls.")
manager.delete_endpoint_by_id(ep['id'])
# NOTE: When using the 2.0 API and not using the admin_token
# the call to delete_endpoint_by_id returns 404.
# Deleting service works and will cascade delete endpoint.
svc = manager.get_service_by_id(service_id)
manager.delete_service_by_id(service_id)
# NOTE: We do not get the service description in API v2.0
create_service_entry(svc['name'], svc['type'], '')
service_id = manager.resolve_service_id(service)
manager.create_endpoints(region=region,
service_id=service_id,
@ -1133,7 +1222,7 @@ def _proxy_manager_call(path, api_version, args, kwargs):
package = dict(path=path,
api_version=api_version,
api_local_endpoint=get_local_endpoint(),
admin_token=get_admin_token(),
charm_credentials=get_charm_credentials(),
args=args,
kwargs=kwargs)
serialized = json.dumps(package, **JSON_ENCODE_OPTIONS)
@ -1696,7 +1785,11 @@ def ensure_all_service_accounts_protected_for_pci_dss_options():
if get_api_version() < 3:
return
log("Ensuring all service users are protected from PCI-DSS options")
users = list_users_for_domain(domain=SERVICE_DOMAIN)
# We want to make sure our own charm credentials are protected too, they
# only exist in DEFAULT_DOMAIN, but the called function gracefully deals
# with that.
users = [{'name': CHARM_USER}]
users += list_users_for_domain(domain=SERVICE_DOMAIN)
for user in users:
protect_user_account_from_pci_dss_force_change_password(user['name'])
@ -1799,7 +1892,6 @@ def add_service_to_keystone(relation_id=None, remote_unit=None):
if not service_username:
return
token = get_admin_token()
roles = get_requested_roles(settings)
service_password = create_service_credentials(service_username,
new_roles=roles)
@ -1829,7 +1921,6 @@ def add_service_to_keystone(relation_id=None, remote_unit=None):
relation_data = {
"auth_host": resolve_address(ADMIN),
"service_host": resolve_address(PUBLIC),
"admin_token": token,
"service_port": config("service-port"),
"auth_port": config("admin-port"),
"service_username": service_username,

View File

@ -23,13 +23,17 @@ import stat
import sys
import time
from keystoneclient.v2_0 import client
from keystoneauth1 import session as ks_session
from keystoneauth1.identity import v2 as ks_identity_v2
from keystoneauth1.identity import v3 as ks_identity_v3
from keystoneclient.v2_0 import client as keystoneclient_v2
from keystoneclient.v3 import client as keystoneclient_v3
from keystoneclient.auth import token_endpoint
from keystoneclient import session, exceptions
from keystoneclient import exceptions
import uds_comms as uds
import keystone_types
_usage = """This file is called from the keystone_utils.py file to implement
various keystone calls and functions. It is called with one parameter which is
@ -42,7 +46,7 @@ following keys:
'path': The api path on the keystone manager object.
'api_version': the keystone API version to use.
'api_local_endpoint': the local endpoint to connect to.
'admin_token': the admin token to use with keystone.
'charm_credentials': the credentials to use when speaking with Keystone.
'args': the non-keyword argument to supply to the keystone manager call.
'kwargs': any keyword args to supply to the keystone manager call.
}
@ -75,17 +79,17 @@ else:
econnrefused = exceptions.ConnectionError
def _get_keystone_manager_class(endpoint, token, api_version):
def _get_keystone_manager_class(endpoint, charm_credentials, api_version):
"""Return KeystoneManager class for the given API version
@param endpoint: the keystone endpoint to point client at
@param token: the keystone admin_token
@param charm_credentials: the keystone credentials
@param api_version: version of the keystone api the client should use
@returns keystonemanager class used for interrogating keystone
"""
if api_version == 2:
return KeystoneManager2(endpoint, token)
return KeystoneManager2(endpoint, charm_credentials)
if api_version == 3:
return KeystoneManager3(endpoint, token)
return KeystoneManager3(endpoint, charm_credentials)
raise ValueError('No manager found for api version {}'.format(api_version))
@ -118,7 +122,7 @@ def retry_on_exception(num_retries, base_delay=0, exc_type=Exception):
@retry_on_exception(5, base_delay=3, exc_type=econnrefused)
def get_keystone_manager(endpoint, token, api_version=None):
def get_keystone_manager(endpoint, charm_credentials, api_version=None):
"""Return a keystonemanager for the correct API version
If api_version has not been set then create a manager based on the endpoint
@ -131,17 +135,20 @@ def get_keystone_manager(endpoint, token, api_version=None):
simplified
@param endpoint: the keystone endpoint to point client at
@param token: the keystone admin_token
@param charm_credentials: the keystone credentials
@param api_version: version of the keystone api the client should use
@returns keystonemanager class used for interrogating keystone
"""
if api_version:
return _get_keystone_manager_class(endpoint, token, api_version)
return _get_keystone_manager_class(
endpoint, charm_credentials, api_version)
else:
if 'v2.0' in endpoint.split('/'):
manager = _get_keystone_manager_class(endpoint, token, 2)
manager = _get_keystone_manager_class(
endpoint, charm_credentials, 2)
else:
manager = _get_keystone_manager_class(endpoint, token, 3)
manager = _get_keystone_manager_class(
endpoint, charm_credentials, 3)
if endpoint.endswith('/'):
base_ep = endpoint.rsplit('/', 2)[0]
else:
@ -158,10 +165,12 @@ def get_keystone_manager(endpoint, token, api_version=None):
break
if version and version == 'v2.0':
new_ep = base_ep + "/" + 'v2.0'
return _get_keystone_manager_class(new_ep, token, 2)
return _get_keystone_manager_class(
new_ep, charm_credentials, 2)
elif version and version == 'v3':
new_ep = base_ep + "/" + 'v3'
return _get_keystone_manager_class(new_ep, token, 3)
return _get_keystone_manager_class(
new_ep, charm_credentials, 3)
else:
return manager
@ -207,6 +216,11 @@ class KeystoneManager(object):
if type == s['type']:
return s['id']
def get_service_by_id(self, service_id):
"""Get a service by the service id"""
service = self.api.services.get(service_id)
return service.to_dict()
def delete_service_by_id(self, service_id):
"""Delete a service by the service id"""
self.api.services.delete(service_id)
@ -232,9 +246,21 @@ class KeystoneManager(object):
class KeystoneManager2(KeystoneManager):
def __init__(self, endpoint, token):
def __init__(self, endpoint, charm_credentials):
self.api_version = 2
self.api = client.Client(endpoint=endpoint, token=token)
auth = ks_identity_v2.Password(
auth_url=endpoint,
username=charm_credentials.username,
password=charm_credentials.password,
tenant_name=charm_credentials.project_name)
session = ks_session.Session(auth=auth)
# NOTE: We need to also provide the local endpoint URL as an
# endpoint_override, otherwise the client will attempt to discover the
# endpoint to use in the catalog. Since we are managing said catalog
# we need to avoid situations where there is no endpoint to be found.
self.api = keystoneclient_v2.Client(
session=session, endpoint_override=endpoint)
def resolve_user_id(self, name, user_domain=None):
"""Find the user_id of a given user"""
@ -300,11 +326,36 @@ class KeystoneManager2(KeystoneManager):
class KeystoneManager3(KeystoneManager):
def __init__(self, endpoint, token):
def __init__(self, endpoint, charm_credentials):
self.api_version = 3
keystone_auth_v3 = token_endpoint.Token(endpoint=endpoint, token=token)
keystone_session_v3 = session.Session(auth=keystone_auth_v3)
self.api = keystoneclient_v3.Client(session=keystone_session_v3)
# The bootstrap process creates a user for the charm in the ``default``
# domain and assigns a system level role. We need to specify domain
# name even when we request a system scoped token.
try:
auth = ks_identity_v3.Password(
auth_url=endpoint,
username=charm_credentials.username,
password=charm_credentials.password,
system_scope=charm_credentials.system_scope,
project_domain_name=charm_credentials.project_domain_name,
user_domain_name=charm_credentials.user_domain_name)
except TypeError:
# Support for OpenStack versions prior to Queens
auth = ks_identity_v3.Password(
auth_url=endpoint,
username=charm_credentials.username,
password=charm_credentials.password,
project_name=charm_credentials.project_name,
project_domain_name=charm_credentials.project_domain_name,
user_domain_name=charm_credentials.user_domain_name)
keystone_session_v3 = ks_session.Session(auth=auth)
# NOTE: We need to also provide the local endpoint URL as an
# endpoint_override, otherwise the client will attempt to discover the
# endpoint to use in the catalog. Since we are managing said catalog
# we need to avoid situations where there is no endpoint to be found.
self.api = keystoneclient_v3.Client(
session=keystone_session_v3, endpoint_override=endpoint)
def resolve_tenant_id(self, name, domain=None):
"""Find the tenant_id of a given tenant"""
@ -532,19 +583,22 @@ class KeystoneManager3(KeystoneManager):
_keystone_manager = dict(
api_version=None,
api_local_endpoint=None,
admin_token=None,
charm_credentials=None,
manager=None)
def get_manager(api_version=None, api_local_endpoint=None, admin_token=None):
def get_manager(api_version=None, api_local_endpoint=None,
charm_credentials=None):
"""Return a keystonemanager for the correct API version
This function actually returns a singleton of the right kind of
KeystoneManager (v2 or v3). If the api_version, api_local_endpoint and
admin_token haven't changed then the current _keystone_manager object is
returned, otherwise a new one is created (and thus the old one goes out of
scope and is closed). This is to that repeated calls to get_manager(...)
only results in a single authorisation request if the details don't change.
charm_credentials haven't changed then the current _keystone_manager object
is returned, otherwise a new one is created (and thus the old one goes out
of scope and is closed). This is to that repeated calls to
get_manager(...) only results in a single authorisation request if the
details don't change.
This is to speed up calls from the keystone charm into keystone and make
the charm more performant. It's hoped that the complexity/performance
trade-off is a good choice.
@ -552,25 +606,26 @@ def get_manager(api_version=None, api_local_endpoint=None, admin_token=None):
:param api_verion: The version of the api to use or None. if None then the
version is determined from the api_local_enpoint variable.
:param api_local_endpoint: where to find the keystone API
:param admin_token: the token used for authentication.
:raises: RuntimeError if api_local_endpoint or admin_token is not set.
:param charm_credentials: the credentials used for authentication.
:raises: RuntimeError if api_local_endpoint or charm_credentials is not
set.
:returns: a KeystoneManager derived class (possibly the singleton).
"""
if api_local_endpoint is None:
raise RuntimeError("get_manager(): api_local_endpoint is not set")
if admin_token is None:
raise RuntimeError("get_manager(): admin_token is not set")
if charm_credentials is None:
raise RuntimeError("get_manager(): charm_credentials is not set")
global _keystone_manager
if (api_version == _keystone_manager['api_version'] and
api_local_endpoint == _keystone_manager['api_local_endpoint'] and
admin_token == _keystone_manager['admin_token']):
charm_credentials == _keystone_manager['charm_credentials']):
return _keystone_manager['manager']
# only retain the params IF getting the manager actually works
_keystone_manager['manager'] = get_keystone_manager(
api_local_endpoint, admin_token, api_version)
api_local_endpoint, charm_credentials, api_version)
_keystone_manager['api_version'] = api_version
_keystone_manager['api_local_endpoint'] = api_local_endpoint
_keystone_manager['admin_token'] = admin_token
_keystone_manager['charm_credentials'] = charm_credentials
return _keystone_manager['manager']
@ -638,7 +693,8 @@ if __name__ == '__main__':
manager = get_manager(
api_version=spec['api_version'],
api_local_endpoint=spec['api_local_endpoint'],
admin_token=spec['admin_token'])
charm_credentials=keystone_types.CharmCredentials._make(
spec['charm_credentials']))
_callable = manager
for attr in spec['path']:
_callable = getattr(_callable, attr)

View File

@ -1,106 +0,0 @@
# icehouse
###############################################################################
# [ WARNING ]
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
admin_port = {{ admin_port }}
public_port = {{ public_port }}
use_syslog = {{ use_syslog }}
log_config = /etc/keystone/logging.conf
debug = {{ debug }}
verbose = {{ verbose }}
public_endpoint = {{ public_endpoint }}
admin_endpoint = {{ admin_endpoint }}
bind_host = {{ bind_host }}
public_workers = {{ workers }}
admin_workers = {{ workers }}
[database]
{% if database_host -%}
connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
{% else -%}
connection = sqlite:////var/lib/keystone/keystone.db
{% endif -%}
connection_recycle_time = 200
[identity]
driver = keystone.identity.backends.{{ identity_backend }}.Identity
[credential]
driver = keystone.credential.backends.sql.Credential
[trust]
driver = keystone.trust.backends.sql.Trust
[os_inherit]
[catalog]
driver = keystone.catalog.backends.sql.Catalog
[endpoint_filter]
[token]
driver = keystone.token.backends.sql.Token
provider = keystone.token.providers.uuid.Provider
expiration = {{ token_expiration }}
{% include "parts/section-signing" %}
[cache]
[policy]
driver = keystone.policy.backends.sql.Policy
[ec2]
driver = keystone.contrib.ec2.backends.sql.Ec2
[assignment]
driver = keystone.assignment.backends.{{ assignment_backend }}.Assignment
[oauth1]
[auth]
methods = external,password,token,oauth1
password = keystone.auth.plugins.password.Password
token = keystone.auth.plugins.token.Token
oauth1 = keystone.auth.plugins.oauth1.OAuth
[paste_deploy]
config_file = keystone-paste.ini
[extra_headers]
Distribution = Ubuntu
[ldap]
{% if identity_backend == 'ldap' -%}
url = {{ ldap_server }}
user = {{ ldap_user }}
password = {{ ldap_password }}
suffix = {{ ldap_suffix }}
{% if ldap_config_flags -%}
{% for key, value in ldap_config_flags.items() -%}
{{ key }} = {{ value }}
{% endfor -%}
{% endif -%}
{% if ldap_readonly -%}
user_allow_create = False
user_allow_update = False
user_allow_delete = False
tenant_allow_create = False
tenant_allow_update = False
tenant_allow_delete = False
role_allow_create = False
role_allow_update = False
role_allow_delete = False
group_allow_create = False
group_allow_update = False
group_allow_delete = False
{% endif -%}
{% endif -%}

View File

@ -1,49 +0,0 @@
# icehouse
[loggers]
keys=root
[formatters]
keys=normal,normal_with_name,debug
[handlers]
keys=production,file,devel
[logger_root]
{% if root_level -%}
level={{ root_level }}
{% else -%}
level=WARNING
{% endif -%}
handlers=file,production
[handler_production]
class=handlers.SysLogHandler
{% if log_level -%}
level={{ log_level }}
{% else -%}
level=ERROR
{% endif -%}
formatter=normal_with_name
args=(('/dev/log'), handlers.SysLogHandler.LOG_USER)
[handler_file]
class=FileHandler
level=DEBUG
formatter=normal_with_name
args=('/var/log/keystone/keystone.log', 'a')
[handler_devel]
class=StreamHandler
level=NOTSET
formatter=debug
args=(sys.stdout,)
[formatter_normal]
format=%(asctime)s %(levelname)s %(message)s
[formatter_normal_with_name]
format=(%(name)s): %(asctime)s %(levelname)s %(message)s
[formatter_debug]
format=(%(name)s): %(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s

View File

@ -1,121 +0,0 @@
# kilo
###############################################################################
# [ WARNING ]
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
use_syslog = {{ use_syslog }}
log_config = /etc/keystone/logging.conf
debug = {{ debug }}
verbose = {{ verbose }}
public_endpoint = {{ public_endpoint }}
admin_endpoint = {{ admin_endpoint }}
[eventlet_server]
admin_bind_host = {{ bind_host }}
public_bind_host = {{ bind_host }}
public_workers = {{ workers }}
admin_workers = {{ workers }}
admin_port = {{ admin_port }}
public_port = {{ public_port }}
[database]
{% if database_host -%}
connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
{% else -%}
connection = sqlite:////var/lib/keystone/keystone.db
{% endif -%}
connection_recycle_time = 200
[identity]
driver = keystone.identity.backends.{{ identity_backend }}.Identity
{% if default_domain_id -%}
default_domain_id = {{ default_domain_id }}
{% endif -%}
{% if api_version == 3 -%}
domain_specific_drivers_enabled = True
domain_config_dir = /etc/keystone/domains
{% endif -%}
[credential]
driver = keystone.credential.backends.sql.Credential
[trust]
driver = keystone.trust.backends.sql.Trust
[os_inherit]
[catalog]
driver = keystone.catalog.backends.sql.Catalog
[endpoint_filter]
[token]
driver = keystone.token.persistence.backends.sql.Token
provider = keystone.token.providers.uuid.Provider
expiration = {{ token_expiration }}
{% include "parts/section-signing" %}
[cache]
[policy]
driver = keystone.policy.backends.sql.Policy
[ec2]
driver = keystone.contrib.ec2.backends.sql.Ec2
[assignment]
driver = keystone.assignment.backends.{{ assignment_backend }}.Assignment
[oauth1]
[auth]
methods = external,password,token,oauth1
password = keystone.auth.plugins.password.Password
token = keystone.auth.plugins.token.Token
oauth1 = keystone.auth.plugins.oauth1.OAuth
[paste_deploy]
config_file = /etc/keystone/keystone-paste.ini
[extra_headers]
Distribution = Ubuntu
[ldap]
{% if identity_backend == 'ldap' -%}
url = {{ ldap_server }}
user = {{ ldap_user }}
password = {{ ldap_password }}
suffix = {{ ldap_suffix }}
{% if ldap_config_flags -%}
{% for key, value in ldap_config_flags.items() -%}
{{ key }} = {{ value }}
{% endfor -%}
{% endif -%}
{% if ldap_readonly -%}
user_allow_create = False
user_allow_update = False
user_allow_delete = False
tenant_allow_create = False
tenant_allow_update = False
tenant_allow_delete = False
role_allow_create = False
role_allow_update = False
role_allow_delete = False
group_allow_create = False
group_allow_update = False
group_allow_delete = False
{% endif -%}
{% endif -%}
[oslo_middleware]
# Bug #1819134
max_request_body_size = 114688

View File

@ -1,382 +0,0 @@
{% if api_version == 3 -%}
{
"admin_required": "role:{{ admin_role }}",
"cloud_admin": "rule:admin_required and domain_id:{{ admin_domain_id }}",
"service_role": "role:service",
"service_or_admin": "rule:admin_required or rule:service_role",
"owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",
"admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner",
"admin_or_cloud_admin": "rule:admin_required or rule:cloud_admin",
"admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s",
"service_admin_or_owner": "rule:service_or_admin or rule:owner",
"default": "rule:admin_required",
"identity:get_region": "",
"identity:list_regions": "",
"identity:create_region": "rule:cloud_admin",
"identity:update_region": "rule:cloud_admin",
"identity:delete_region": "rule:cloud_admin",
"identity:get_service": "rule:admin_or_cloud_admin",
"identity:list_services": "rule:admin_or_cloud_admin",
"identity:create_service": "rule:cloud_admin",
"identity:update_service": "rule:cloud_admin",
"identity:delete_service": "rule:cloud_admin",
"identity:get_endpoint": "rule:admin_or_cloud_admin",
"identity:list_endpoints": "rule:admin_or_cloud_admin",
"identity:create_endpoint": "rule:cloud_admin",
"identity:update_endpoint": "rule:cloud_admin",
"identity:delete_endpoint": "rule:cloud_admin",
"identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id",
"identity:list_domains": "rule:cloud_admin",
"identity:create_domain": "rule:cloud_admin",
"identity:update_domain": "rule:cloud_admin",
"identity:delete_domain": "rule:cloud_admin",
"admin_and_matching_target_project_domain_id": "rule:admin_required and domain_id:%(target.project.domain_id)s",
"admin_and_matching_project_domain_id": "rule:admin_required and domain_id:%(project.domain_id)s",
"identity:get_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
"identity:list_projects": "rule:cloud_admin or rule:admin_and_matching_domain_id",
"identity:list_user_projects": "rule:owner or rule:admin_and_matching_domain_id",
"identity:create_project": "rule:cloud_admin or rule:admin_and_matching_project_domain_id",
"identity:update_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
"identity:delete_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
"admin_and_matching_target_user_domain_id": "rule:admin_required and domain_id:%(target.user.domain_id)s",
"admin_and_matching_user_domain_id": "rule:admin_required and domain_id:%(user.domain_id)s",
"identity:get_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
"identity:list_users": "rule:cloud_admin or rule:admin_and_matching_domain_id",
"identity:create_user": "rule:cloud_admin or rule:admin_and_matching_user_domain_id",
"identity:update_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
"identity:delete_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
"admin_and_matching_target_group_domain_id": "rule:admin_required and domain_id:%(target.group.domain_id)s",
"admin_and_matching_group_domain_id": "rule:admin_required and domain_id:%(group.domain_id)s",
"identity:get_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:list_groups": "rule:cloud_admin or rule:admin_and_matching_domain_id",
"identity:list_groups_for_user": "rule:owner or rule:admin_and_matching_domain_id",
"identity:create_group": "rule:cloud_admin or rule:admin_and_matching_group_domain_id",
"identity:update_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:delete_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:list_users_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:remove_user_from_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:check_user_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
"identity:get_credential": "rule:admin_required",
"identity:list_credentials": "rule:admin_required or user_id:%(user_id)s",
"identity:create_credential": "rule:admin_required",
"identity:update_credential": "rule:admin_required",
"identity:delete_credential": "rule:admin_required",
"identity:ec2_get_credential": "rule:admin_or_cloud_admin or (rule:owner and user_id:%(target.credential.user_id)s)",
"identity:ec2_list_credentials": "rule:admin_or_cloud_admin or rule:owner",
"identity:ec2_create_credential": "rule:admin_or_cloud_admin or rule:owner",
"identity:ec2_delete_credential": "rule:admin_or_cloud_admin or (rule:owner and user_id:%(target.credential.user_id)s)",
"identity:get_role": "rule:admin_or_cloud_admin",
"identity:list_roles": "rule:admin_or_cloud_admin",
"identity:create_role": "rule:cloud_admin",
"identity:update_role": "rule:cloud_admin",
"identity:delete_role": "rule:cloud_admin",
"domain_admin_for_grants": "rule:admin_required and (domain_id:%(domain_id)s or domain_id:%(target.project.domain_id)s)",
"project_admin_for_grants": "rule:admin_required and project_id:%(project_id)s",
"identity:check_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
"identity:list_grants": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
"identity:create_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
"identity:revoke_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
"admin_on_domain_filter" : "rule:admin_required and domain_id:%(scope.domain.id)s",
"admin_on_project_filter" : "rule:admin_required and project_id:%(scope.project.id)s",
"identity:list_role_assignments": "rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter",
"identity:get_policy": "rule:cloud_admin",
"identity:list_policies": "rule:cloud_admin",
"identity:create_policy": "rule:cloud_admin",
"identity:update_policy": "rule:cloud_admin",
"identity:delete_policy": "rule:cloud_admin",
"identity:change_password": "rule:owner",
"identity:check_token": "rule:admin_or_owner",
"identity:validate_token": "rule:service_admin_or_owner",
"identity:validate_token_head": "rule:service_or_admin",
"identity:revocation_list": "rule:service_or_admin",
"identity:revoke_token": "rule:admin_or_owner",
"identity:create_trust": "user_id:%(trust.trustor_user_id)s",
"identity:list_trusts": "",
"identity:list_roles_for_trust": "",
"identity:get_role_for_trust": "",
"identity:delete_trust": "",
"identity:create_consumer": "rule:admin_required",
"identity:get_consumer": "rule:admin_required",
"identity:list_consumers": "rule:admin_required",
"identity:delete_consumer": "rule:admin_required",
"identity:update_consumer": "rule:admin_required",
"identity:authorize_request_token": "rule:admin_required",
"identity:list_access_token_roles": "rule:admin_required",
"identity:get_access_token_role": "rule:admin_required",
"identity:list_access_tokens": "rule:admin_required",
"identity:get_access_token": "rule:admin_required",
"identity:delete_access_token": "rule:admin_required",
"identity:list_projects_for_endpoint": "rule:admin_required",
"identity:add_endpoint_to_project": "rule:admin_required",
"identity:check_endpoint_in_project": "rule:admin_required",
"identity:list_endpoints_for_project": "rule:admin_required",
"identity:remove_endpoint_from_project": "rule:admin_required",
"identity:create_endpoint_group": "rule:admin_required",
"identity:list_endpoint_groups": "rule:admin_required",
"identity:get_endpoint_group": "rule:admin_required",
"identity:update_endpoint_group": "rule:admin_required",
"identity:delete_endpoint_group": "rule:admin_required",
"identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
"identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
"identity:get_endpoint_group_in_project": "rule:admin_required",
"identity:list_endpoint_groups_for_project": "rule:admin_required",
"identity:add_endpoint_group_to_project": "rule:admin_required",
"identity:remove_endpoint_group_from_project": "rule:admin_required",
"identity:create_identity_provider": "rule:cloud_admin",
"identity:list_identity_providers": "rule:cloud_admin",
"identity:get_identity_providers": "rule:cloud_admin",
"identity:update_identity_provider": "rule:cloud_admin",
"identity:delete_identity_provider": "rule:cloud_admin",
"identity:create_protocol": "rule:cloud_admin",
"identity:update_protocol": "rule:cloud_admin",
"identity:get_protocol": "rule:cloud_admin",
"identity:list_protocols": "rule:cloud_admin",
"identity:delete_protocol": "rule:cloud_admin",
"identity:create_mapping": "rule:cloud_admin",
"identity:get_mapping": "rule:cloud_admin",
"identity:list_mappings": "rule:cloud_admin",
"identity:delete_mapping": "rule:cloud_admin",
"identity:update_mapping": "rule:cloud_admin",
"identity:create_service_provider": "rule:cloud_admin",
"identity:list_service_providers": "rule:cloud_admin",
"identity:get_service_provider": "rule:cloud_admin",
"identity:update_service_provider": "rule:cloud_admin",
"identity:delete_service_provider": "rule:cloud_admin",
"identity:get_auth_catalog": "",
"identity:get_auth_projects": "",
"identity:get_auth_domains": "",
"identity:list_projects_for_groups": "",
"identity:list_domains_for_groups": "",
"identity:list_revoke_events": "",
"identity:create_policy_association_for_endpoint": "rule:cloud_admin",
"identity:check_policy_association_for_endpoint": "rule:cloud_admin",
"identity:delete_policy_association_for_endpoint": "rule:cloud_admin",
"identity:create_policy_association_for_service": "rule:cloud_admin",
"identity:check_policy_association_for_service": "rule:cloud_admin",
"identity:delete_policy_association_for_service": "rule:cloud_admin",
"identity:create_policy_association_for_region_and_service": "rule:cloud_admin",
"identity:check_policy_association_for_region_and_service": "rule:cloud_admin",
"identity:delete_policy_association_for_region_and_service": "rule:cloud_admin",
"identity:get_policy_for_endpoint": "rule:cloud_admin",
"identity:list_endpoints_for_policy": "rule:cloud_admin",
"identity:create_domain_config": "rule:cloud_admin",
"identity:get_domain_config": "rule:cloud_admin",
"identity:update_domain_config": "rule:cloud_admin",
"identity:delete_domain_config": "rule:cloud_admin"
}
{% else -%}
{
"admin_required": "role:admin or is_admin:1",
"service_role": "role:service",
"service_or_admin": "rule:admin_required or rule:service_role",
"owner" : "user_id:%(user_id)s",
"admin_or_owner": "rule:admin_required or rule:owner",
"token_subject": "user_id:%(target.token.user_id)s",
"admin_or_token_subject": "rule:admin_required or rule:token_subject",
"service_admin_or_token_subject": "rule:service_or_admin or rule:token_subject",
"default": "rule:admin_required",
"identity:get_region": "",
"identity:list_regions": "",
"identity:create_region": "rule:admin_required",
"identity:update_region": "rule:admin_required",
"identity:delete_region": "rule:admin_required",
"identity:get_service": "rule:admin_required",
"identity:list_services": "rule:admin_required",
"identity:create_service": "rule:admin_required",
"identity:update_service": "rule:admin_required",
"identity:delete_service": "rule:admin_required",
"identity:get_endpoint": "rule:admin_required",
"identity:list_endpoints": "rule:admin_required",
"identity:create_endpoint": "rule:admin_required",
"identity:update_endpoint": "rule:admin_required",
"identity:delete_endpoint": "rule:admin_required",
"identity:get_domain": "rule:admin_required",
"identity:list_domains": "rule:admin_required",
"identity:create_domain": "rule:admin_required",
"identity:update_domain": "rule:admin_required",
"identity:delete_domain": "rule:admin_required",
"identity:get_project": "rule:admin_required",
"identity:list_projects": "rule:admin_required",
"identity:list_user_projects": "rule:admin_or_owner",
"identity:create_project": "rule:admin_required",
"identity:update_project": "rule:admin_required",
"identity:delete_project": "rule:admin_required",
"identity:get_user": "rule:admin_required",
"identity:list_users": "rule:admin_required",
"identity:create_user": "rule:admin_required",
"identity:update_user": "rule:admin_required",
"identity:delete_user": "rule:admin_required",
"identity:change_password": "rule:admin_or_owner",
"identity:get_group": "rule:admin_required",
"identity:list_groups": "rule:admin_required",
"identity:list_groups_for_user": "rule:admin_or_owner",
"identity:create_group": "rule:admin_required",
"identity:update_group": "rule:admin_required",
"identity:delete_group": "rule:admin_required",
"identity:list_users_in_group": "rule:admin_required",
"identity:remove_user_from_group": "rule:admin_required",
"identity:check_user_in_group": "rule:admin_required",
"identity:add_user_to_group": "rule:admin_required",
"identity:get_credential": "rule:admin_required",
"identity:list_credentials": "rule:admin_required",
"identity:create_credential": "rule:admin_required",
"identity:update_credential": "rule:admin_required",
"identity:delete_credential": "rule:admin_required",
"identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
"identity:ec2_list_credentials": "rule:admin_or_owner",
"identity:ec2_create_credential": "rule:admin_or_owner",
"identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
"identity:get_role": "rule:admin_required",
"identity:list_roles": "rule:admin_required",
"identity:create_role": "rule:admin_required",
"identity:update_role": "rule:admin_required",
"identity:delete_role": "rule:admin_required",
"identity:check_grant": "rule:admin_required",
"identity:list_grants": "rule:admin_required",
"identity:create_grant": "rule:admin_required",
"identity:revoke_grant": "rule:admin_required",
"identity:list_role_assignments": "rule:admin_required",
"identity:get_policy": "rule:admin_required",
"identity:list_policies": "rule:admin_required",
"identity:create_policy": "rule:admin_required",
"identity:update_policy": "rule:admin_required",
"identity:delete_policy": "rule:admin_required",
"identity:check_token": "rule:admin_or_token_subject",
"identity:validate_token": "rule:service_admin_or_token_subject",
"identity:validate_token_head": "rule:service_or_admin",
"identity:revocation_list": "rule:service_or_admin",
"identity:revoke_token": "rule:admin_or_token_subject",
"identity:create_trust": "user_id:%(trust.trustor_user_id)s",
"identity:list_trusts": "",
"identity:list_roles_for_trust": "",
"identity:get_role_for_trust": "",
"identity:delete_trust": "",
"identity:create_consumer": "rule:admin_required",
"identity:get_consumer": "rule:admin_required",
"identity:list_consumers": "rule:admin_required",
"identity:delete_consumer": "rule:admin_required",
"identity:update_consumer": "rule:admin_required",
"identity:authorize_request_token": "rule:admin_required",
"identity:list_access_token_roles": "rule:admin_required",
"identity:get_access_token_role": "rule:admin_required",
"identity:list_access_tokens": "rule:admin_required",
"identity:get_access_token": "rule:admin_required",
"identity:delete_access_token": "rule:admin_required",
"identity:list_projects_for_endpoint": "rule:admin_required",
"identity:add_endpoint_to_project": "rule:admin_required",
"identity:check_endpoint_in_project": "rule:admin_required",
"identity:list_endpoints_for_project": "rule:admin_required",
"identity:remove_endpoint_from_project": "rule:admin_required",
"identity:create_endpoint_group": "rule:admin_required",
"identity:list_endpoint_groups": "rule:admin_required",
"identity:get_endpoint_group": "rule:admin_required",
"identity:update_endpoint_group": "rule:admin_required",
"identity:delete_endpoint_group": "rule:admin_required",
"identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
"identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
"identity:get_endpoint_group_in_project": "rule:admin_required",
"identity:list_endpoint_groups_for_project": "rule:admin_required",
"identity:add_endpoint_group_to_project": "rule:admin_required",
"identity:remove_endpoint_group_from_project": "rule:admin_required",
"identity:create_identity_provider": "rule:admin_required",
"identity:list_identity_providers": "rule:admin_required",
"identity:get_identity_providers": "rule:admin_required",
"identity:update_identity_provider": "rule:admin_required",
"identity:delete_identity_provider": "rule:admin_required",
"identity:create_protocol": "rule:admin_required",
"identity:update_protocol": "rule:admin_required",
"identity:get_protocol": "rule:admin_required",
"identity:list_protocols": "rule:admin_required",
"identity:delete_protocol": "rule:admin_required",
"identity:create_mapping": "rule:admin_required",
"identity:get_mapping": "rule:admin_required",
"identity:list_mappings": "rule:admin_required",
"identity:delete_mapping": "rule:admin_required",
"identity:update_mapping": "rule:admin_required",
"identity:create_service_provider": "rule:admin_required",
"identity:list_service_providers": "rule:admin_required",
"identity:get_service_provider": "rule:admin_required",
"identity:update_service_provider": "rule:admin_required",
"identity:delete_service_provider": "rule:admin_required",
"identity:get_auth_catalog": "",
"identity:get_auth_projects": "",
"identity:get_auth_domains": "",
"identity:list_projects_for_groups": "",
"identity:list_domains_for_groups": "",
"identity:list_revoke_events": "",
"identity:create_policy_association_for_endpoint": "rule:admin_required",
"identity:check_policy_association_for_endpoint": "rule:admin_required",
"identity:delete_policy_association_for_endpoint": "rule:admin_required",
"identity:create_policy_association_for_service": "rule:admin_required",
"identity:check_policy_association_for_service": "rule:admin_required",
"identity:delete_policy_association_for_service": "rule:admin_required",
"identity:create_policy_association_for_region_and_service": "rule:admin_required",
"identity:check_policy_association_for_region_and_service": "rule:admin_required",
"identity:delete_policy_association_for_region_and_service": "rule:admin_required",
"identity:get_policy_for_endpoint": "rule:admin_required",
"identity:list_endpoints_for_policy": "rule:admin_required",
"identity:create_domain_config": "rule:admin_required",
"identity:get_domain_config": "rule:admin_required",
"identity:update_domain_config": "rule:admin_required",
"identity:delete_domain_config": "rule:admin_required"
}
{% endif -%}

View File

@ -4,7 +4,6 @@
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
use_syslog = {{ use_syslog }}
log_config_append = /etc/keystone/logging.conf
debug = {{ debug }}
@ -111,4 +110,4 @@ admin_project_name = admin
{% include "section-oslo-middleware" %}
# This goes in the section above, selectively
# Bug #1819134
max_request_body_size = 114688
max_request_body_size = 114688

View File

@ -1,7 +1,11 @@
{% if api_version == 3 -%}
{
"admin_required": "role:{{ admin_role }}",
"cloud_admin": "rule:admin_required and (token.is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% if transitional_charm_user_id %}
"cloud_admin": "rule:admin_required and (user_id:{{ transitional_charm_user_id }} or token.is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% else %}
"cloud_admin": "rule:admin_required",
{% endif %}
"service_role": "role:service",
"service_or_admin": "rule:admin_required or rule:service_role",
"owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",

View File

@ -1,7 +1,11 @@
{% if api_version == 3 -%}
{
"admin_required": "role:{{ admin_role }}",
"cloud_admin": "rule:admin_required and (token.is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% if transitional_charm_user_id %}
"cloud_admin": "rule:admin_required and (user_id:{{ transitional_charm_user_id }} or token.is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% else %}
"cloud_admin": "rule:admin_required",
{% endif %}
"service_role": "role:service",
"service_or_admin": "rule:admin_required or rule:service_role",
"owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",

View File

@ -4,7 +4,6 @@
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
use_syslog = {{ use_syslog }}
log_config_append = {{ log_config }}
debug = {{ debug }}

View File

@ -1,7 +1,11 @@
{% if api_version == 3 -%}
{
"admin_required": "role:{{ admin_role }}",
"cloud_admin": "rule:admin_required and (is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% if transitional_charm_user_id %}
"cloud_admin": "rule:admin_required and (user_id:{{ transitional_charm_user_id }} or token.is_admin_project:True or domain_id:{{ admin_domain_id }} or project_id:{{ service_tenant_id }})",
{% else %}
"cloud_admin": "rule:admin_required",
{% endif %}
"service_role": "role:service",
"service_or_admin": "rule:admin_required or rule:service_role",
"owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",

View File

@ -4,7 +4,6 @@
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
use_syslog = {{ use_syslog }}
log_config_append = {{ log_config }}
debug = {{ debug }}

View File

@ -4,7 +4,6 @@
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
admin_token = {{ token }}
use_syslog = {{ use_syslog }}
log_config_append = {{ log_config }}
debug = {{ debug }}

View File

@ -582,6 +582,7 @@ class KeystoneRelationTests(CharmTestCase):
cmd = ['a2dissite', 'openstack_https_frontend']
self.check_call.assert_called_with(cmd)
@patch.object(hooks, 'bootstrap_keystone')
@patch.object(hooks,
'ensure_all_service_accounts_protected_for_pci_dss_options')
@patch.object(hooks, 'maybe_do_policyd_overrides')
@ -601,7 +602,8 @@ class KeystoneRelationTests(CharmTestCase):
os_release,
update,
mock_maybe_do_policyd_overrides,
mock_protect_service_accounts):
mock_protect_service_accounts,
mock_bootstrap_keystone):
os_release.return_value = 'havana'
mock_is_db_initialised.return_value = True
mock_is_db_ready.return_value = True
@ -615,11 +617,13 @@ class KeystoneRelationTests(CharmTestCase):
self.assertTrue(update.called)
self.remove_old_packages.assert_called_once_with()
self.service_restart.assert_called_with('apache2')
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
mock_stop_manager_instance.assert_called_once_with()
mock_maybe_do_policyd_overrides.assert_called_once_with(
ANY, "keystone")
mock_protect_service_accounts.assert_called_once_with()
@patch.object(hooks, 'bootstrap_keystone')
@patch.object(hooks,
'ensure_all_service_accounts_protected_for_pci_dss_options')
@patch.object(hooks, 'maybe_do_policyd_overrides')
@ -639,7 +643,8 @@ class KeystoneRelationTests(CharmTestCase):
os_release,
update,
mock_maybe_do_policyd_overrides,
mock_protect_service_accounts):
mock_protect_service_accounts,
mock_bootstrap_keystone):
os_release.return_value = 'havana'
mock_is_db_initialised.return_value = True
mock_is_db_ready.return_value = True
@ -653,15 +658,17 @@ class KeystoneRelationTests(CharmTestCase):
self.assertTrue(update.called)
self.remove_old_packages.assert_called_once_with()
self.service_restart.assert_called_with('apache2')
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
mock_stop_manager_instance.assert_called_once_with()
mock_maybe_do_policyd_overrides.assert_called_once_with(
ANY, "keystone")
mock_protect_service_accounts.assert_called_once_with()
@patch.object(hooks, 'bootstrap_keystone')
@patch.object(hooks, 'update_all_identity_relation_units')
@patch.object(hooks, 'is_db_initialised')
def test_leader_init_db_if_ready(self, is_db_initialized,
update):
update, mock_bootstrap_keystone):
""" Verify leader initilaizes db """
self.is_elected_leader.return_value = True
is_db_initialized.return_value = False
@ -670,6 +677,7 @@ class KeystoneRelationTests(CharmTestCase):
hooks.leader_init_db_if_ready()
self.is_db_ready.assert_called_with(use_current_context=False)
self.migrate_database.assert_called_with()
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
update.assert_called_with(check_db_ready=False)
@patch.object(hooks, 'update_all_identity_relation_units')
@ -803,6 +811,7 @@ class KeystoneRelationTests(CharmTestCase):
# Still updates relations
self.assertTrue(self.relation_ids.called)
@patch.object(hooks, 'bootstrap_keystone')
@patch.object(hooks, 'maybe_do_policyd_overrides')
@patch.object(hooks, 'update_all_identity_relation_units')
@patch.object(utils, 'os_release')
@ -814,7 +823,8 @@ class KeystoneRelationTests(CharmTestCase):
mock_relation_ids,
mock_log,
os_release, update,
mock_maybe_do_policyd_overrides):
mock_maybe_do_policyd_overrides,
mock_bootstrap_keystone):
os_release.return_value = 'havana'
self.filter_installed_packages.return_value = ['something']
@ -823,10 +833,12 @@ class KeystoneRelationTests(CharmTestCase):
self.assertTrue(self.apt_install.called)
self.assertTrue(self.log.called)
self.assertFalse(update.called)
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
mock_stop_manager_instance.assert_called_once()
mock_maybe_do_policyd_overrides.assert_called_once_with(
ANY, "keystone")
@patch.object(hooks, 'bootstrap_keystone')
@patch.object(hooks, 'maybe_do_policyd_overrides')
@patch.object(hooks, 'update_all_identity_relation_units')
@patch.object(utils, 'os_release')
@ -840,7 +852,8 @@ class KeystoneRelationTests(CharmTestCase):
mock_log,
os_release,
update,
mock_maybe_do_policyd_overrides
mock_maybe_do_policyd_overrides,
mock_bootstrap_keystone,
):
os_release.return_value = 'havana'
@ -850,6 +863,7 @@ class KeystoneRelationTests(CharmTestCase):
self.assertFalse(self.apt_install.called)
self.assertTrue(self.log.called)
self.assertFalse(update.called)
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
mock_stop_manager_instance.assert_called_once()
mock_maybe_do_policyd_overrides.assert_called_once_with(
ANY, "keystone")

View File

@ -15,7 +15,7 @@
import builtins
import collections
import copy
from mock import patch, call, MagicMock, mock_open, Mock
from mock import ANY, patch, call, MagicMock, mock_open, Mock
import json
import os
import subprocess
@ -23,6 +23,8 @@ import time
from test_utils import CharmTestCase
import keystone_types as ks_types
os.environ['JUJU_UNIT_NAME'] = 'keystone'
with patch('charmhelpers.core.hookenv.config') as config, \
patch('charmhelpers.contrib.openstack.'
@ -42,7 +44,6 @@ TO_PATCH = [
'create_role',
'create_service_entry',
'create_endpoint_template',
'get_admin_token',
'get_local_endpoint',
'get_requested_roles',
'get_service_password',
@ -242,6 +243,7 @@ class TestKeystoneUtils(CharmTestCase):
if p.startswith('python-')] +
['python-keystone', 'python-memcache'])
@patch.object(utils, 'bootstrap_keystone')
@patch.object(utils, 'is_elected_leader')
@patch.object(utils, 'disable_unused_apache_sites')
@patch('os.path.exists')
@ -251,7 +253,7 @@ class TestKeystoneUtils(CharmTestCase):
def test_openstack_upgrade_leader(
self, migrate_database, determine_packages,
run_in_apache, os_path_exists, disable_unused_apache_sites,
mock_is_elected_leader):
mock_is_elected_leader, mock_bootstrap_keystone):
configs = MagicMock()
self.test_config.set('openstack-origin', 'cloud:xenial-newton')
self.os_release.return_value = 'ocata'
@ -285,6 +287,7 @@ class TestKeystoneUtils(CharmTestCase):
self.assertTrue(configs.set_release.called)
self.assertTrue(configs.write_all.called)
self.assertTrue(migrate_database.called)
mock_bootstrap_keystone.assert_called_once_with(configs=ANY)
disable_unused_apache_sites.assert_called_with()
self.reset_os_release.assert_called()
@ -374,7 +377,6 @@ class TestKeystoneUtils(CharmTestCase):
leader_get.return_value = None
relation_id = 'identity-service:0'
remote_unit = 'unit/0'
self.get_admin_token.return_value = 'token'
self.get_service_password.return_value = 'password'
self.test_config.set('service-tenant', 'tenant')
self.test_config.set('admin-role', 'Admin')
@ -418,7 +420,6 @@ class TestKeystoneUtils(CharmTestCase):
publicurl='10.0.0.1',
adminurl='10.0.0.2',
internalurl='192.168.1.2')
self.assertTrue(self.get_admin_token.called)
self.get_service_password.assert_called_with('keystone')
create_user.assert_called_with('keystone', 'password',
domain=service_domain,
@ -435,7 +436,7 @@ class TestKeystoneUtils(CharmTestCase):
'admin_user_id': admin_user_id,
'admin_project_id': admin_project_id,
'auth_host': '10.0.0.3',
'service_host': '10.0.0.3', 'admin_token': 'token',
'service_host': '10.0.0.3',
'service_port': 81, 'auth_port': 80,
'service_username': 'keystone',
'service_password': 'password',
@ -1830,3 +1831,78 @@ class TestKeystoneUtils(CharmTestCase):
self.assertEqual(csum,
('d938ff5656d3d9b50345e8061b4c73c8'
'116a9c7fbc087765ce2e3a4a5df7cb17'))
@patch.object(utils, 'leader_get')
def test_get_charm_credentials(self, mock_leader_get):
expect = ks_types.CharmCredentials(
'_charm-keystone-admin', 'fakepassword',
'all', 'admin', 'default', 'default')
mock_leader_get.return_value = 'fakepassword'
self.assertEquals(utils.get_charm_credentials(), expect)
mock_leader_get.assert_called_once_with(expect.username + '_passwd')
mock_leader_get.retrun_value = None
mock_leader_get.side_effect = [None]
with self.assertRaises(RuntimeError):
utils.get_charm_credentials()
@patch.object(utils, 'leader_get')
def test_is_bootstrapped(self, mock_leader_get):
mock_leader_get.side_effect = [None, None]
self.assertFalse(utils.is_bootstrapped())
mock_leader_get.assert_called_once_with('keystone-bootstrapped')
mock_leader_get.side_effect = [True, None]
self.assertFalse(utils.is_bootstrapped())
mock_leader_get.side_effect = [True, 'fakepassword']
self.assertTrue(utils.is_bootstrapped())
mock_leader_get.assert_called_with('_charm-keystone-admin_passwd')
@patch.object(utils, 'get_manager')
@patch.object(utils, 'leader_set')
@patch.object(utils, 'resolve_address')
@patch.object(utils, 'endpoint_url')
@patch.object(utils, 'pwgen')
@patch.object(utils, 'leader_get')
@patch.object(utils, 'get_api_suffix')
def test_bootstrap_keystone(
self,
mock_get_api_suffix,
mock_leader_get,
mock_pwgen,
mock_endpoint_url,
mock_resolve_address,
mock_leader_set,
mock_get_manager):
configs = MagicMock()
mock_get_api_suffix.return_value = 'suffix'
mock_resolve_address.side_effect = lambda x: x
mock_endpoint_url.side_effect = (
lambda x, y, z: 'http://{}:{}/{}'.format(x, y, z))
mock_leader_get.return_value = 'fakepassword'
mock_get_manager().resolve_user_id.return_value = 'fakeid'
self.os_release.return_value = 'queens'
utils.bootstrap_keystone(configs=configs)
self.subprocess.check_call.assert_called_once_with(
('keystone-manage', 'bootstrap',
'--bootstrap-username', '_charm-keystone-admin',
'--bootstrap-password', 'fakepassword',
'--bootstrap-project-name', 'admin',
'--bootstrap-role-name', 'Admin',
'--bootstrap-service-name', 'keystone',
'--bootstrap-admin-url', 'http://admin:35357/suffix',
'--bootstrap-public-url', 'http://public:5000/suffix',
'--bootstrap-internal-url', 'http://int:5000/suffix',
'--bootstrap-region-id', 'RegionOne'),
)
mock_leader_set.assert_called_once_with({
'keystone-bootstrapped': True,
'_charm-keystone-admin_passwd': 'fakepassword'})
self.assertFalse(configs.write_all.called)
mock_leader_set.reset_mock()
self.os_release.return_value = 'pike'
utils.bootstrap_keystone(configs=configs)
mock_leader_set.assert_has_calls([
call({'keystone-bootstrapped': True,
'_charm-keystone-admin_passwd': 'fakepassword'}),
call({'transitional_charm_user_id': 'fakeid'}),
])
configs.write_all.assert_called_once_with()