Skip to content

Commit

Permalink
Merge pull request #4814 from freedomofpress/backport-4801
Browse files Browse the repository at this point in the history
[1.0.0] backport #4801 Rework Ansible restore role to detect Onion service version mismatch
  • Loading branch information
emkll authored Sep 13, 2019
2 parents f71c16c + b83c903 commit 964c92c
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 73 deletions.
4 changes: 4 additions & 0 deletions admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,10 @@ def restore_securedrop(args):
# but the securedrop-admin
# script will be invoked from the repo root, so preceding dirs are likely.
restore_file_basename = os.path.basename(args.restore_file)

# Would like readable output if there's a problem
os.environ["ANSIBLE_STDOUT_CALLBACK"] = "debug"

ansible_cmd = [
'ansible-playbook',
os.path.join(args.ansible_path, 'securedrop-restore.yml'),
Expand Down
69 changes: 69 additions & 0 deletions install_files/ansible-base/roles/restore/files/compare_torrc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python

#
# Compares Tor configurations on the app server and from a backup. If
# restoring the backup would alter the server's Tor configuration,
# print a warning and exit.
#

from __future__ import print_function

import os
import re
import sys


def get_tor_versions(path):
"""
Determine which service versions are offered in the given torrc.
"""
service_re = re.compile(r"HiddenServiceDir\s+(?:.*)/(.*)")
versions = set([])
with open(path) as f:
for line in f:
m = service_re.match(line)
if m:
service = m.group(1)
if "v3" in service:
versions.add(3)
else:
versions.add(2)

return versions


def strset(s):
"""
Sort the given set and join members with "and".
"""
return " and ".join(str(v) for v in sorted(s))


if __name__ == "__main__":
tempdir = sys.argv[1]

server_versions = get_tor_versions(os.path.join(tempdir, "app/etc/tor/torrc"))
backup_versions = get_tor_versions(os.path.join(tempdir, "backup/etc/tor/torrc"))

if server_versions == backup_versions:
print("The Tor configuration in the backup matches the server.")
sys.exit(0)

print(
"The Tor configuration on the app server offers version {} services.".format(
strset(server_versions)
)
)

print(
"The Tor configuration in this backup offers version {} services.".format(
strset(backup_versions)
)
)

print("\nRestoring a backup with a different Tor configuration than the server ")
print("is currently unsupported. If you require technical assistance, please ")
print("contact the SecureDrop team via the support portal or at ")
print("[email protected].")

sys.exit(1)
57 changes: 0 additions & 57 deletions install_files/ansible-base/roles/restore/files/restore.py

This file was deleted.

91 changes: 75 additions & 16 deletions install_files/ansible-base/roles/restore/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,81 @@
---
- name: Copy restore script to Application Server.
copy:
src: restore.py
dest: /tmp/
owner: root
mode: "0770"

- name: Copy backup tarball of config info to Application Server.
copy:
- name: Create temporary directory for Tor configuration check
connection: local
become: no
tempfile:
state: directory
register: torrc_check_dir

- name: Fetch current Tor configuration from app server
become: no
fetch:
src: /etc/tor/torrc
dest: "{{ torrc_check_dir.path }}"

- name: Create directory to hold the Tor configuration from the backup
connection: local
become: no
file:
path: "{{ torrc_check_dir.path }}/backup"
state: directory

- name: Extract Tor configuration from backup
connection: local
become: no
unarchive:
dest: "{{ torrc_check_dir.path }}/backup/"
src: "{{ restore_file }}"
dest: /tmp/{{ restore_file }}
extra_opts:
- "etc/tor/torrc"

- name: Run the restore script (can be slow).
command: /tmp/restore.py /tmp/{{ restore_file }}
async: 3600
poll: 10
- name: Check for Tor configuration differences between the backup and server
connection: local
become: no
command: "python {{ role_path }}/files/compare_torrc.py {{ torrc_check_dir.path }}"

- name: Delete the restore file to save disk space.
- name: Remove temporary directory for Tor configuration check
connection: local
become: no
file:
path: /tmp/{{ restore_file }}
path: "{{ torrc_check_dir.path }}"
state: absent
when: torrc_check_dir.path is defined

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

- name: Extract backup
unarchive:
dest: /
remote_src: yes
src: "/tmp/{{ restore_file}}"

- name: Reconfigure securedrop-app-code
command: dpkg-reconfigure securedrop-app-code

- name: Reconfigure securedrop-config
command: dpkg-reconfigure securedrop-config

- name: Reload Apache service
service:
name: apache2
state: reloaded

- name: Reload Tor service
service:
name: tor
state: reloaded
async: 60
poll: 0
register: tor_reload_job

- name: Wait for Tor reload
async_status:
jid: "{{ tor_reload_job.ansible_job_id }}"
register: tor_reload
until: tor_reload.finished
retries: 6
delay: 10

0 comments on commit 964c92c

Please sign in to comment.