Merge "Store BMC password in Openstack Barbican instead of keyring."

This commit is contained in:
Zuul 2019-02-13 15:54:41 +00:00 committed by Gerrit Code Review
commit e1dd3de752
7 changed files with 164 additions and 115 deletions

View File

@ -546,20 +546,13 @@ fm::database_max_overflow: 20
fm::database_max_pool_size: 1 fm::database_max_pool_size: 1
# Barbican # Barbican
barbican::use_syslog: true
barbican::log_facility: 'local2'
barbican::database_idle_timeout: 60
barbican::database_max_pool_size: 1
barbican::database_max_overflow: 10
barbican::alarm_history_time_to_live: 86400
barbican::auth::auth_endpoint_type: 'internalURL'
barbican::db::sync::user: 'root'
barbican::api::enabled: false barbican::api::enabled: false
barbican::api::service_name: 'barbican-api' barbican::api::service_name: 'barbican-api'
barbican::api::enable_proxy_headers_parsing: true barbican::api::enable_proxy_headers_parsing: true
barbican::api::logging::use_syslog: true
barbican::api::logging::log_facility: 'local2'
barbican::db::sync::user: 'root'
barbican::db::database_idle_timeout: 60
barbican::db::database_max_pool_size: 1
barbican::keystone-listener::enabled: false barbican::keystone-listener::enabled: false
barbican::worker::enabled: false barbican::worker::enabled: false

View File

@ -55,12 +55,15 @@ class openstack::barbican::service
} }
$api_fqdn = $::platform::params::controller_hostname $api_fqdn = $::platform::params::controller_hostname
$url_host = "http://${api_fqdn}:${api_port}" $url_host = "http://${api_fqdn}:${api_port}"
if str2bool($::is_initial_config_primary) {
$enabled = true
} else {
$enabled = false
}
include ::platform::amqp::params include ::platform::amqp::params
class { '::barbican::api': class { '::barbican::api':
enabled => true, enabled => $enabled,
manage_service => true,
bind_host => $api_host, bind_host => $api_host,
bind_port => $api_port, bind_port => $api_port,
host_href => $url_host, host_href => $url_host,

View File

@ -2440,15 +2440,9 @@ class HostController(rest.RestController):
"problem persists then contact your system " "problem persists then contact your system "
"administrator.")) "administrator."))
# tell conductor to delete the keystore entry associated # tell conductor to delete the barbican entry associated with this host (if present)
# with this host (if present) pecan.request.rpcapi.delete_barbican_secret(pecan.request.context,
try: host.uuid)
pecan.request.rpcapi.unconfigure_keystore_account(
pecan.request.context,
KEYRING_BM_SERVICE,
ihost.uuid)
except exception.NotFound:
pass
# Notify patching to drop the host # Notify patching to drop the host
if ihost.hostname is not None: if ihost.hostname is not None:
@ -3795,7 +3789,7 @@ class HostController(rest.RestController):
raise wsme.exc.ClientSideError( raise wsme.exc.ClientSideError(
_("Host-add Rejected: bm_ip %s already exists") % phost['bm_ip']) _("Host-add Rejected: bm_ip %s already exists") % phost['bm_ip'])
# Update keyring with updated board management credentials (if supplied) # Update barbican with updated board management credentials (if supplied)
if (ohost['bm_username'] and phost['bm_username'] and if (ohost['bm_username'] and phost['bm_username'] and
(ohost['bm_username'] != phost['bm_username'])): (ohost['bm_username'] != phost['bm_username'])):
if not password_exists: if not password_exists:
@ -3806,12 +3800,11 @@ class HostController(rest.RestController):
ohost['bm_username'], ohost['bm_username'],
phost['bm_username']))) phost['bm_username'])))
if password_exists: if password_exists and patch_bm_password:
# The conductor will handle creating the keystore acct pecan.request.rpcapi.create_barbican_secret(pecan.request.context,
pecan.request.rpcapi.configure_keystore_account(pecan.request.context, phost['uuid'],
KEYRING_BM_SERVICE, patch_bm_password)
phost['uuid'],
patch_bm_password)
LOG.info("%s bm semantic checks for user_agent %s passed" % LOG.info("%s bm semantic checks for user_agent %s passed" %
(phost['hostname'], pecan.request.user_agent)) (phost['hostname'], pecan.request.user_agent))

