From 72b13c705c7eaeeb40e7b959f06f6b5ae2b6a38d Mon Sep 17 00:00:00 2001 From: Rakib Date: Tue, 19 Aug 2025 18:07:00 +0200 Subject: [PATCH 1/2] Refactor hsm partition create cmd to use repository methods --- barbican/cmd/hsm_partition_create.py | 119 +++++++++++---------------- barbican/model/repositories.py | 34 ++++++++ 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/barbican/cmd/hsm_partition_create.py b/barbican/cmd/hsm_partition_create.py index b78a4c906..809c4e2c2 100644 --- a/barbican/cmd/hsm_partition_create.py +++ b/barbican/cmd/hsm_partition_create.py @@ -24,15 +24,11 @@ from oslo_utils import timeutils +from barbican.common import resources from barbican.common import utils from barbican.model import models from barbican.model import repositories -DEFAULT_CREDS = { - "library_path": "/usr/local/lib/softhsm/libsofthsm2.so", - "password": "1234", -} - # Initialize logging and configuration CONF = repositories.CONF LOG = utils.getLogger(__name__) @@ -48,13 +44,12 @@ def main(): "--external-project-id", "-p", help="External project ID", - default="12345", ) parser.add_argument( "--partition-label", "-l", help="Label for the HSM partition", - default="hsm-partition-1", + default="", ) parser.add_argument( "--token-label", "-t", help="Token label", default="testing" @@ -64,25 +59,19 @@ def main(): "-s", help="Slot ID for the HSM", type=int, - default=175517174, - ) - parser.add_argument( - "--library-path", - help="Path to the HSM library", - # I'm testing against softhsm2 - default="/usr/local/lib/softhsm/libsofthsm2.so", ) parser.add_argument( - "--password", help="Password/PIN for the HSM", default="1234" + "--password", + help="Password/PIN for the HSM", ) parser.add_argument( "--partition-id", - help="Override partition UUID (default: auto-generated)", + help="Override partition UUID", default=None, ) parser.add_argument( "--mapping-id", - help="Override mapping UUID (default: auto-generated)", + help="Override mapping UUID", default=None, ) parser.add_argument( @@ -115,62 +104,52 @@ def setup_database(): def create_hsm_partition(args): """Create HSM partition configuration and map to project.""" - # Initialize session - session = repositories.get_session() + # Step 1: Fetch or create project based on external_id + project = resources.get_or_create_project(args.external_project_id) + LOG.debug("Got project with id: %s", project.id) - try: - # Step 1: Check for existing external_id conflict - project_query = session.query(models.Project).filter_by( - external_id=args.external_project_id, deleted=False + # Step 2: Check if HSM partition config already exists for the project + hsm_partition_config_repo = ( + repositories.get_hsm_partition_config_repository() + ) + existing_config = hsm_partition_config_repo.get_by_project_id( + project.id, suppress_exception=True + ) + + if existing_config: + LOG.info( + "HSM partition config already exists for project %s", + project.external_project_id, ) + return existing_config + + # Step 3: Create new HSM partition config for the project + hsm_partition_config_obj = models.HSMPartitionConfig() + # Always set the id explicitly for HSMPartitionConfig + hsm_partition_config_obj.id = args.partition_id or str(uuid.uuid4()) + hsm_partition_config_obj.created_at = timeutils.utcnow() + hsm_partition_config_obj.updated_at = timeutils.utcnow() + hsm_partition_config_obj.project_id = project.id + hsm_partition_config_obj.partition_label = args.partition_label + hsm_partition_config_obj.token_label = args.token_label + hsm_partition_config_obj.slot_id = args.slot_id + hsm_partition_config_obj.credentials = {"password": args.password} + hsm_partition_config_obj.status = models.States.ACTIVE + hsm_partition_config_obj.deleted = False - project = project_query.first() - if project: - LOG.warning( - "Project (external_id: %s) already exists!", - args.external_project_id, - ) - else: - # Create project - LOG.debug("Project doesn't exist, creating new one") - project = models.Project() - project.external_id = args.external_project_id - project.status = models.States.ACTIVE - project.deleted = False - session.add(project) - session.flush() - LOG.debug("Created new project with id: %s", project.id) - - # Step: Create HSM partition config - LOG.debug("Creating HSM partition config") - hsm_partition_config = models.HSMPartitionConfig() - - # Always set the id explicitly for HSMPartitionConfig - hsm_partition_config.id = args.partition_id or str(uuid.uuid4()) - hsm_partition_config.created_at = timeutils.utcnow() - hsm_partition_config.updated_at = timeutils.utcnow() - hsm_partition_config.project_id = project.id - hsm_partition_config.partition_label = args.partition_label - hsm_partition_config.token_label = args.token_label - hsm_partition_config.slot_id = args.slot_id - - # Set credentials - hsm_partition_config.credentials = { - "library_path": args.library_path, - "password": args.password, - } - hsm_partition_config.status = models.States.ACTIVE - hsm_partition_config.deleted = False - - session.add(hsm_partition_config) - session.flush() # This will assign an ID to the partition if needed + try: + hsm_partition_config = hsm_partition_config_repo.create_from( + hsm_partition_config_obj + ) + repositories.commit() + except Exception: + repositories.rollback() + return None + else: LOG.debug( "Created HSM partition config with id: %s", hsm_partition_config.id ) - # Commit all changes - session.commit() - LOG.info("Successfully created HSM partition configuration:") LOG.info( " Project ID: %s (External ID: %s)", @@ -182,13 +161,7 @@ def create_hsm_partition(args): hsm_partition_config.id, args.partition_label, ) - - except Exception as e: - LOG.exception("Error creating HSM partition configuration: %s", e) - session.rollback() - raise - finally: - session.close() + return hsm_partition_config if __name__ == "__main__": diff --git a/barbican/model/repositories.py b/barbican/model/repositories.py index f0ef7d130..7b8853806 100644 --- a/barbican/model/repositories.py +++ b/barbican/model/repositories.py @@ -2590,6 +2590,40 @@ def _do_build_get_query(self, entity_id, external_project_id, session): """Sub-class hook: build a retrieve query.""" return session.query(models.HSMPartitionConfig).filter_by(id=entity_id) + def create_from(self, entity, session=None): + """Sub-class hook: create from entity.""" + if not entity: + msg = u._("Must supply non-None {entity_name}.").format( + entity_name=self._do_entity_name() + ) + raise exception.Invalid(msg) + + LOG.debug("Begin create from...") + session = self.get_session(session) + start = time.time() # DEBUG + + # Validate the attributes before we go any further. From my + # (unknown Glance developer) investigation, the @validates + # decorator does not validate + # on new records, only on existing records, which is, well, + # idiotic. + self._do_validate(entity.to_dict()) + + try: + LOG.debug("Saving entity...") + entity.save(session=session) + except db_exc.DBDuplicateEntry as e: + session.rollback() + LOG.exception("Problem saving entity for create") + error_msg = re.sub("[()]", "", str(e.args)) + raise exception.ConstraintCheck(error=error_msg) + + LOG.debug( + "Elapsed repo " "create secret:%s", (time.time() - start) + ) # DEBUG + + return entity + def get_by_project_id( self, project_id, suppress_exception=False, session=None ): From f29266e9a9389488efbc296f05111f017f3f6258 Mon Sep 17 00:00:00 2001 From: Rakib Date: Mon, 1 Sep 2025 15:55:14 +0200 Subject: [PATCH 2/2] Add HSM partition config create cmd to barbican manage cmd --- barbican/cmd/barbican_manage.py | 79 +++++++++++++++++-- barbican/cmd/hsm_partition_create.py | 75 ++---------------- .../plugin/test_resource_softhsm.py | 1 - docs/getting-started.md | 5 +- 4 files changed, 83 insertions(+), 77 deletions(-) diff --git a/barbican/cmd/barbican_manage.py b/barbican/cmd/barbican_manage.py index b899f3230..ce1e8fbf1 100644 --- a/barbican/cmd/barbican_manage.py +++ b/barbican/cmd/barbican_manage.py @@ -24,10 +24,10 @@ from oslo_config import cfg from oslo_log import log as logging -# from oslo_config import cfg as oslo_cfg - -from sqlalchemy import create_engine, text +from sqlalchemy import create_engine +from sqlalchemy import text +from barbican.cmd.hsm_partition_create import create_hsm_partition from barbican.cmd import pkcs11_kek_rewrap as pkcs11_rewrap from barbican.common import config from barbican.model import clean @@ -98,7 +98,7 @@ class DbCommands(object): action="store_true", dest="do_clean_unassociated_projects", default=False, - help="Remove projects that have no " "associated resources.", + help="Remove projects that have no associated resources.", ) @args( "--soft-delete-expired-secrets", @@ -617,7 +617,6 @@ def _verify_label_does_not_exist(self, key_type, label, session): class SAPCommands(object): - description = ( "Move all secrets associated with " "the old_project_id to the new_project_id." @@ -687,6 +686,76 @@ def move_secrets( except Exception as e: print(f"An error occurred: {e}") + @args( + "--external-project-id", + "-p", + dest="external_project_id", + metavar="", + help="External project ID", + ) + @args( + "--partition-label", + "-l", + dest="partition_label", + metavar="", + help="Label for the HSM partition", + ) + @args( + "--token-label", + "-t", + dest="token_label", + metavar="", + help="Token label", + ) + @args( + "--slot-id", + "-s", + dest="slot_id", + type=int, + metavar="", + help="Slot ID for the HSM", + ) + @args( + "--password", + dest="password", + metavar="", + help="Password/PIN for the HSM", + ) + @args( + "--partition-id", + dest="partition_id", + metavar="", + help="Override partition UUID", + ) + @args( + "--debug", + dest="debug", + action="store_true", + default=False, + help="Enable debug output", + ) + def create_hsm_partition_config( + self, + conf, + external_project_id=None, + partition_label=None, + token_label=None, + slot_id=None, + password=None, + partition_id=None, + debug=False, + ): + parsed_args = argparse.Namespace( + external_project_id=external_project_id, + token_label=token_label, + slot_id=slot_id, + password=password, + partition_id=partition_id, + partition_label=partition_label, + debug=debug, + ) + create_hsm_partition(parsed_args) + CATEGORIES = { "db": DbCommands, diff --git a/barbican/cmd/hsm_partition_create.py b/barbican/cmd/hsm_partition_create.py index 809c4e2c2..4992b30f4 100644 --- a/barbican/cmd/hsm_partition_create.py +++ b/barbican/cmd/hsm_partition_create.py @@ -18,8 +18,6 @@ and mapping them to projects in the Barbican database. """ -import argparse -import sys import uuid from oslo_utils import timeutils @@ -34,67 +32,7 @@ LOG = utils.getLogger(__name__) -# Set up command-line arguments -def main(): - parser = argparse.ArgumentParser( - description="Create HSM partition configurations in Barbican." - ) - - parser.add_argument( - "--external-project-id", - "-p", - help="External project ID", - ) - parser.add_argument( - "--partition-label", - "-l", - help="Label for the HSM partition", - default="", - ) - parser.add_argument( - "--token-label", "-t", help="Token label", default="testing" - ) - parser.add_argument( - "--slot-id", - "-s", - help="Slot ID for the HSM", - type=int, - ) - parser.add_argument( - "--password", - help="Password/PIN for the HSM", - ) - parser.add_argument( - "--partition-id", - help="Override partition UUID", - default=None, - ) - parser.add_argument( - "--mapping-id", - help="Override mapping UUID", - default=None, - ) - parser.add_argument( - "--debug", help="Enable debug output", action="store_true" - ) - - args = parser.parse_args() - - if args.debug: - LOG.logger.setLevel("DEBUG") - - try: - setup_database() - create_hsm_partition(args) - LOG.info("HSM partition configuration created successfully") - except Exception as e: - LOG.exception("Error creating HSM partition configuration: %s", e) - return 1 - - return 0 - - -def setup_database(): +def _setup_database(): """Initialize database connection.""" LOG.debug("Initializing database connection") repositories.setup_database_engine_and_factory() @@ -102,6 +40,11 @@ def setup_database(): def create_hsm_partition(args): + if hasattr(args, "debug") and args.debug: + LOG.logger.setLevel("DEBUG") + + _setup_database() + """Create HSM partition configuration and map to project.""" # Step 1: Fetch or create project based on external_id @@ -130,7 +73,7 @@ def create_hsm_partition(args): hsm_partition_config_obj.created_at = timeutils.utcnow() hsm_partition_config_obj.updated_at = timeutils.utcnow() hsm_partition_config_obj.project_id = project.id - hsm_partition_config_obj.partition_label = args.partition_label + hsm_partition_config_obj.partition_label = args.partition_label or "" hsm_partition_config_obj.token_label = args.token_label hsm_partition_config_obj.slot_id = args.slot_id hsm_partition_config_obj.credentials = {"password": args.password} @@ -162,7 +105,3 @@ def create_hsm_partition(args): args.partition_label, ) return hsm_partition_config - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/barbican/integrationtests/plugin/test_resource_softhsm.py b/barbican/integrationtests/plugin/test_resource_softhsm.py index 6e782c0c2..3f6cf191e 100644 --- a/barbican/integrationtests/plugin/test_resource_softhsm.py +++ b/barbican/integrationtests/plugin/test_resource_softhsm.py @@ -219,7 +219,6 @@ def _create_project_secret_store_mapping( project = resources.get_or_create_project(project_name) # Create HSM partition config in DB - # ToDo: Refactor in a proper way with repository # ToDo: Note: Some of the options are not present in HSM crypto plugin args = Namespace( external_project_id=project.external_id, diff --git a/docs/getting-started.md b/docs/getting-started.md index cdbfb896a..8cad24b1e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -243,12 +243,11 @@ pkcs11-tool --module /usr/local/lib/softhsm/libsofthsm2.so -O \ Create HSM partition config for the project in the DB: ``` -python ./barbican/cmd/hsm_partition_create.py \ + barbican-manage sap create_hsm_partition_config \ --external-project-id \ --token-label