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
# 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::service_name: 'barbican-api'
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::worker::enabled: false

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@ from keystoneclient.auth.identity import v3
from keystoneclient import session
from sqlalchemy.orm import exc
from magnumclient.v1 import client as magnum_client_v1
from barbicanclient.v1 import client as barbican_client_v1
LOG = logging.getLogger(__name__)
@ -105,6 +105,9 @@ openstack_keystone_opts = [
cfg.StrOpt('magnum_region_name',
default='RegionOne',
help=_("Magnum Region Name")),
cfg.StrOpt('barbican_region_name',
default='RegionOne',
help=_("Barbican Region Name")),
cfg.StrOpt('project_name',
default='admin',
help=_("keystone user project name")),
@ -129,9 +132,12 @@ class OpenStackOperator(object):
def __init__(self, dbapi):
self.dbapi = dbapi
self.barbican_client = None
self.cinder_client = None
self.keystone_client = None
self.keystone_session = None
self.openstack_keystone_client = None
self.openstack_keystone_session = None
self.magnum_client = None
self.nova_client = None
self.neutron_client = None
@ -530,29 +536,7 @@ class OpenStackOperator(object):
#################
# Keystone
#################
def _get_keystone_session(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):
def _get_keystone_password(self, service_config):
if service_config == OPENSTACK_CONFIG:
password = keyring.get_password(cfg.CONF[OPENSTACK_CONFIG].
keyring_service,
@ -560,18 +544,70 @@ class OpenStackOperator(object):
username)
else:
password = cfg.CONF[service_config].password
return password
if not self.keystone_client: # should not cache this forever
self.keystone_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=password,
auth_url=self._get_auth_url(service_config),
region_name=cfg.CONF[service_config].region_name)
return self.keystone_client
def _get_new_keystone_session(self, service_config):
auth = v3.Password(auth_url=self._get_auth_url(service_config),
username=cfg.CONF[service_config].username,
password=self._get_keystone_password(service_config),
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)
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
@ -785,6 +821,56 @@ class OpenStackOperator(object):
LOG.error("Unable to get backend list of magnum clusters")
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):
# get region name from platform.conf

View File

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

View File

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