Skip to content

Commit

Permalink
Add support for partial backup exports
Browse files Browse the repository at this point in the history
  • Loading branch information
elonen committed Sep 22, 2024
1 parent 9f1156b commit 5aed5dc
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
25 changes: 23 additions & 2 deletions hsm_secrets/hsm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import cast
import click

from hsm_secrets.config import HSMAsymmetricKey, HSMConfig, click_hsm_obj_auto_complete, find_all_config_items_per_type, parse_keyid
from hsm_secrets.config import HSMAsymmetricKey, HSMConfig, HSMKeyID, click_hsm_obj_auto_complete, find_all_config_items_per_type, parse_keyid
from hsm_secrets.secret_sharing.ceremony import cli_reconstruction_ceremony, cli_splitting_ceremony
from hsm_secrets.log import _check_and_format_audit_conf_differences
from hsm_secrets.utils import HSMAuthMethod, HsmSecretsCtx, cli_confirm, cli_error, cli_info, cli_pause, cli_prompt, cli_result, cli_ui_msg, cli_warn, confirm_and_delete_old_yubihsm_object_if_exists, open_hsm_session, open_hsm_session_with_password, pass_common_args, pretty_fmt_yubihsm_object, prompt_for_secret, pw_check_fromhex
Expand Down Expand Up @@ -497,17 +497,33 @@ def make_wrap_key(ctx: HsmSecretsCtx):

@cmd_hsm_backup.command('export')
@pass_common_args
@click.argument('ids', nargs=-1, type=str, metavar='<id|label> ...', required=False)
@click.option('--out', '-o', type=click.Path(exists=False, allow_dash=False), required=False, help='Output file', default=None)
def backup_export(ctx: HsmSecretsCtx, out: click.File|None):
@click.option('--all', is_flag=True, help="Export all objects")
def backup_export(ctx: HsmSecretsCtx, ids: list[str], out: click.File|None, all: bool):
"""Export backup .tar.gz of HSM
Exports all objects under wrap from the YubiHSM and saves them
to a .tar.gz file. The file can be used to restore the objects
to the same or another YubiHSM device that has the same wrap key.
"""
if not all and not ids:
cli_error("No object IDs or labels provided. Use --all to export all objects.")
raise click.Abort()

cli_info("")
cli_info(f"Reading objects from YubiHSM device {ctx.hsm_serial}...")

# Convert explicitly selected object IDs/labels to numeric IDs
selected_key_ids: list[HSMKeyID] = []
for id_or_label in ids:
try:
id_int = ctx.conf.find_def_non_typed(id_or_label).id
except KeyError:
cli_warn(f"Object '{id_or_label}' not found in the configuration file. Assuming it's raw ID on the device.")
id_int = parse_keyid(id_or_label)
selected_key_ids.append(id_int)

# Open the output file
fh = None
if out is None:
Expand All @@ -524,6 +540,11 @@ def backup_export(ctx: HsmSecretsCtx, out: click.File|None):
with open_hsm_session(ctx, HSMAuthMethod.DEFAULT_ADMIN, ctx.hsm_serial) as ses:
device_objs = list(ses.list_objects())
for obj in device_objs:

if not all and obj.id not in selected_key_ids:
cli_warn(f"- SKIPPED non-selected object 0x{obj.id:04x} ({obj.object_type.name}): {str(obj.get_info().label)}")
continue

# Try to export the object
try:
key_bytes = ses.export_wrapped(ctx.conf.admin.wrap_key, obj.id, obj.object_type)
Expand Down
2 changes: 1 addition & 1 deletion hsm_secrets/x509/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def init_crl(ctx: HsmSecretsCtx, cacerts: list[str], out: str|None, period: int|
if period is not None:
next_update = this_update + datetime.timedelta(days=period)
else:
next_update = ca_cert.not_valid_after - datetime.timedelta(seconds=1)
next_update = ca_cert.not_valid_after_utc - datetime.timedelta(minutes=1)

builder = x509.CertificateRevocationListBuilder()
builder = builder.issuer_name(ca_cert.subject)
Expand Down
2 changes: 1 addition & 1 deletion run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ test_password_derivation() {

test_wrapped_backup() {
setup
run_cmd -q hsm backup export --out $TEMPDIR/backup.tgz
run_cmd -q hsm backup export --all --out $TEMPDIR/backup.tgz
assert_success

tar tvfz $TEMPDIR/backup.tgz | grep -q 'ASYMMETRIC_KEY' || { echo "ERROR: No asymmetric keys found in backup"; return 1; }
Expand Down

0 comments on commit 5aed5dc

Please sign in to comment.