View File

@ -45,7 +45,6 @@ import uuid
import xml.etree.ElementTree as ElementTree import xml.etree.ElementTree as ElementTree
from contextlib import contextmanager from contextlib import contextmanager
import keyring
import tsconfig.tsconfig as tsc import tsconfig.tsconfig as tsc
from cgcs_patch.patch_verify import verify_files from cgcs_patch.patch_verify import verify_files
from controllerconfig.upgrades import management as upgrades_management from controllerconfig.upgrades import management as upgrades_management
@ -9428,38 +9427,23 @@ class ConductorManager(service.PeriodicService):
target_load = self.dbapi.load_get(host_upgrade.target_load) target_load = self.dbapi.load_get(host_upgrade.target_load)
return target_load.software_version == tsc.SW_VERSION return target_load.software_version == tsc.SW_VERSION
def configure_keystore_account(self, context, service_name, def create_barbican_secret(self, context, name, payload):
username, password): """Calls Barbican API to create a secret
"""Synchronously, have a conductor configure a ks(keyring) account.
Does the following tasks:
- call keyring API to create an account under a service.
:param context: request context. :param context: request context.
:param service_name: the keystore service. :param name: secret name
:param username: account username :param payload: secret payload
:param password: account password
""" """
if (not service_name.strip()): self._openstack.create_barbican_secret(context=context,
raise exception.SysinvException(_( name=name, payload=payload)
"Keystore service is a blank value"))
keyring.set_password(service_name, username, password) def delete_barbican_secret(self, context, name):
"""Calls Barbican API to delete a secret
def unconfigure_keystore_account(self, context, service_name, username):
"""Synchronously, have a conductor unconfigure a ks(keyring) account.
Does the following tasks:
- call keyring API to delete an account under a service.
:param context: request context. :param context: request context.
:param service_name: the keystore service. :param name: secret name
:param username: account username
""" """
try: self._openstack.delete_barbican_secret(context=context, name=name)
keyring.delete_password(service_name, username)
except keyring.errors.PasswordDeleteError:
pass
def update_snmp_config(self, context): def update_snmp_config(self, context):
"""Update the snmpd configuration""" """Update the snmpd configuration"""

View File

