6e03a68c14
This driver is an oslo.config backend driver implemented with Castellan. It extends oslo.config's capabilities by enabling it to retrieve configuration values from a secret manager behind Castellan. Change-Id: Id7cf99bea5788e0a6309461a75eaa8d08d29641b Signed-off-by: Moises Guimaraes de Medeiros <moguimar@redhat.com>
142 lines
4.9 KiB
Python
142 lines
4.9 KiB
Python
# 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.
|
|
|
|
r"""
|
|
Castellan Oslo Config Driver
|
|
----------------------------
|
|
|
|
This driver is an oslo.config backend driver implemented with Castellan. It
|
|
extends oslo.config's capabilities by enabling it to retrieve configuration
|
|
values from a secret manager behind Castellan.
|
|
|
|
The setup of a Castellan configuration source is as follow::
|
|
|
|
[DEFAULT]
|
|
config_source = castellan_config_group
|
|
|
|
[castellan_config_group]
|
|
driver = castellan
|
|
config_file = castellan.conf
|
|
mapping_file = mapping.conf
|
|
|
|
In the following sessions, you can find more information about this driver's
|
|
classes and its options.
|
|
|
|
The Driver Class
|
|
================
|
|
|
|
.. autoclass:: CastellanConfigurationSourceDriver
|
|
|
|
The Configuration Source Class
|
|
==============================
|
|
|
|
.. autoclass:: CastellanConfigurationSource
|
|
|
|
"""
|
|
from castellan.common.exception import KeyManagerError
|
|
from castellan.common.exception import ManagedObjectNotFoundError
|
|
from castellan import key_manager
|
|
|
|
from oslo_config import cfg
|
|
from oslo_config import sources
|
|
from oslo_log import log
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class CastellanConfigurationSourceDriver(sources.ConfigurationSourceDriver):
|
|
"""A backend driver for configuration values served through castellan.
|
|
|
|
Required options:
|
|
- config_file: The castellan configuration file.
|
|
|
|
- mapping_file: A configuration/castellan_id mapping file. This file
|
|
creates connections between configuration options and
|
|
castellan ids. The group and option name remains the
|
|
same, while the value gets stored a secret manager behind
|
|
castellan and is replaced by its castellan id. The ids
|
|
will be used to fetch the values through castellan.
|
|
"""
|
|
|
|
_castellan_driver_opts = [
|
|
cfg.StrOpt(
|
|
'config_file',
|
|
required=True,
|
|
sample_default='etc/castellan/castellan.conf',
|
|
help=('The path to a castellan configuration file.'),
|
|
),
|
|
cfg.StrOpt(
|
|
'mapping_file',
|
|
required=True,
|
|
sample_default='etc/castellan/secrets_mapping.conf',
|
|
help=('The path to a configuration/castellan_id mapping file.'),
|
|
),
|
|
]
|
|
|
|
def list_options_for_discovery(self):
|
|
return self._castellan_driver_opts
|
|
|
|
def open_source_from_opt_group(self, conf, group_name):
|
|
conf.register_opts(self._castellan_driver_opts, group_name)
|
|
|
|
return CastellanConfigurationSource(
|
|
group_name,
|
|
conf[group_name].config_file,
|
|
conf[group_name].mapping_file)
|
|
|
|
|
|
class CastellanConfigurationSource(sources.ConfigurationSource):
|
|
"""A configuration source for configuration values served through castellan.
|
|
|
|
:param config_file: The path to a castellan configuration file.
|
|
|
|
:param mapping_file: The path to a configuration/castellan_id mapping file.
|
|
"""
|
|
|
|
def __init__(self, group_name, config_file, mapping_file):
|
|
conf = cfg.ConfigOpts()
|
|
conf(args=[], default_config_files=[config_file])
|
|
|
|
self._name = group_name
|
|
self._mngr = key_manager.API(conf)
|
|
self._mapping = {}
|
|
|
|
cfg.ConfigParser(mapping_file, self._mapping).parse()
|
|
|
|
def get(self, group_name, option_name, opt):
|
|
try:
|
|
group_name = group_name or "DEFAULT"
|
|
|
|
castellan_id = self._mapping[group_name][option_name][0]
|
|
|
|
return (self._mngr.get("ctx", castellan_id).get_encoded().decode(),
|
|
cfg.LocationInfo(cfg.Locations.user, castellan_id))
|
|
|
|
except KeyError:
|
|
# no mapping 'option = castellan_id'
|
|
LOG.info("option '[%s] %s' not present in '[%s] mapping_file'",
|
|
group_name, option_name, self._name)
|
|
|
|
except KeyManagerError:
|
|
# bad mapping 'option =' without a castellan_id
|
|
LOG.warning("missing castellan_id for option "
|
|
"'[%s] %s' in '[%s] mapping_file'",
|
|
group_name, option_name, self._name)
|
|
|
|
except ManagedObjectNotFoundError:
|
|
# good mapping, but unknown castellan_id by secret manager
|
|
LOG.warning("invalid castellan_id for option "
|
|
"'[%s] %s' in '[%s] mapping_file'",
|
|
group_name, option_name, self._name)
|
|
|
|
return (sources._NoValue, None)
|