Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow SSH over local network instead of Tor #2592

Merged
merged 35 commits into from
Apr 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
454bc41
Allow more extensive disable of ssh over tor
msheiny Nov 17, 2017
c6f5c12
Move enable_ssh_over_tor default to roles
msheiny Nov 20, 2017
9658f74
Improve logic-SSHd listen addr when ssh w/o tor
msheiny Nov 20, 2017
b5d3b42
Config ssh_cfg based tor_ssh status - admin wkstn
msheiny Nov 20, 2017
ecfe205
Remove tor test from common
msheiny Nov 20, 2017
8eb54e1
Expand documentation for local ssh config
msheiny Nov 21, 2017
feda2dc
Address documentation nits raised in PR
msheiny Nov 27, 2017
06ab470
Remove legacy second interface on staging env
msheiny Nov 28, 2017
8d67a98
Ensure netaddr ansible filter dependency present
msheiny Mar 1, 2018
b23b3d1
Ensure ssh localnet opened when tor ssh is disabled
msheiny Mar 1, 2018
ce95a44
Punt aws molecule scenario vars to new file
msheiny Mar 2, 2018
fcd877b
Remove no longer utilized ansible ossec var
msheiny Mar 2, 2018
05e5f80
Squash deprecation warnings over ec2 facts modules
msheiny Mar 2, 2018
d2fceb8
Allow over-ride of ssh network allowance
msheiny Mar 2, 2018
9d9e1f1
Re-enable tor install for monitor server
msheiny Mar 2, 2018
3531ad8
Fix iptables tests to match staging environment
msheiny Mar 2, 2018
057c7a2
Address documentation nits
msheiny Mar 7, 2018
f04a4ea
Remove legacy authd_rules variable
msheiny Mar 7, 2018
ba44342
Make sure netaddr dependency added to admin list
msheiny Mar 28, 2018
66a070a
Add option to toggle ssh over tor
msheiny Mar 29, 2018
a6b0d93
Fix for iptables logic for ssh_over_localnet
msheiny Mar 29, 2018
7e26a2e
Address transistion scenario when disabling ssh_over_tor
msheiny Mar 29, 2018
b41b11a
Fix playbook when user toggles ssh_tor -> localnet
msheiny Mar 29, 2018
a55dd5a
Add accompanying admin test for nable_ssh_over_tor
msheiny Mar 29, 2018
51606ed
fix iptables template, expand tests ssh+localnet
msheiny Mar 29, 2018
a5a8a5e
Ignore visual-studio code local config folder
msheiny Mar 29, 2018
b4e62e3
Fix - prod not installw/ ssh/local on fresh inst
msheiny Apr 3, 2018
db0cf42
Revert "Remove legacy second interface on staging env"
msheiny Apr 3, 2018
3314884
Fix var name, ssh over local net for mon
msheiny Apr 5, 2018
8cc1557
Add detection when reboot needed for iptables
msheiny Apr 5, 2018
927e54c
Adjust iptables tor rules to allow traffic for mon
msheiny Apr 5, 2018
82a8bed
Address SSH IP ruleset when servers on split nets
msheiny Apr 6, 2018
367827d
Update SSH over LAN docs
msheiny Apr 6, 2018
4ee572e
Tweak SSH documentation to add reference to env update
msheiny Apr 6, 2018
113ccd0
Fix doc goof with reference to admin command
msheiny Apr 17, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,6 @@ raw-test-output/

#Used in CI for parsing out tor nightly version
.tor_version

