Skip to content

Commit

Permalink
Merge pull request #1803 from freedomofpress/configure-tails-via-ansible
Browse files Browse the repository at this point in the history
Configures Tails workstations via Ansible
  • Loading branch information
conorsch authored Jun 14, 2017
2 parents 38c26c2 + 78ba07b commit 11d0d5d
Show file tree
Hide file tree
Showing 22 changed files with 296 additions and 464 deletions.
10 changes: 7 additions & 3 deletions install_files/ansible-base/inventory-dynamic
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,18 @@ def lookup_tor_hostname(hostname):
with open(aths_path, 'r') as f:
tor_config = f.readline().rstrip().split()
try:
# Regardless of THS/ATHS, Onion URL will be first item.
# That's all we care about to get the address.
return tor_config[0]
# Ordinarily the Onion URL would be the first field in the file,
# assuming the file is a raw `hostname` file generated by tor,
# but the SD playbooks format the line with `HidServAuth` prefix,
# so it can be concatenated into the torrc file on Tails.
tor_hostname = tor_config[1]
except IndexError:
msg = ("Tor config file for '{}' ",
"appears to be empty").format(hostname)
raise Exception(msg=msg)

return tor_hostname


def lookup_ssh_address(hostname):
"""
Expand Down
43 changes: 43 additions & 0 deletions install_files/ansible-base/roles/tails-config/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# Locations for SecureDrop-specific dotfiles, for Tails persistence.
tails_config_amnesia_home: /home/amnesia
tails_config_amnesia_persistent: "{{ tails_config_amnesia_home }}/Persistent"

# Directory containing Ansible config, including site-specific customizations.
tails_config_ansible_base: "{{ tails_config_amnesia_persistent }}/securedrop/install_files/ansible-base"

# Custom persistence directory whence site-specific configs will be copied
# on every login under Tails.
tails_config_securedrop_dotfiles: "{{ tails_config_amnesia_persistent }}/.securedrop"

# Locations for Tails persistence settings, used to bootstrap SecureDrop config
tails_config_live_persistence: /live/persistence/TailsData_unlocked
tails_config_live_dotfiles: "{{ tails_config_live_persistence }}/dotfiles"

# Destination directories for storing the SecureDrop desktop icons, which
# provide a user-friendly method of accessing the Onion URLs in a browser.
tails_config_desktop_icon_directories:
- "{{ tails_config_securedrop_dotfiles }}"
- "{{ tails_config_live_dotfiles }}"
- "{{ tails_config_amnesia_home }}/Desktop"
- "{{ tails_config_live_dotfiles }}/Desktop"
- "{{ tails_config_amnesia_home }}/.local/share/applications"
- "{{ tails_config_live_dotfiles }}/.local/share/applications"

# Path for storing site-specific ATHS info for connecting to Journalist Interface.
tails_config_torrc_additions: "{{ tails_config_securedrop_dotfiles }}/torrc_additions"

# Location for NetworkManager hooks, used to activate ATHS info.
tails_config_network_manager_dispatcher: /etc/NetworkManager/dispatcher.d

# Parent directories for joining with the config_files below,
# to ensure absence from all locations succinctly.
tails_config_deprecated_directories:
- "{{ tails_config_live_persistence }}"
- "{{ tails_config_securedrop_dotfiles }}"
- "{{ tails_config_network_manager_dispatcher }}"
- "{{ tails_config_network_manager_dispatcher }}/custom-nm-hooks"

tails_config_deprecated_config_files:
- 70-tor-reload.sh
- 99-tor-reload.sh
File renamed without changes
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# Run the SecureDrop init script, which implements the torrc additions
# so the ATHS Onion URLs are accessible. See `securedrop_init.py` for details.
- name: run securedrop network hook
# Writes files to /etc, so elevated privileges are required.
become: yes
command: /usr/bin/python "{{ tails_config_securedrop_dotfiles }}/securedrop_init.py"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
# Legacy changes handler to ensure backwards-compatibility. If an Admin runs
# this config after already having set up SecureDrop before, any outdated
# items will be handled and updated accordingly.

- name: Remove deprecated network hook config files.
file:
path: "{{ item.0 }}/{{ item.1 }}"
state: absent
with_nested:
- "{{ tails_config_deprecated_directories }}"
- "{{ tails_config_deprecated_config_files }}"

- name: Remove deprecated xsessionrc file.
file:
path: "{{ tails_config_live_persistence }}/dotfiles/.xsessionrc"
state: absent

- name: Remove deprecated Document Interface desktop icons.
file:
state: absent
path: "{{ item }}"
with_items:
- "{{ tails_config_amnesia_home }}/Desktop/document.desktop"
- "{{ tails_config_amnesia_home }}/.local/share/applications/document.desktop"
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
- name: Enable persistence for NetworkManager hooks.
# Elevated privileges are required for writing to persistence config.
become: yes
lineinfile:
dest: "{{ tails_config_live_persistence }}/persistence.conf"
regexp: '^/etc/NetworkManager'
line: "{{ tails_config_network_manager_dispatcher }} source=custom-nm-hooks,link"

- name: Copy NetworkManager hook for managing SecureDrop interfaces.
become: yes
copy:
src: 65-configure-tor-for-securedrop.sh
dest: "{{ item }}/"
owner: root
group: root
mode: "0755"
with_items:
- "{{ tails_config_live_persistence }}/custom-nm-hooks"
- "{{ tails_config_network_manager_dispatcher }}"
notify: run securedrop network hook

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
- name: Find Tor ATHS info for SecureDrop interfaces.
find:
paths:
- "{{ tails_config_ansible_base }}"
patterns:
# Collect all files that end in `-aths`, since only ATHS services
# contain HidServAuth info that must be added to torrc.
- '*-aths'
register: find_aths_info_result

# We need at least one ATHS value, for the Journalist Interface.
# Admin Workstations will have three, including the two SSH interfaces.
# This task simply validates that at least one suitable file was found;
# if not, then the playbooks haven't been run, so fail with instructions.
- name: Confirm ATHS info was found.
assert:
that:
- find_aths_info_result.matched >= 1
msg: >-
Failed to find ATHS info locally. Make sure you've installed SecureDrop
on the servers, and that the `-aths` files are located in:
`{{ tails_config_ansible_base }}/`.
- name: Assemble ATHS info into torrc additions.
become: yes
assemble:
src: "{{ tails_config_ansible_base }}"
regexp: '.*-aths$'
dest: "{{ tails_config_torrc_additions }}"
owner: root
group: root
mode: "0400"
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
- name: Create SecureDrop-specific dotfiles directory for Tails persistence.
file:
path: "{{ tails_config_securedrop_dotfiles }}"
state: directory
mode: "0755"

- name: Copy SecureDrop logo for desktop icons to dotfiles directory.
copy:
src: securedrop_icon.png
dest: "{{ tails_config_securedrop_dotfiles }}/"

# Script used to append torrc additions. Triggered by NetworkManager hook.
# Resides in dotfiles in order to achieve persistence.
- name: Copy SecureDrop network hook for Tor config.
# Elevated privileges for root:root ownership, so only the system can
# execute, in the context of the NetworkManager hook, which calls it.
become: yes
copy:
src: securedrop_init.py
dest: "{{ tails_config_securedrop_dotfiles }}/"
owner: root
group: root
mode: "0700"
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
# Read the Onion URL from the Tor info files that were fetched back during
# installation. On the Admin Workstation, these files will be present
# after running the playbooks, but on the Journalist Workstation, they must
# be copied manually by the Admin.
- name: Look up Source Interface URL.
command: grep -Po '.{16}\.onion' app-source-ths
changed_when: false
register: source_interface_lookup_result

- name: Look up Journalist Interface URL.
command: grep -Po '.{16}\.onion' app-journalist-aths
changed_when: false
register: journalist_interface_lookup_result

- name: Create desktop shortcut parent directories.
file:
state: directory
path: "{{ item }}"
with_items: "{{ tails_config_desktop_icon_directories }}"

# Storing as host fact so we can loop over the data in one task.
- name: Assemble desktop icon info.
set_fact:
_securedrop_desktop_icon_info:
- name: SecureDrop Source Interface
filename: source.desktop
onion_url: "{{ source_interface_lookup_result.stdout }}"
- name: SecureDrop Journalist Interface
filename: journalist.desktop
onion_url: "{{ journalist_interface_lookup_result.stdout }}"

- name: Create SecureDrop interface desktop icons.
template:
src: desktop-icon.j2
dest: "{{ item.1 }}/{{ item.0.filename }}"
mode: "0700"
with_nested:
- "{{ _securedrop_desktop_icon_info }}"
- "{{ tails_config_desktop_icon_directories }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
# Read the Onion URL from the Tor info files that were fetched back during
# installation. On the Admin Workstation, these files will be present
# after running the playbooks, but on the Journalist Workstation, they must
# be copied manually by the Admin.

- name: Look up Application Server SSH Onion URL.
command: grep -Po '.{16}\.onion' app-ssh-aths
changed_when: false
register: app_ssh_lookup_result

- name: Look up Monitor Server SSH Onion URL.
command: grep -Po '.{16}\.onion' mon-ssh-aths
changed_when: false
register: mon_ssh_lookup_result

- name: Create SSH config directory.
file:
state: directory
path: "{{ tails_config_amnesia_home }}/.ssh"
mode: "0700"

- name: Create SSH alias
template:
src: ssh_config.j2
dest: "{{ item }}"
mode: "0600"
with_items:
- "{{ tails_config_securedrop_dotfiles }}/ssh_config"
- "{{ tails_config_amnesia_home }}/.ssh/config"
18 changes: 18 additions & 0 deletions install_files/ansible-base/roles/tails-config/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# Reuse validation logic.
- include: "{{ role_path }}/../validate/tasks/validate_tails_environment.yml"

- include: cleanup_legacy_artifacts.yml

- include: copy_dotfiles.yml

- include: configure_torrc_additions.yml

- include: create_desktop_shortcuts.yml

- include: configure_network_hook.yml

- include: create_ssh_aliases.yml
# Only Admin Workstation will have ATHS values for SSH, in addition
# to ATHS value for the Journalist Interface.
when: find_aths_info_result.matched > 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env xdg-open

[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Categories=Network;
Name[en_US]={{ item.0.name }}
Icon[en_US]={{ tails_config_securedrop_dotfiles }}/securedrop_icon.png
Name={{ item.0.name }}
Icon={{ tails_config_securedrop_dotfiles }}/securedrop_icon.png
Exec=/usr/local/bin/tor-browser {{ item.0.onion_url }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Host app
Hostname {{ app_ssh_lookup_result.stdout }}
Host mon
Hostname {{ mon_ssh_lookup_result.stdout }}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
with_items:
- /live/persistence/TailsData_unlocked/persistence.conf
- /live/persistence/TailsData_unlocked/openssh-client
- /home/amnesia/Persistent/securedrop

- name: Confirm persistence volume is configured.
assert:
Expand All @@ -22,4 +23,6 @@
msg: >-
Persistence must configured on the Tails device for the Admin
Workstation, and the SSH option for persistent dotfiles must be enabled.
The SecureDrop git repository should be cloned
to `~/Persistent/securedrop`.
with_items: "{{ tails_persistence_check_result.results }}"
23 changes: 23 additions & 0 deletions install_files/ansible-base/securedrop-tails.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env ansible-playbook
---
# Configures SecureDrop dotfiles persistence on Admin and Journalist
# Workstations. Should be run after the servers have been installed.
- name: Configure Tails workstation.
hosts: localhost
connection: local
gather_facts: yes
roles:
- role: tails-config
tags: tails-config
tasks:
- name: Configuration complete.
debug:
msg: >-
Successfully configured Tor and set up desktop bookmarks for SecureDrop!
You will see a notification appear on your screen when Tor is ready.
The Journalist Interface's Tor onion URL is: http://{{ journalist_interface_lookup_result.stdout }}
The Source Interfaces's Tor onion URL is: http://{{ source_interface_lookup_result.stdout }}
{% if find_aths_info_result.matched > 1 %}
SSH aliases are set up. You can use them with 'ssh app' and 'ssh mon'.
{% endif %}
7 changes: 5 additions & 2 deletions securedrop-admin
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ def install_securedrop(args):

def run_tails_config(args):
"""Configure Tails environment post SD install"""
subprocess.check_call(['sudo',
os.path.join(SD_DIR, 'tails_files/install.sh')])
activate_venv()
subprocess.check_call([os.path.join(ANSIBLE_PATH, 'securedrop-tails.yml'),
"--ask-become-pass",
],
cwd=ANSIBLE_PATH)


if __name__ == "__main__":
Expand Down
3 changes: 0 additions & 3 deletions tails_files/README.md

This file was deleted.

Loading

0 comments on commit 11d0d5d

Please sign in to comment.