def delete_proxy_user_for_job_execution(job_execution): '''Delete a proxy user based on a JobExecution :param job_execution: The job execution with proxy user information :returns: An updated job_configs dictionary or None ''' proxy_configs = job_execution.job_configs.get('proxy_configs') if proxy_configs is not None: proxy_username = proxy_configs.get('proxy_username') key = key_manager.API().get( context.current(), proxy_configs.get('proxy_password')) proxy_password = key.get_encoded() proxy_trust_id = proxy_configs.get('proxy_trust_id') proxy_user = k.auth_for_proxy(proxy_username, proxy_password, proxy_trust_id) t.delete_trust(proxy_user, proxy_trust_id) proxy_user_delete(proxy_username) key_manager.API().delete(context.current(), proxy_configs.get('proxy_password')) update = job_execution.job_configs.to_dict() del update['proxy_configs'] return update return None
def data_source_update(self, context, id, values): """Update the Data Source or raise if it does not exist.""" values = copy.deepcopy(values) values["id"] = id # in cases where the credentials to access the data source are # stored with the record and the external key manager is being # used, we need to delete the old key from the manager and # create a new one. the other option here would be to retrieve # the previous key and check to see if it has changed, but it # seems less expensive to just delete the old and create a new # one. # it should be noted that the jsonschema validation ensures that # if the proxy domain is not in use then credentials must be # sent with this record. if (CONF.use_barbican_key_manager and not CONF.use_domain_for_proxy_users): # first we retrieve the original record to get the old key # uuid, and delete it. ds_record = self.data_source_get(context, id) if (ds_record.get('credentials') and ds_record['credentials'].get('password')): key_manager.API().delete(context, ds_record['credentials']['password']) # next we create the new key. if (values.get('credentials') and values['credentials'].get('password')): key = passphrase.Passphrase(values['credentials']['password']) password = key_manager.API().store(context, key) values['credentials']['password'] = password return self.db.data_source_update(context, values)
def job_binary_update(self, context, id, values): """Update a JobBinary from the values dictionary.""" values = copy.deepcopy(values) values['id'] = id # in cases where the credentials to access the job binary are # stored with the record and the external key manager is being # used, we need to delete the old key from the manager and # create a new one. the other option here would be to retrieve # the previous key and check to see if it has changed, but it # seems less expensive to just delete the old and create a new # one. if (CONF.use_barbican_key_manager and not CONF.use_domain_for_proxy_users): # first we retrieve the original record to get the old key # uuid, and delete it. jb_record = self.job_binary_get(context, id) if jb_record.get('extra') and jb_record['extra'].get('password'): key_manager.API().delete(context, jb_record['extra']['password']) # next we create the new key. if values.get('extra') and values['extra'].get('password'): key = passphrase.Passphrase(values['extra']['password']) password = key_manager.API().store(context, key) values['extra']['password'] = password return self.db.job_binary_update(context, values)
def secdel_get_barbican_manager_and_ctxt(output_manager, conf, api_class): try: # FIXME: Parameters have different names if passed as options # to swift-client user_domain_name = conf.get('os_user_domain_name') if user_domain_name is None: user_domain_name = 'Default' project_domain_name = conf.get('os_project_domain_name') if project_domain_name is None: project_domain_name = 'Default' ctxt = keystone_password.KeystonePassword( username=conf.get('os_username'), password=conf.get('os_password'), project_name=conf.get('os_project_name'), user_domain_name=user_domain_name, project_domain_name=project_domain_name, user_id=conf.get('os_user_id'), user_domain_id=conf.get('os_user_domain_id'), trust_id=conf.get('os_trust_id'), domain_id=conf.get('os_domain_id'), domain_name=conf.get('os_domain_name'), project_id=conf.get('os_project_id'), project_domain_id=conf.get('os_project_domain_id'), reauthenticate=conf.get('reauthenticate')) oslo_conf = cfg.ConfigOpts() # FIXME: os_auth_url and not auth_endpoint? options.set_defaults( oslo_conf, auth_endpoint=conf.get('os_auth_url'), api_class=conf.get('api_class', api_class) ) options.enable_logging() manager = key_manager.API(oslo_conf) return manager, ctxt except SwiftError as e: output_manager.error(e.value)
def _encrypt_data(context, data): try: # TODO(pbourke): move auth construction into common area if it ends up # been required in other areas auth = identity.V3Password( auth_url=settings.KEY_MANAGER['auth_url'], username=settings.KEY_MANAGER['username'], user_domain_name=settings.KEY_MANAGER['user_domain_name'], password=settings.KEY_MANAGER['password'], project_name=settings.KEY_MANAGER['project_name'], project_domain_name=settings.KEY_MANAGER['project_domain_name'] ) except (KeyError, AttributeError) as e: LOG.exception(e) msg = ('Could not find valid key manager credentials in the ' 'murano-dashboard config. encryptData yaql function not ' 'available') raise castellan_exception.KeyManagerError(message_arg=msg) sess = session.Session(auth=auth) auth_context = _oslo_context.RequestContext( auth_token=auth.get_token(sess), tenant=auth.get_project_id(sess)) options.set_defaults(cfg.CONF, auth_endpoint=settings.KEY_MANAGER['auth_url']) manager = key_manager.API() try: # TODO(pbourke): while we feel opaque data should cover the most common # use case, we may want to add support for other secret types in the # future (see https://goo.gl/tZhfqe) stored_key_id = manager.store(auth_context, opaque_data.OpaqueData(data)) except castellan_exception.KeyManagerError as e: LOG.exception(e) raise return stored_key_id
def test_set_defaults(self): conf = cfg.ConfigOpts() self.assertTrue( isinstance(key_manager.API(conf), bkm.BarbicanKeyManager)) cls = mock_key_manager.MockKeyManager backend = '%s.%s' % (cls.__module__, cls.__name__) options.set_defaults(conf, backend=backend) self.assertEqual(backend, conf.key_manager.backend) self.assertIsInstance(key_manager.API(conf), mock_key_manager.MockKeyManager) barbican_endpoint = 'http://test-server.org:9311/' options.set_defaults(conf, barbican_endpoint=barbican_endpoint) self.assertEqual(barbican_endpoint, conf.get(bkm.BARBICAN_OPT_GROUP).barbican_endpoint) barbican_api_version = 'vSomething' options.set_defaults(conf, barbican_api_version=barbican_api_version) self.assertEqual(barbican_api_version, conf.get(bkm.BARBICAN_OPT_GROUP).barbican_api_version) auth_endpoint = 'http://test-server.org/identity' options.set_defaults(conf, auth_endpoint=auth_endpoint) self.assertEqual(auth_endpoint, conf.get(bkm.BARBICAN_OPT_GROUP).auth_endpoint) retry_delay = 3 options.set_defaults(conf, retry_delay=retry_delay) self.assertEqual(retry_delay, conf.get(bkm.BARBICAN_OPT_GROUP).retry_delay) number_of_retries = 10 options.set_defaults(conf, number_of_retries=number_of_retries) self.assertEqual(number_of_retries, conf.get(bkm.BARBICAN_OPT_GROUP).number_of_retries) verify_ssl = True options.set_defaults(conf, verify_ssl=True) self.assertEqual(verify_ssl, conf.get(bkm.BARBICAN_OPT_GROUP).verify_ssl) barbican_endpoint_type = 'internal' options.set_defaults(conf, barbican_endpoint_type='internal') result_type = conf.get(bkm.BARBICAN_OPT_GROUP).barbican_endpoint_type self.assertEqual(barbican_endpoint_type, result_type)
def key_manager(): conf = cfg.ConfigOpts() auth_endpoint = settings.OPENSTACK_KEYSTONE_URL insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) options.set_defaults(conf, auth_endpoint=auth_endpoint, verify_ssl=not insecure) return key_manager_api.API(conf)
def get_secret(): """Authenticates user and obtains the one time use key""" ctxt = kmgr_auth.get_context() config = get_config() kmgr = key_manager.API(config) secret_uuid = os.getenv('OS_SECRET_UUID', None) secret = kmgr.get(ctxt, secret_uuid) return secret.get_encoded()
def brick_get_encryptor(connection_info, *args, **kwargs): """Wrapper to get a brick encryptor object.""" root_helper = get_root_helper() km = key_manager.API(CONF) return encryptors.get_volume_encryptor(root_helper=root_helper, connection_info=connection_info, keymgr=km, *args, **kwargs)
def test_no_fixed_key(self): conf = self.conf conf.set_override('fixed_key', None, group='key_manager') key_mgr = key_manager.API(conf) self.assertNotEqual('MigrationKeyManager', type(key_mgr).__name__) self.assertRaises(exception.KeyManagerError, key_mgr.get, context=self.ctxt, managed_object_id=self.fixed_key_id)
def get_raw_data(job_binary, proxy_configs=None): conn_kwargs = {} if proxy_configs: key = key_manager.API().get(context.current(), proxy_configs.get('proxy_password')) password = key.get_encoded() conn_kwargs.update(username=proxy_configs.get('proxy_username'), password=password, trust_id=proxy_configs.get('proxy_trust_id')) else: key = key_manager.API().get(context.current(), job_binary.extra.get('password')) password = key.get_encoded() conn_kwargs.update(username=job_binary.extra.get('user'), password=password) conn = sw.client(**conn_kwargs) return _get_raw_data(job_binary, conn)
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 delete_secret(id, ctx=None): """delete a secret from the external key manager :param id: The identifier of the secret to delete :param ctx: The context, and associated authentication, to use with this operation (defaults to the current context) """ if ctx is None: ctx = context.current() key_manager.API().delete(ctx, id)
def get_secret(id, ctx=None): """get a secret associated with an id :param id: The identifier of the secret to retrieve :param ctx: The context, and associated authentication, to use with this operation (defaults to the current context) """ if ctx is None: ctx = context.current() key = key_manager.API().get(ctx, id) return key.get_encoded()
def _get_root_secret(self, conf): """ Retrieve the root encryption secret from an external key management system using Castellan. :param conf: the keymaster config section from proxy-server.conf :type conf: dict :return: the encryption root secret binary bytes :rtype: bytearray """ ctxt = keystone_password.KeystonePassword( auth_url=conf.get('auth_endpoint'), username=conf.get('username'), password=conf.get('password'), project_name=conf.get('project_name'), user_domain_name=conf.get('user_domain_name'), project_domain_name=conf.get('project_domain_name'), user_id=conf.get('user_id'), user_domain_id=conf.get('user_domain_id'), trust_id=conf.get('trust_id'), domain_id=conf.get('domain_id'), domain_name=conf.get('domain_name'), project_id=conf.get('project_id'), project_domain_id=conf.get('project_domain_id'), reauthenticate=conf.get('reauthenticate')) oslo_conf = cfg.ConfigOpts() options.set_defaults(oslo_conf, auth_endpoint=conf.get('auth_endpoint'), api_class=conf.get('api_class')) options.enable_logging() manager = key_manager.API(oslo_conf) key = manager.get(ctxt, conf.get('key_id')) if key is None: raise ValueError("Retrieval of encryption root secret with key_id " "'%s' returned None." % conf.get('key_id')) try: if (key.bit_length < 256) or (key.algorithm.lower() != "aes"): raise ValueError('encryption root secret stored in the ' 'external KMS must be an AES key of at least ' '256 bits (provided key length: %d, provided ' 'key algorithm: %s)' % (key.bit_length, key.algorithm)) if (key.format != 'RAW'): raise ValueError('encryption root secret stored in the ' 'external KMS must be in RAW format and not ' 'e.g., as a base64 encoded string (format of ' 'key with uuid %s: %s)' % (conf.get('key_id'), key.format)) except Exception: raise ValueError("Secret with key_id '%s' is not a symmetric key " "(type: %s)" % (conf.get('key_id'), str(type(key)))) return key.get_encoded()
def _run_backup(self, context, backup, volume): # Save a copy of the encryption key ID in case the volume is deleted. if (volume.encryption_key_id is not None and backup.encryption_key_id is None): backup.encryption_key_id = volume_utils.clone_encryption_key( context, key_manager.API(CONF), volume.encryption_key_id) backup.save() backup_service = self.service(context) properties = volume_utils.brick_get_connector_properties() # NOTE(geguileo): Not all I/O disk operations properly do greenthread # context switching and may end up blocking the greenthread, so we go # with native threads proxy-wrapping the device file object. try: backup_device = self.volume_rpcapi.get_backup_device( context, backup, volume) attach_info = self._attach_device(context, backup_device.device_obj, properties, backup_device.is_snapshot) try: device_path = attach_info['device']['path'] if (isinstance(device_path, str) and not os.path.isdir(device_path)): if backup_device.secure_enabled: with open(device_path, 'rb') as device_file: updates = backup_service.backup( backup, tpool.Proxy(device_file)) else: with utils.temporary_chown(device_path): with open(device_path, 'rb') as device_file: updates = backup_service.backup( backup, tpool.Proxy(device_file)) # device_path is already file-like so no need to open it else: updates = backup_service.backup(backup, tpool.Proxy(device_path)) finally: self._detach_device(context, attach_info, backup_device.device_obj, properties, backup_device.is_snapshot, force=True, ignore_errors=True) finally: with backup.as_read_deleted(): backup.refresh() self._cleanup_temp_volumes_snapshots_when_backup_created( context, backup) return updates
def test_using_conf_key_manager(self): conf = self.conf ckm_backend = 'castellan.tests.unit.key_manager.' \ 'test_migration_key_manager.ConfKeyManager' conf.set_override('backend', ckm_backend, group='key_manager') key_mgr = key_manager.API(conf) self.assertNotEqual('MigrationKeyManager', type(key_mgr).__name__) self.assertRaises(NotImplementedError, key_mgr.get, context=self.ctxt, managed_object_id=self.fixed_key_id)
def _create_key_manager(self): self.fixed_key = '1' * 64 try: self.conf.register_opt(cfg.StrOpt('fixed_key'), group='key_manager') except cfg.DuplicateOptError: pass self.conf.set_override('fixed_key', self.fixed_key, group='key_manager') return key_manager.API(self.conf)
def store_secret(secret, ctx=None): """store a secret and return its identifier :param secret: The secret to store, this should be a string :param ctx: The context, and associated authentication, to use with this operation (defaults to the current context) """ if ctx is None: ctx = context.current() key = passphrase.Passphrase(secret) return key_manager.API().store(ctx, key)
def job_binary_create(self, context, values): """Create a JobBinary from the values dictionary.""" values = copy.deepcopy(values) values = _apply_defaults(values, JOB_BINARY_DEFAULTS) values['tenant_id'] = context.tenant_id # if credentials are being passed in, we use the key_manager # to store the password. if values.get('extra') and values['extra'].get('password'): key = passphrase.Passphrase(values['extra']['password']) password = key_manager.API().store(context, key) values['extra']['password'] = password return self.db.job_binary_create(context, values)
def job_binary_destroy(self, context, job_binary): """Destroy the JobBinary or raise if it does not exist.""" # in cases where the credentials to access the job binary are # stored with the record and the external key manager is being # used, we need to delete the key from the external manager. if (CONF.use_barbican_key_manager and not CONF.use_domain_for_proxy_users): jb_record = self.job_binary_get(context, job_binary) if jb_record.get('extra') and jb_record['extra'].get('password'): key_manager.API().delete(context, jb_record['extra']['password']) self.db.job_binary_destroy(context, job_binary)
def data_source_destroy(self, context, data_source): """Destroy the Data Source or raise if it does not exist.""" # in cases where the credentials to access the data source are # stored with the record and the external key manager is being # used, we need to delete the key from the external manager. if (CONF.use_barbican_key_manager and not CONF.use_domain_for_proxy_users): ds_record = self.data_source_get(context, data_source) if (ds_record.get('credentials') and ds_record['credentials'].get('password')): key_manager.API().delete(context, ds_record['credentials']['password']) return self.db.data_source_destroy(context, data_source)
def data_source_create(self, context, values): """Create a Data Source from the values dictionary.""" values = copy.deepcopy(values) values = _apply_defaults(values, DATA_SOURCE_DEFAULTS) values['tenant_id'] = context.tenant_id # if credentials are being passed in, we use the key_manager # to store the password. if (values.get('credentials') and values['credentials'].get('password')): key = passphrase.Passphrase(values['credentials']['password']) password = key_manager.API().store(context, key) values['credentials']['password'] = password return self.db.data_source_create(context, values)
def delete_proxy_user_for_cluster(cluster): '''Delete a proxy user based on a Cluster :param cluster: The cluster model with proxy user information ''' proxy_configs = cluster.cluster_configs.get('proxy_configs') if proxy_configs is not None: proxy_username = proxy_configs.get('proxy_username') key = key_manager.API().get( context.current(), proxy_configs.get('proxy_password')) proxy_password = key.get_encoded() proxy_trust_id = proxy_configs.get('proxy_trust_id') proxy_user = k.auth_for_proxy(proxy_username, proxy_password, proxy_trust_id) t.delete_trust(proxy_user, proxy_trust_id) proxy_user_delete(proxy_username) key_manager.API().delete(context.current(), proxy_configs.get('proxy_password')) update = {'cluster_configs': cluster.cluster_configs.to_dict()} del update['cluster_configs']['proxy_configs'] conductor.cluster_update(context.ctx(), cluster, update)
def decrypt_data(value): manager = key_manager.API() try: context = castellan_utils.credential_factory(conf=cfg.CONF) except castellan_exception.AuthTypeInvalidError as e: LOG.exception(e) LOG.error("Castellan must be correctly configured in order to use " "decryptData()") raise try: data = manager.get(context, value).get_encoded() except castellan_exception.KeyManagerError as e: LOG.exception(e) raise return data
def get_configs(self, input_data, output_data, proxy_configs=None): configs = {} if proxy_configs: key = key_manager.API().get(context.current(), proxy_configs.get('proxy_password')) configs[sw.HADOOP_SWIFT_USERNAME] = proxy_configs.get( 'proxy_username') configs[sw.HADOOP_SWIFT_PASSWORD] = key.get_encoded() configs[sw.HADOOP_SWIFT_TRUST_ID] = proxy_configs.get( 'proxy_trust_id') configs[sw.HADOOP_SWIFT_DOMAIN_NAME] = CONF.proxy_user_domain_name return configs for src in (input_data, output_data): if src.type == "swift" and hasattr(src, "credentials"): if "user" in src.credentials: configs[sw.HADOOP_SWIFT_USERNAME] = src.credentials['user'] if "password" in src.credentials: key = key_manager.API().get(context.current(), src.credentials['password']) configs[sw.HADOOP_SWIFT_PASSWORD] = key.get_encoded() break return configs
def get_user_root_secret_by_id(self, account, user_token, key_id): """ Retrieve the user's root encryption secret with the specified ID from an external key management system using Castellan. :param account: the name of the account :type account: string :param user_token: the keystone token of the user from the request :type user_token: string :param key_id: the ID of the user's root encryption secret to retrieve :return: the binary bytes of the user's root encryption secret with the specified ID :rtype: bytearray """ user_root_secrets = self._user_root_secrets.get(account) if user_root_secrets is None: user_root_secrets = dict() else: encoded_key = user_root_secrets.get(key_id) if ROOT_SECRET_CACHE_TIME > 0: if encoded_key is not None: return encoded_key conf = self.conf if self.keymaster_config_path is not None: if any(opt in conf for opt in ('key_id', )): raise ValueError('keymaster_config_path is set, but there ' 'are other config options specified!') conf = readconf(self.keymaster_config_path, 'rotating_keymaster') user_ctxt = keystone_token.KeystoneToken(token=user_token) oslo_conf = cfg.ConfigOpts() options.set_defaults(oslo_conf, auth_endpoint=conf.get('auth_endpoint'), api_class=conf.get('api_class')) options.enable_logging() manager = key_manager.API(oslo_conf) # Get the latest key from Barbican. If no keymanager class has been # specified (using 'api_class'), or the keymaster does not have a # 'get_latest_key()' method, an exception will be raised. key = manager.get(user_ctxt, key_id) if key is None: raise ValueError("Could not find user '%s' with key_id '%s'" % (account, key_id)) user_root_secrets[key_id] = key.get_encoded() self._user_root_secrets[account] = user_root_secrets return key.get_encoded()
def get_configs(self, proxy_configs=None): configs = {} if proxy_configs: key = key_manager.API().get(context.current(), proxy_configs.get('proxy_password')) password = key.get_encoded() configs[sw.HADOOP_SWIFT_USERNAME] = proxy_configs.get( 'proxy_username') configs[sw.HADOOP_SWIFT_PASSWORD] = password configs[sw.HADOOP_SWIFT_TRUST_ID] = proxy_configs.get( 'proxy_trust_id') configs[sw.HADOOP_SWIFT_DOMAIN_NAME] = CONF.proxy_user_domain_name return configs return configs
def get_certificate(context, signature_certificate_uuid): """Create the certificate object from the retrieved certificate data. :param context: the user context for authentication :param signature_certificate_uuid: the uuid to use to retrieve the certificate :returns: the certificate cryptography object :raises glance.common.exception.SignatureVerificationError: if the retrieval fails or the format is invalid """ keymgr_api = key_manager.API() try: # The certificate retrieved here is a castellan certificate object cert = keymgr_api.get(context, signature_certificate_uuid) except Exception as e: # The problem encountered may be backend-specific, since castellan # can use different backends. Rather than importing all possible # backends here, the generic "Exception" is used. msg = (_LE("Unable to retrieve certificate with ID %(id)s: %(e)s") % {'id': signature_certificate_uuid, 'e': encodeutils.exception_to_unicode(e)}) LOG.error(msg) raise exception.SignatureVerificationError( _('Unable to retrieve certificate with ID: %s') % signature_certificate_uuid ) if cert.format not in CERTIFICATE_FORMATS: raise exception.SignatureVerificationError( _('Invalid certificate format: %s') % cert.format ) if cert.format == X_509: # castellan always encodes certificates in DER format cert_data = cert.get_encoded() certificate = x509.load_der_x509_certificate(cert_data, default_backend()) else: raise exception.SignatureVerificationError( _('Certificate format not supported: %s') % cert.format ) # verify the certificate verify_certificate(certificate) return certificate
def get_latest_user_root_secret_and_id(self, account, user_token): """ Retrieve the user's latest root encryption secret from an external key management system using Castellan. :param account: the name of the account :type account: string :param user_token: the keystone token of the user from the request :type user_token: string :return: a tuple containing the binary bytes of the latest encryption root secret, and the id of the latest root encryption secret :rtype: (bytearray, string) """ conf = self.conf if self.keymaster_config_path is not None: if any(opt in conf for opt in ('key_id', )): raise ValueError('keymaster_config_path is set, but there ' 'are other config options specified!') conf = readconf(self.keymaster_config_path, 'rotating_keymaster') user_ctxt = keystone_token.KeystoneToken(token=user_token) oslo_conf = cfg.ConfigOpts() options.set_defaults(oslo_conf, auth_endpoint=conf.get('auth_endpoint'), api_class=conf.get('api_class')) options.enable_logging() manager = key_manager.API(oslo_conf) # Get the latest key from Barbican. If no keymanager class has been # specified (using 'api_class'), or the keymaster does not have a # 'get_latest_key()' method, an exception will be raised. latest_user_root_secret_id, key = manager.get_latest_key( user_ctxt, bits=256, algorithm='aes', name='swift_root_secret') self.logger.log( SECDEL_LOG_LEVEL_DEBUG, "ID of latest user root secret is %s" % latest_user_root_secret_id) if latest_user_root_secret_id is None or key is None: return None, None user_root_secrets = self._user_root_secrets.get(account) if user_root_secrets is None: user_root_secrets = dict() user_root_secrets[latest_user_root_secret_id] = key.get_encoded() self._user_root_secrets[account] = user_root_secrets return key.get_encoded(), latest_user_root_secret_id