# Ignore visual studio code folder
.vscode
1 change: 1 addition & 0 deletions admin/requirements-ansible.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ansible>2.4<2.5
netaddr
3 changes: 3 additions & 0 deletions admin/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ jinja2==2.10 \
markupsafe==1.0 \
--hash=sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665 \
# via jinja2
netaddr==0.7.19 \
--hash=sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd \
--hash=sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca
paramiko==2.4.0 \
--hash=sha256:486f637f0a33a4792e0e567be37426c287efaa8c4c4a45e3216f9ce7fd70b1fc \
--hash=sha256:8851e728e8b7590989e68e3936c48ee3ca4dad91d29e3d7ff0305b6c5fc582db \
Expand Down
4 changes: 4 additions & 0 deletions admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ def __init__(self, args):
u'SASL password for sending OSSEC alerts',
SiteConfig.ValidateOSSECPassword(),
None],
['enable_ssh_over_tor', True, bool,
u'Enable SSH over Tor',
SiteConfig.ValidateYesNo(),
lambda x: x.lower() == 'yes'],
['securedrop_supported_locales', [], types.ListType,
u'Space separated list of additional locales to support '
'(' + translations + ')',
Expand Down
20 changes: 12 additions & 8 deletions admin/tests/test_securedrop-admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,14 +580,7 @@ def verify_desc_consistency(self, site_config, desc):
with pytest.raises(ValidationError):
site_config.user_prompt_config_one(desc, '')

verify_prompt_ssh_users = verify_desc_consistency
verify_prompt_app_ip = verify_desc_consistency
verify_prompt_monitor_ip = verify_desc_consistency
verify_prompt_app_hostname = verify_desc_consistency
verify_prompt_monitor_hostname = verify_desc_consistency
verify_prompt_dns_server = verify_desc_consistency

def verify_prompt_securedrop_app_https_on_source_interface(
def verify_prompt_boolean(
self, site_config, desc):
self.verify_desc_consistency(site_config, desc)
(var, default, etype, prompt, validator, transform) = desc
Expand All @@ -596,6 +589,17 @@ def verify_prompt_securedrop_app_https_on_source_interface(
assert site_config.user_prompt_config_one(desc, 'YES') is True
assert site_config.user_prompt_config_one(desc, 'NO') is False

verify_prompt_ssh_users = verify_desc_consistency
verify_prompt_app_ip = verify_desc_consistency
verify_prompt_monitor_ip = verify_desc_consistency
verify_prompt_app_hostname = verify_desc_consistency
verify_prompt_monitor_hostname = verify_desc_consistency
verify_prompt_dns_server = verify_desc_consistency

verify_prompt_securedrop_app_https_on_source_interface = \
verify_prompt_boolean
verify_prompt_enable_ssh_over_tor = verify_prompt_boolean

verify_prompt_securedrop_app_gpg_public_key = verify_desc_consistency

def verify_prompt_not_empty(self, site_config, desc):
Expand Down
17 changes: 6 additions & 11 deletions docs/development/virtual_environments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ a few exceptions:

* The Debian packages are built from your local copy of the code, instead of
installing the current stable release packages from https://apt.freedom.press.
* The production environment only allows SSH over an Authenticated Tor Hidden
Service (ATHS), but the staging environment allows direct SSH access so it's
* The staging environment is configured for direct SSH access so it's
more ergonomic for developers to interact with the system during debugging.
* The Postfix service is disabled, so OSSEC alerts will not be sent via email.

Expand Down Expand Up @@ -108,18 +107,12 @@ Vagrant host's ``install_files/ansible-base`` directory, named:

* ``app-source-ths``
* ``app-journalist-aths``
* ``app-ssh-aths``

For working on OSSEC monitoring rules with most system hardening active, update
the OSSEC-related configuration in
``install_files/ansible-base/staging-specific.yml`` so you receive the OSSEC
alert emails.

A copy of the the Onion URL for SSH access to the *Monitor Server* is written to
the Vagrant host's ``install_files/ansible-base`` directory, named:

* ``mon-ssh-aths``

Direct SSH access is available via Vagrant for staging hosts, so you can use
``vagrant ssh app-staging`` and ``vagrant ssh mon-staging`` to start an
interactive session on either server.
Expand Down Expand Up @@ -211,7 +204,7 @@ To create the prod servers, run:
cd /var/www/securedrop/
./manage.py add-admin

A copy of the the Onion URLs for Source and Journalist Interfaces, as well as
A copy of the Onion URLs for Source and Journalist Interfaces, as well as
SSH access, are written to the Vagrant host's ``install_files/ansible-base``
directory, named:

Expand All @@ -223,5 +216,7 @@ directory, named:
SSH Access
~~~~~~~~~~

Direct SSH access is not available in the prod environment. You will need to log
in over Tor after initial provisioning. See :ref:`ssh_over_tor` for more info.
By default, direct SSH access is not enabled in the prod environment. You will need to log
in over Tor after initial provisioning or set ``enable_ssh_over_tor`` to "false"
during ``./securedrop-admin tailsconfig``. See :ref:`ssh_over_tor` or :ref:`ssh_over_local`
for more info.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ anonymous sources.
tails_guide
tails_printing_guide
https_source_interface
ssh_over_local_net
training_schedule
yubikey_setup
backup_and_restore
Expand Down
97 changes: 97 additions & 0 deletions docs/ssh_over_local_net.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
SSH Over Local Network
======================

Under a production installation post-install, the default way to gain SSH
administrative access is over the Tor network. This provides a number of benefits:

* Allows remote administration outside of the local network
* Provides anonymity to an administrator while logging into the SecureDrop
back-end.
* Can mitigate against an attacker on your local network attempting to exploit
vulnerabilities against the SSH daemon.

Most administrators will need SSH access during the course of running a
SecureDrop instance and a few times a year for maintanence. So the
potential short-falls of having SSH over Tor aren't usually a big deal.
The cons of having SSH over Tor can include:

* Really slow and delayed remote terminal performance
* Allowing SSH access from outside of your local network can be seen as a
potential larger security hole for some organizations. Particularly those
with tight network security controls.

That being said, the default setting of only allowing SSH over Tor is a good fit
for most organizations. If you happen to require SSH restricted to the local
network instead please continue to read.


.. _ssh_over_local:

Configuring SSH for local access
--------------------------------

.. warning:: It is important that your firewall is configured adequately if you
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a statement around physical access controls to the Firewall/server/network room.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think an expansion of docs are really needed? i ask because we only enable ssh via keys - i don't see the increased threat vector here. If someone has physical access to the server room, the entire system can be compromised regardless of ssh status. If they own the firewall, i guess they could hammer on ssh ? They could technically do that if there is a vulnerability in tor and/or an adversary gets ahold of someone's tails stick + persistence creds.

decide you need SSH over the local network. The install process locks
down access as much as possible with net restrictions, SSH-keys, and
google authenticator. However, you could still leave the interface
exposed to unintended users if you did not properly follow our network
firewall guide.

.. warning:: This setting will lock you out of SSH access to your instance if your
*Admin Workstation* passes through a NAT in order to get to the
SecureDrop servers. If you are unsure whether this is the case, please
consult with your firewall configuration or network administrator.

.. note:: Whichever network you install from will be the one that SSH is
restricted to post-install. This will come into play particularly if
you have multiple network interfaces.

First, make sure your local SecureDrop environment is up-to-date and on the
latest production release.

.. code:: sh

$ cd ~/Persistent/securedrop
$ ./securedrop-admin update
$ ./securedrop-admin setup

The setting that controls SSH over LAN access is set during the `sdconfig` step
of the install. Below is an example of what the prompt will look like. You can
answer either 'no' or 'false' when you are prompted for `Enable SSH over Tor`:

.. code:: sh

$ ./securedrop-admin sdconfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest recommending ./securedrop-admin setup to pull in the new requirements (netaddr)


Username for SSH access to the servers: vagrant
Local IPv4 address for the Application Server: 10.0.1.4
Local IPv4 address for the Monitor Server: 10.0.1.5
Hostname for Application Server: app
Hostname for Monitor Server: mon
[...]
Enable SSH over Tor: no

Then you'll have to run the installation script

.. code:: sh

$ ./securedrop-admin install

.. note:: If you are migrating from a production install previously configured
with SSH over Tor, you will be prompted to re-run the `install` portion
twice. This is due to the behind the scenes configuration changes being
done to switch between Tor and the local network.

Finally, re-configure your *Admin Workstation* as follows:

.. code:: sh

$ ./securedrop-admin tailsconfig

Assuming everything is working you should be able to gain SSH access as follows

.. code:: sh

$ ssh app
$ ssh mon

3 changes: 3 additions & 0 deletions docs/test_the_installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Test connectivity
SSH to both servers over Tor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Assuming you haven't disabled ssh over tor, SSH access will be
restricted to the tor network.

On the *Admin Workstation*, you should be able to SSH to the *Application Server* and the *Monitor Server*. ::

ssh app
Expand Down
9 changes: 9 additions & 0 deletions install_files/ansible-base/group_vars/all/securedrop
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@ appserver_dependencies:
- libjpeg-dev

tor_apt_repo_url: https://tor-apt.freedom.press

# Enable Tor over SSH by default
enable_ssh_over_tor: true


# If file is present on system at the end of ansible run
# force a reboot. Needed because of the de-coupled nature of
# the many roles of the current prod playbook
securedrop_cond_reboot_file: /tmp/sd-reboot-now
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ local_deb_packages:

# Configuring the tor hidden services
tor_instances:
- service: ssh
filename: app-ssh-aths
- "{{ {'service': 'ssh', 'filename': 'app-ssh-aths'} if enable_ssh_over_tor else [] }}"
- service: source
filename: app-source-ths
- service: journalist
Expand All @@ -40,3 +39,6 @@ authd_iprules:

# Declare Application Server as OSSEC agent role.
ossec_is_client: yes

ssh_ip: "{{ app_ip|default(ansible_default_ipv4.address) }}"
adjacent_sd_ip: "{{ monitor_ip }}"
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ local_deb_packages:

# Configure the tor hidden services. The Monitor server has only one,
# for SSH, since no web interfaces.
tor_instances:
- service: ssh
filename: mon-ssh-aths
tor_instances: "{{ [{ 'service': 'ssh', 'filename': 'mon-ssh-aths'}] if enable_ssh_over_tor else [] }}"

authd_iprules:
- chain: INPUT
Expand All @@ -36,3 +34,6 @@ authd_iprules:

# Declare Monitor Server as OSSEC server role.
ossec_is_server: yes

ssh_ip: "{{ monitor_ip|default(ansible_default_ipv4.address) }}"
adjacent_sd_ip: "{{ app_ip }}"
3 changes: 1 addition & 2 deletions install_files/ansible-base/group_vars/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ postfix_enable_service: no

# Permit direct access for SSH in the staging environment.
# Otherwise, all SSH connections would be forced over Tor.
ssh_listening_address: 0.0.0.0
allow_direct_access: true
enable_ssh_over_tor: false

### Use for backup restores ###
# If the `backup_zip` variable is defined ansible will copy the defined file to
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
- name: Extract ec2 vars when in AWS
ec2_facts:
ec2_metadata_facts:

- name: Set inventory hostnames
hostname:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
# Set the default SSH listening address for the sshd config file.
# In production, sshd listening to localhost (127.0.0.1), since all SSH
# connections are forced over Tor. In staging, this value will be 0.0.0.0
# to enable direct access for testing during development.
ssh_listening_address: 127.0.0.1
enable_ssh_over_tor: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value consistent with current project settings. 👍


allow_direct_access: false
# Set the default SSH listening address for the sshd config file.
# If enable_ssh_over_tor is false, open up SSH (additional iptables templates
# helps us for restriction) otherwise restrict to localhost (tor).
ssh_listening_address: "{{ '127.0.0.1' if enable_ssh_over_tor else '0.0.0.0' }}"

# This var is defined in the tor-hidden-services role, but won't be available
# in separate plays, so declaring it within the context of iptables role, so
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@
service:
name: ssh
state: restarted

- name: drop flag for reboot
file:
path: "{{ securedrop_cond_reboot_file }}"
state: touch
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,39 @@
- iptables
- permissions

- name: Determine admin network - first find admin net dev
set_fact:
admin_dev: "{{ lookup('pipe','/bin/ip r get '+ssh_ip)|regex_search('(?<=dev )\\w+') }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this so I want to make a note for posterity: this logic doesn't work as is for the vagrant prod VM workflow on macOS (only for when: not enable_ssh_over_tor) - the reason being that ip is not present:

TASK [restrict-direct-access : Determine admin network - first find admin net dev] ***
/bin/sh: /bin/ip: No such file or directory
fatal: [app-prod]: FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'pipe'. Error was a <class 'ansible.errors.AnsibleError'>, original message: lookup_plugin.pipe(/bin/ip r get 10.0.1.4) returned 127"}
/bin/sh: /bin/ip: No such file or directory
fatal: [mon-prod]: FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'pipe'. Error was a <class 'ansible.errors.AnsibleError'>, original message: lookup_plugin.pipe(/bin/ip r get 10.0.1.5) returned 127"}

That said, the prod VM workflow works when SSH over Tor is on (double checked this via manual testing), and since the restrict-direct-access role isn't used in staging, I think this isn't a blocker.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually OK with this, @redshiftzero. Use of the prod VMs has become highly dependent on a virtualized Tails setup, and we'd do well to go more in that direction, e.g. removing the Ansible integration from the Vagrantfile for the "prod" VMs altogether. Holler if you disagree; we can discuss separately.

when: not enable_ssh_over_tor
tags:
- iptables
- permissions

- name: Gather localhost facts first
setup:
become: no
delegate_to: localhost
delegate_facts: True
run_once: True

- name: Determine admin network - next compute admin network cidr
set_fact:
admin_net_cidr: "{{ '/'.join([hostvars['localhost']['ansible_'+admin_dev].ipv4.network,
hostvars['localhost']['ansible_'+admin_dev].ipv4.netmask]
)|ipaddr('cidr') }}"
delegate_to: localhost
when: not enable_ssh_over_tor
tags:
- iptables
- permissions

- name: Copy IPv4 iptables rules.
template:
src: rules_v4
dest: /etc/network/iptables/rules_v4
owner: root
mode: "0644"
notify: drop flag for reboot
tags:
- iptables
- permissions
Expand Down
Loading