@ -26,7 +26,7 @@ from keystoneclient.auth.identity import v3
from keystoneclient import session from keystoneclient import session
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from magnumclient.v1 import client as magnum_client_v1 from magnumclient.v1 import client as magnum_client_v1
from barbicanclient.v1 import client as barbican_client_v1
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -105,6 +105,9 @@ openstack_keystone_opts = [
cfg.StrOpt('magnum_region_name', cfg.StrOpt('magnum_region_name',
default='RegionOne', default='RegionOne',
help=_("Magnum Region Name")), help=_("Magnum Region Name")),
cfg.StrOpt('barbican_region_name',
default='RegionOne',
help=_("Barbican Region Name")),
cfg.StrOpt('project_name', cfg.StrOpt('project_name',
default='admin', default='admin',
help=_("keystone user project name")), help=_("keystone user project name")),
@ -129,9 +132,12 @@ class OpenStackOperator(object):
def __init__(self, dbapi): def __init__(self, dbapi):
self.dbapi = dbapi self.dbapi = dbapi
self.barbican_client = None
self.cinder_client = None self.cinder_client = None
self.keystone_client = None self.keystone_client = None
self.keystone_session = None self.keystone_session = None
self.openstack_keystone_client = None
self.openstack_keystone_session = None
self.magnum_client = None self.magnum_client = None
self.nova_client = None self.nova_client = None
self.neutron_client = None self.neutron_client = None
@ -530,29 +536,7 @@ class OpenStackOperator(object):
################# #################
# Keystone # Keystone
################# #################
def _get_keystone_session(self, service_config): def _get_keystone_password(self, service_config):
if not self.keystone_session:
if service_config == OPENSTACK_CONFIG:
password = keyring.get_password(cfg.CONF[OPENSTACK_CONFIG].
keyring_service,
cfg.CONF[OPENSTACK_CONFIG].
username)
else:
password = cfg.CONF[service_config].password
auth = v3.Password(auth_url=self._get_auth_url(service_config),
username=cfg.CONF[service_config].username,
password=password,
user_domain_name=cfg.CONF[service_config].
user_domain_name,
project_name=cfg.CONF[service_config].
project_name,
project_domain_name=cfg.CONF[service_config].
project_domain_name)
self.keystone_session = session.Session(auth=auth)
return self.keystone_session
def _get_keystoneclient(self, service_config):
if service_config == OPENSTACK_CONFIG: if service_config == OPENSTACK_CONFIG:
password = keyring.get_password(cfg.CONF[OPENSTACK_CONFIG]. password = keyring.get_password(cfg.CONF[OPENSTACK_CONFIG].
keyring_service, keyring_service,
@ -560,18 +544,70 @@ class OpenStackOperator(object):
username) username)
else: else:
password = cfg.CONF[service_config].password password = cfg.CONF[service_config].password
return password
if not self.keystone_client: # should not cache this forever def _get_new_keystone_session(self, service_config):
self.keystone_client = keystone_client.Client( auth = v3.Password(auth_url=self._get_auth_url(service_config),
username=cfg.CONF[service_config].username, username=cfg.CONF[service_config].username,
user_domain_name=cfg.CONF[service_config].user_domain_name, password=self._get_keystone_password(service_config),
project_name=cfg.CONF[service_config].project_name, user_domain_name=cfg.CONF[service_config].
project_domain_name=cfg.CONF[service_config] user_domain_name,
.project_domain_name, project_name=cfg.CONF[service_config].
password=password, project_name,
auth_url=self._get_auth_url(service_config), project_domain_name=cfg.CONF[service_config].
region_name=cfg.CONF[service_config].region_name) project_domain_name)
return self.keystone_client sess = session.Session(auth=auth)
return sess
def _get_cached_keystone_session(self, service_config):
if service_config == OPENSTACK_CONFIG:
return self.openstack_keystone_session
else:
return self.keystone_session
def _set_cached_keystone_session(self, service_config, sess):
if service_config == OPENSTACK_CONFIG:
self.openstack_keystone_session = sess
else:
self.keystone_session = sess
def _get_keystone_session(self, service_config):
sess = self._get_cached_keystone_session(service_config)
if not sess:
sess = self._get_new_keystone_session(service_config)
self._set_cached_keystone_session(service_config, sess)
return sess
def _get_new_keystone_client(self, service_config):
client = keystone_client.Client(
username=cfg.CONF[service_config].username,
user_domain_name=cfg.CONF[service_config].user_domain_name,
project_name=cfg.CONF[service_config].project_name,
project_domain_name=cfg.CONF[service_config]
.project_domain_name,
password=self._get_keystone_password(service_config),
auth_url=self._get_auth_url(service_config),
region_name=cfg.CONF[service_config].region_name)
return client
def _get_cached_keystone_client(self, service_config):
if service_config == OPENSTACK_CONFIG:
return self.openstack_keystone_client
else:
return self.keystone_client
def _set_cached_keystone_client(self, service_config, client):
if service_config == OPENSTACK_CONFIG:
self.openstack_keystone_client = client
else:
self.keystone_client = client
def _get_keystone_client(self, service_config):
client = self._get_cached_keystone_client(service_config)
if not client:
client = self._get_new_keystone_client(service_config)
self._set_cached_keystone_client(service_config, client)
return client
################# #################
# Cinder # Cinder
@ -785,6 +821,56 @@ class OpenStackOperator(object):
LOG.error("Unable to get backend list of magnum clusters") LOG.error("Unable to get backend list of magnum clusters")
return 0 return 0
#################
# Barbican
#################
def _get_barbicanclient(self):
if not self.barbican_client:
self.barbican_client = barbican_client_v1.Client(
session=self._get_keystone_session(PLATFORM_CONFIG),
interface='internalURL',
region_name=cfg.CONF[OPENSTACK_CONFIG].barbican_region_name)
return self.barbican_client
def get_barbican_secret_by_name(self, context, name):
try:
client = self._get_barbicanclient()
secret_list = client.secrets.list(name=name)
secret = next(iter(secret_list), None)
return secret
except Exception:
LOG.error("Unable to find Barbican secret %s", name)
return None
def create_barbican_secret(self, context, name, payload):
if not payload:
LOG.error("Empty password is passed to Barbican %s" % name)
return None
try:
client = self._get_barbicanclient()
secret = self.get_barbican_secret_by_name(context, name)
if secret:
client.secrets.delete(secret.secret_ref)
secret = client.secrets.create(name, payload)
secret.store()
return secret.secret_ref
except Exception:
LOG.error("Unable to create Barbican secret %s" % name)
return None
def delete_barbican_secret(self, context, name):
try:
client = self._get_barbicanclient()
secret = self.get_barbican_secret_by_name(context=context, name=name)
if not secret:
LOG.error("Unable to delete unknown Barbican secret %s" % name)
return False
client.secrets.delete(secret_ref=secret.secret_ref)
return True
except Exception:
LOG.error("Unable to delete Barbican secret %s" % name)
return False
def get_region_name(region): def get_region_name(region):
# get region name from platform.conf # get region name from platform.conf

View File

@ -1343,37 +1343,27 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
return self.call(context, return self.call(context,
self.make_msg('update_vswitch_type')) self.make_msg('update_vswitch_type'))
def configure_keystore_account(self, context, service_name, def create_barbican_secret(self, context, name, payload):
username, password): """Calls Barbican API to create a secret
"""Synchronously, have a conductor configure a ks(keyring) account.
Does the following tasks:
- call keyring API to create an account under a service.
:param context: request context. :param context: request context.
:param service_name: the keystore service. :param name: secret name
:param username: account username :param payload: secret payload
:param password: account password
""" """
return self.call(context, return self.call(context,
self.make_msg('configure_keystore_account', self.make_msg('create_barbican_secret',
service_name=service_name, name=name,
username=username, password=password)) payload=payload))
def unconfigure_keystore_account(self, context, service_name, username): def delete_barbican_secret(self, context, name):
"""Synchronously, have a conductor unconfigure a ks(keyring) account. """Calls Barbican API to delete a secret
Does the following tasks:
- call keyring API to delete an account under a service.
:param context: request context. :param context: request context.
:param service_name: the keystore service. :param name: secret name
:param username: account username
""" """
return self.call(context, return self.call(context,
self.make_msg('unconfigure_keystore_account', self.make_msg('delete_barbican_secret',
service_name=service_name, name=name))
username=username))
def update_snmp_config(self, context): def update_snmp_config(self, context):
"""Synchronously, have a conductor configure the SNMP configuration. """Synchronously, have a conductor configure the SNMP configuration.

View File

@ -59,7 +59,7 @@ class BarbicanPuppet(openstack.OpenstackBasePuppet):
'barbican::keystone::authtoken::project_domain_name': 'barbican::keystone::authtoken::project_domain_name':
self._get_service_project_domain_name(), self._get_service_project_domain_name(),
'barbican::keystone::authtoken::project_name': 'barbican::keystone::authtoken::project_name':
self._get_service_tenant_name(), self._get_service_project_name(),
'barbican::keystone::authtoken::region_name': 'barbican::keystone::authtoken::region_name':
self._keystone_region_name(), self._keystone_region_name(),
'barbican::keystone::authtoken::username': ksuser, 'barbican::keystone::authtoken::username': ksuser,