Skip to content

Commit

Permalink
Adds option to restore from backup file already on server.
Browse files Browse the repository at this point in the history
when the '--no-transfer' argument is used with `./securedrop-admin restore`,
instead of transferring the backup tarball to the Application Server, the
local copy of the tarball will be compared with an expected remote file of the
same name in `/tmp` on the server. If checksums match, the remote copy will be
used to perform the backup.

This is intended to address cases where backups are too large to reliably
transmit over Tor via the Ansible synchronize module. Instead, backups can be
copied to the server using rsync, or via an encrypted transfer USB.
  • Loading branch information
zenmonkeykstop committed Apr 21, 2021
1 parent fedce7a commit 5ebe435
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 10 deletions.
23 changes: 13 additions & 10 deletions admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,25 +883,23 @@ def restore_securedrop(args: argparse.Namespace) -> int:
# Would like readable output if there's a problem
os.environ["ANSIBLE_STDOUT_CALLBACK"] = "debug"

ansible_cmd_full_restore = [
ansible_cmd = [
'ansible-playbook',
os.path.join(args.ansible_path, 'securedrop-restore.yml'),
'-e',
"restore_file='{}'".format(restore_file_basename),
]

ansible_cmd_skip_tor = [
'ansible-playbook',
os.path.join(args.ansible_path, 'securedrop-restore.yml'),
'-e',
"restore_file='{}' restore_skip_tor='True'".format(restore_file_basename),
ansible_cmd_extras = [
"restore_file='{}'".format(restore_file_basename),
]

if args.restore_skip_tor:
ansible_cmd = ansible_cmd_skip_tor
else:
ansible_cmd = ansible_cmd_full_restore
ansible_cmd_extras.append("restore_skip_tor='True'")

if args.restore_manual_transfer:
ansible_cmd_extras.append("restore_manual_transfer='True")

ansible_cmd.append(' '.join(ansible_cmd_extras))
return subprocess.check_call(ansible_cmd, cwd=args.ansible_path)


Expand Down Expand Up @@ -1161,6 +1159,11 @@ class ArgParseFormatterCombo(argparse.ArgumentDefaultsHelpFormatter,
dest='restore_skip_tor',
help="Preserve the server's current Tor config")

parse_restore.add_argument("--no-transfer", default=False,
action='store_true',
dest='restore_manual_transfer',
help="Restore using a backup file already present on the server")

parse_update = subparsers.add_parser('update', help=update.__doc__)
parse_update.set_defaults(func=update)

Expand Down
1 change: 1 addition & 0 deletions install_files/ansible-base/roles/restore/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
# backup. add the `--preserve-tor-config` to preserve the server's existing config.

restore_skip_tor: False
restore_manual_transfer: False
29 changes: 29 additions & 0 deletions install_files/ansible-base/roles/restore/tasks/perform_restore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,40 @@
- "More info: {{ compare_result.stdout }}"
when: not restore_skip_tor

- name: Calculate local backup file checksum
connection: local
become: no
stat:
path: "{{ restore_file }}"
checksum_algorithm: sha256
register: local_backup_file
when: restore_manual_transfer

- name: Calculate remote backup file checksum
stat:
path: "/tmp/{{ restore_file }}"
checksum_algorithm: sha256
register: remote_backup_file
when: restore_manual_transfer

- name: Verify that local and remote backup file checksums match
assert:
that:
- "remote_backup_file.stat.checksum == local_backup_file.stat.checksum"
fail_msg:
- "Checksum comparison for the local and remote copies of the backup file failed."
- "When using the --no-transfer flag. the same file must be present both locally"
- "in `install_files/ansible-base and on the Application Server in `/tmp`, to allow"
- "for config verification. Please copy the backup file into place on the"
- "Application Server before proceeding, or restore without the --no-transfer flag."
when: restore_manual_transfer

- name: Copy backup to application server
synchronize:
src: "{{ restore_file }}"
dest: /tmp/{{ restore_file }}
partial: yes
when: not restore_manual_transfer

- name: Extract backup
unarchive:
Expand Down

0 comments on commit 5ebe435

Please sign in to comment.