From 390eb44afff7e7685a7728cf5df643240b1bc4a0 Mon Sep 17 00:00:00 2001 From: Kevin O'Gorman Date: Fri, 23 Apr 2021 11:44:35 -0400 Subject: [PATCH 1/3] Removes v2 service configuration and setup support - Removes the options to select v2 and/or v3 in sdconfig. v3 is the only option available, so no need to prompt - Removes ansible tasks and defaults related to v2 service setup, and cleans up conditionals around v3 config - Removes tailsconfig tasks and defauls related to v2 services --- admin/securedrop_admin/__init__.py | 79 +----- admin/tests/test_integration.py | 227 ------------------ admin/tests/test_securedrop-admin.py | 58 ----- .../ansible-base/group_vars/staging.yml | 3 - install_files/ansible-base/inventory-dynamic | 28 +-- .../ansible-base/roles/app/defaults/main.yml | 6 - .../tasks/copy_tor_url_info_to_app_dir.yml | 38 --- .../restrict-direct-access/defaults/main.yml | 6 - .../tasks/fetch_tor_config.yml | 38 --- .../roles/tails-config/defaults/main.yml | 6 - .../tasks/configure_torrc_additions.yml | 34 +-- .../tasks/create_desktop_shortcuts.yml | 19 +- .../tails-config/tasks/create_ssh_aliases.yml | 15 -- .../tails-config/templates/ssh_config.j2 | 35 --- .../tor-hidden-services/defaults/main.yml | 6 - .../check_tor_service_config_for_admins.yml | 39 --- .../tasks/configure_tor_hidden_services.yml | 12 +- .../roles/tor-hidden-services/tasks/main.yml | 2 - .../roles/tor-hidden-services/templates/torrc | 26 +- .../tasks/validate_tails_environment.yml | 7 - .../ansible-base/securedrop-prod.yml | 9 - 21 files changed, 13 insertions(+), 680 deletions(-) delete mode 100644 install_files/ansible-base/roles/tor-hidden-services/tasks/check_tor_service_config_for_admins.yml diff --git a/admin/securedrop_admin/__init__.py b/admin/securedrop_admin/__init__.py index 7c4f7f0fa9..4e504d510b 100755 --- a/admin/securedrop_admin/__init__.py +++ b/admin/securedrop_admin/__init__.py @@ -64,7 +64,7 @@ sdlog = logging.getLogger(__name__) RELEASE_KEY = '22245C81E3BAEB4138B36061310F561200F4AD77' DEFAULT_KEYSERVER = 'hkps://keys.openpgp.org' -SUPPORT_ONION_URL = 'http://support6kv2242qx.onion' +SUPPORT_ONION_URL = 'http://sup6h5iyiyenvjkfxbgrjynm5wsgijjoatvnvdgyyi7je3xqm4kh6uqd.onion' SUPPORT_URL = 'https://support.freedom.press' EXIT_SUCCESS = 0 EXIT_SUBPROCESS_ERROR = 1 @@ -193,23 +193,6 @@ def validate(self, document: Document) -> bool: return True raise ValidationError(message="Must be either yes or no") - class ValidateYesNoForV3(Validator): - - def __init__(self, *args: Any, **kwargs: Any) -> None: - Validator.__init__(*args, **kwargs) - self.caller = args[0] - - def validate(self, document: Document) -> bool: - text = document.text.lower() - # Raise error if admin tries to disable v3 when v2 - # is already disabled. - if text == 'no' and \ - not self.caller._config_in_progress.get("v2_onion_services"): # noqa: E501 - raise ValidationError(message="Since you disabled v2 onion services, you must enable v3 onion services.") # noqa: E501 - if text == 'yes' or text == 'no': - return True - raise ValidationError(message="Must be either yes or no") - class ValidateFingerprint(Validator): def validate(self, document: Document) -> bool: text = document.text.replace(' ', '') @@ -457,17 +440,6 @@ def __init__(self, args: argparse.Namespace) -> None: SiteConfig.ValidateLocales(self.args.app_path), str.split, lambda config: True), - ('v2_onion_services', self.check_for_v2_onion(), bool, - 'WARNING: v2 onion services cannot be installed on servers ' + - 'running Ubuntu 20.04. Do you want to enable v2 onion services?', - SiteConfig.ValidateYesNo(), - lambda x: x.lower() == 'yes', - lambda config: True), - ('v3_onion_services', self.check_for_v3_onion, bool, - 'Do you want to enable v3 onion services (recommended)?', - SiteConfig.ValidateYesNoForV3(self), - lambda x: x.lower() == 'yes', - lambda config: True), ] # type: List[_DescEntryType] def load_and_update_config(self, validate: bool = True, prompt: bool = True) -> bool: @@ -485,52 +457,8 @@ def update_config(self, prompt: bool = True) -> bool: self.save() self.validate_gpg_keys() self.validate_journalist_alert_email() - self.validate_https_and_v3() return True - def validate_https_and_v3(self) -> bool: - """ - Checks if https is enabled with v3 onion service. - - :returns: False if both v3 and https enabled, True otherwise. - """ - warning_msg = ("You have configured HTTPS on your source interface " - "and v3 onion services. " - "IMPORTANT: Ensure that you update your certificate " - "to include your v3 source URL before advertising " - "it to sources! ") - - if self.config.get("v3_onion_services", False) and \ - self.config.get("securedrop_app_https_certificate_cert_src"): - print(warning_msg) - return False - return True - - def check_for_v2_onion(self) -> bool: - """ - Check if v2 onion services are already enabled or not. - """ - source_ths = os.path.join(self.args.ansible_path, "app-source-ths") - if os.path.exists(source_ths): # Means old installation - data = "" - with open(source_ths) as fobj: - data = fobj.read() - - data = data.strip() - if len(data) < 56: # Old v2 onion address - return True - return False - - def check_for_v3_onion(self) -> bool: - """ - Check if v3 onion services should be enabled by default or not. - """ - v2_value = self._config_in_progress.get("v2_onion_services", False) - # We need to see the value in the configuration file - # for v3_onion_services - v3_value = self.config.get("v3_onion_services", True) - return v3_value or not v2_value - def user_prompt_config(self) -> Dict[str, Any]: self._config_in_progress = {} for desc in self.desc: @@ -547,10 +475,7 @@ def user_prompt_config_one( self, desc: _DescEntryType, from_config: Optional[Any] ) -> Any: (var, default, type, prompt, validator, transform, condition) = desc - if from_config is not None and var != "v3_onion_services": - # v3_onion_services must be true if v2 is disabled by the admin - # otherwise, we may end up in a situation where both v2 and v3 - # are disabled by the admin (by mistake). + if from_config is not None: default = from_config prompt += ': ' diff --git a/admin/tests/test_integration.py b/admin/tests/test_integration.py index 72a269b816..eff9ff99ad 100644 --- a/admin/tests/test_integration.py +++ b/admin/tests/test_integration.py @@ -47,76 +47,6 @@ smtp_relay: smtp.gmail.com smtp_relay_port: 587 ssh_users: sd -v2_onion_services: false -v3_onion_services: true -''' - -WHEN_BOTH_TRUE = '''app_hostname: app -app_ip: 10.20.2.2 -daily_reboot_time: 5 -dns_server: -- 8.8.8.8 -- 8.8.4.4 -enable_ssh_over_tor: true -journalist_alert_email: '' -journalist_alert_gpg_public_key: '' -journalist_gpg_fpr: '' -monitor_hostname: mon -monitor_ip: 10.20.3.2 -ossec_alert_email: test@gmail.com -ossec_alert_gpg_public_key: sd_admin_test.pub -ossec_gpg_fpr: 1F544B31C845D698EB31F2FF364F1162D32E7E58 -sasl_domain: gmail.com -sasl_password: testpassword -sasl_username: testuser -securedrop_app_gpg_fingerprint: 1F544B31C845D698EB31F2FF364F1162D32E7E58 -securedrop_app_gpg_public_key: sd_admin_test.pub -securedrop_app_https_certificate_cert_src: '' -securedrop_app_https_certificate_chain_src: '' -securedrop_app_https_certificate_key_src: '' -securedrop_app_https_on_source_interface: false -securedrop_supported_locales: -- de_DE -- es_ES -smtp_relay: smtp.gmail.com -smtp_relay_port: 587 -ssh_users: sd -v2_onion_services: true -v3_onion_services: true -''' - -WHEN_ONLY_V2 = '''app_hostname: app -app_ip: 10.20.2.2 -daily_reboot_time: 5 -dns_server: -- 8.8.8.8 -- 8.8.4.4 -enable_ssh_over_tor: true -journalist_alert_email: '' -journalist_alert_gpg_public_key: '' -journalist_gpg_fpr: '' -monitor_hostname: mon -monitor_ip: 10.20.3.2 -ossec_alert_email: test@gmail.com -ossec_alert_gpg_public_key: sd_admin_test.pub -ossec_gpg_fpr: 1F544B31C845D698EB31F2FF364F1162D32E7E58 -sasl_domain: gmail.com -sasl_password: testpassword -sasl_username: testuser -securedrop_app_gpg_fingerprint: 1F544B31C845D698EB31F2FF364F1162D32E7E58 -securedrop_app_gpg_public_key: sd_admin_test.pub -securedrop_app_https_certificate_cert_src: '' -securedrop_app_https_certificate_chain_src: '' -securedrop_app_https_certificate_key_src: '' -securedrop_app_https_on_source_interface: false -securedrop_supported_locales: -- de_DE -- es_ES -smtp_relay: smtp.gmail.com -smtp_relay_port: 587 -ssh_users: sd -v2_onion_services: true -v3_onion_services: false ''' JOURNALIST_ALERT_OUTPUT = '''app_hostname: app @@ -149,8 +79,6 @@ smtp_relay: smtp.gmail.com smtp_relay_port: 587 ssh_users: sd -v2_onion_services: false -v3_onion_services: true ''' HTTPS_OUTPUT = '''app_hostname: app @@ -183,8 +111,6 @@ smtp_relay: smtp.gmail.com smtp_relay_port: 587 ssh_users: sd -v2_onion_services: false -v3_onion_services: true ''' @@ -339,21 +265,6 @@ def verify_locales_prompt(child): child.expect(rb'Space separated list of additional locales to support') # noqa: E501 -def verify_v2_onion_for_first_time(child): - child.expect(rb'Do you want to enable v2 onion services\?\:', timeout=2) # noqa: E501 - assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'no' # noqa: E501 - - -def verify_v3_onion_for_first_time(child): - child.expect(rb'Do you want to enable v3 onion services \(recommended\)\?\:', timeout=2) # noqa: E501 - assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'yes' # noqa: E501 - - -def verify_v3_onion_when_v2_is_enabled(child): - child.expect(rb'Do you want to enable v3 onion services \(recommended\)\?\:', timeout=2) # noqa: E501 - assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'yes' # noqa: E501 - - def verify_install_has_valid_config(): """ Checks that securedrop-admin install validates the configuration. @@ -424,9 +335,7 @@ def test_sdconfig_on_first_run(): child.sendline('') verify_locales_prompt(child) child.sendline('de_DE es_ES') - verify_v2_onion_for_first_time(child) child.sendline('\b' * 3 + 'no') - verify_v3_onion_for_first_time(child) child.sendline('\b' * 4 + 'yes') child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur @@ -441,134 +350,6 @@ def test_sdconfig_on_first_run(): verify_install_has_valid_config() -def test_sdconfig_both_v2_v3_true(): - cmd = os.path.join(os.path.dirname(CURRENT_DIR), - 'securedrop_admin/__init__.py') - child = pexpect.spawn('python {0} --force --root {1} sdconfig'.format(cmd, SD_DIR)) - verify_username_prompt(child) - child.sendline('') - verify_reboot_prompt(child) - child.sendline('\b5') # backspace and put 5 - verify_ipv4_appserver_prompt(child) - child.sendline('') - verify_ipv4_monserver_prompt(child) - child.sendline('') - verify_hostname_app_prompt(child) - child.sendline('') - verify_hostname_mon_prompt(child) - child.sendline('') - verify_dns_prompt(child) - child.sendline('') - verify_app_gpg_key_prompt(child) - child.sendline('\b' * 14 + 'sd_admin_test.pub') - verify_https_prompt(child) - # Default answer is no - child.sendline('') - verify_app_gpg_fingerprint_prompt(child) - child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58') - verify_ossec_gpg_key_prompt(child) - child.sendline('\b' * 9 + 'sd_admin_test.pub') - verify_ossec_gpg_fingerprint_prompt(child) - child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58') - verify_admin_email_prompt(child) - child.sendline('test@gmail.com') - verify_journalist_gpg_key_prompt(child) - child.sendline('') - verify_smtp_relay_prompt(child) - child.sendline('') - verify_smtp_port_prompt(child) - child.sendline('') - verify_sasl_domain_prompt(child) - child.sendline('') - verify_sasl_username_prompt(child) - child.sendline('testuser') - verify_sasl_password_prompt(child) - child.sendline('testpassword') - verify_ssh_over_lan_prompt(child) - child.sendline('') - verify_locales_prompt(child) - child.sendline('de_DE es_ES') - verify_v2_onion_for_first_time(child) - child.sendline('\b' * 3 + 'yes') - verify_v3_onion_when_v2_is_enabled(child) - child.sendline('\b' * 3 + 'yes') - - child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur - child.close() - assert child.exitstatus == 0 - assert child.signalstatus is None - - with open(os.path.join(SD_DIR, 'install_files/ansible-base/group_vars/all/site-specific')) as fobj: # noqa: E501 - data = fobj.read() - assert data == WHEN_BOTH_TRUE - - verify_install_has_valid_config() - - -def test_sdconfig_only_v2_true(): - cmd = os.path.join(os.path.dirname(CURRENT_DIR), - 'securedrop_admin/__init__.py') - child = pexpect.spawn('python {0} --force --root {1} sdconfig'.format(cmd, SD_DIR)) - verify_username_prompt(child) - child.sendline('') - verify_reboot_prompt(child) - child.sendline('\b5') # backspace and put 5 - verify_ipv4_appserver_prompt(child) - child.sendline('') - verify_ipv4_monserver_prompt(child) - child.sendline('') - verify_hostname_app_prompt(child) - child.sendline('') - verify_hostname_mon_prompt(child) - child.sendline('') - verify_dns_prompt(child) - child.sendline('') - verify_app_gpg_key_prompt(child) - child.sendline('\b' * 14 + 'sd_admin_test.pub') - verify_https_prompt(child) - # Default answer is no - child.sendline('') - verify_app_gpg_fingerprint_prompt(child) - child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58') - verify_ossec_gpg_key_prompt(child) - child.sendline('\b' * 9 + 'sd_admin_test.pub') - verify_ossec_gpg_fingerprint_prompt(child) - child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58') - verify_admin_email_prompt(child) - child.sendline('test@gmail.com') - verify_journalist_gpg_key_prompt(child) - child.sendline('') - verify_smtp_relay_prompt(child) - child.sendline('') - verify_smtp_port_prompt(child) - child.sendline('') - verify_sasl_domain_prompt(child) - child.sendline('') - verify_sasl_username_prompt(child) - child.sendline('testuser') - verify_sasl_password_prompt(child) - child.sendline('testpassword') - verify_ssh_over_lan_prompt(child) - child.sendline('') - verify_locales_prompt(child) - child.sendline('de_DE es_ES') - verify_v2_onion_for_first_time(child) - child.sendline('\b' * 3 + 'yes') - verify_v3_onion_when_v2_is_enabled(child) - child.sendline('\b' * 3 + 'no') - - child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur - child.close() - assert child.exitstatus == 0 - assert child.signalstatus is None - - with open(os.path.join(SD_DIR, 'install_files/ansible-base/group_vars/all/site-specific')) as fobj: # noqa: E501 - data = fobj.read() - assert data == WHEN_ONLY_V2 - - verify_install_has_valid_config() - - def test_sdconfig_enable_journalist_alerts(): cmd = os.path.join(os.path.dirname(CURRENT_DIR), 'securedrop_admin/__init__.py') @@ -621,10 +402,6 @@ def test_sdconfig_enable_journalist_alerts(): child.sendline('') verify_locales_prompt(child) child.sendline('de_DE es_ES') - verify_v2_onion_for_first_time(child) - child.sendline('\b' * 3 + 'no') - verify_v3_onion_for_first_time(child) - child.sendline('\b' * 4 + 'yes') child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur child.close() @@ -697,10 +474,6 @@ def test_sdconfig_enable_https_on_source_interface(): child.sendline('') verify_locales_prompt(child) child.sendline('de_DE es_ES') - verify_v2_onion_for_first_time(child) - child.sendline('\b' * 3 + 'no') - verify_v3_onion_for_first_time(child) - child.sendline('\b' * 4 + 'yes') child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur child.close() diff --git a/admin/tests/test_securedrop-admin.py b/admin/tests/test_securedrop-admin.py index 2f9fc2a4b2..33230dbde1 100644 --- a/admin/tests/test_securedrop-admin.py +++ b/admin/tests/test_securedrop-admin.py @@ -814,15 +814,6 @@ def verify_desc_consistency_optional(self, site_config, desc): def verify_desc_consistency(self, site_config, desc): self.verify_desc_consistency_optional(site_config, desc) - (var, default, etype, prompt, validator, transform, condition) = desc - with pytest.raises(ValidationError): - site_config.user_prompt_config_one(desc, '') - # If we are testing v3_onion_services, that will create a default - # value of 'yes', means it will not raise the ValidationError. We - # are generating it below for test to behave properly with all - # other test cases. - if var == "v3_onion_services": - raise ValidationError() def verify_prompt_boolean( self, site_config, desc): @@ -833,34 +824,6 @@ def verify_prompt_boolean( assert site_config.user_prompt_config_one(desc, 'YES') is True assert site_config.user_prompt_config_one(desc, 'NO') is False - def verify_prompt_boolean_for_v3( - self, site_config, desc): - """As v3_onion_services input depends on input of - v2_onion_service, the answers will change. - """ - self.verify_desc_consistency(site_config, desc) - (var, default, etype, prompt, validator, transform, condition) = desc - assert site_config.user_prompt_config_one(desc, True) is True - # Because if no v2_onion_service, v3 will become True - assert site_config.user_prompt_config_one(desc, False) is True - assert site_config.user_prompt_config_one(desc, 'YES') is True - # Because if no v2_onion_service, v3 will become True - assert site_config.user_prompt_config_one(desc, 'NO') is True - - # Now we will set v2_onion_services as True so that we - # can set v3_onion_service as False. This is the case - # when an admin particularly marked v3 as False. - site_config._config_in_progress = {"v2_onion_services": True} - site_config.config = {"v3_onion_services": False} - - # The next two tests should use the default from the above line, - # means it will return False value. - assert site_config.user_prompt_config_one(desc, True) is False - assert site_config.user_prompt_config_one(desc, 'YES') is False - - assert site_config.user_prompt_config_one(desc, False) is False - assert site_config.user_prompt_config_one(desc, 'NO') is False - def test_desc_conditional(self): """Ensure that conditional prompts behave correctly. @@ -915,8 +878,6 @@ def auto_prompt(prompt, default, **kwargs): verify_prompt_enable_ssh_over_tor = verify_prompt_boolean verify_prompt_securedrop_app_gpg_public_key = verify_desc_consistency - verify_prompt_v2_onion_services = verify_prompt_boolean - verify_prompt_v3_onion_services = verify_prompt_boolean_for_v3 def verify_prompt_not_empty(self, site_config, desc): with pytest.raises(ValidationError): @@ -1094,22 +1055,3 @@ def test_find_or_generate_new_torv3_keys_subsequent_run(tmpdir, capsys): v3_onion_service_keys = json.load(f) assert v3_onion_service_keys == old_keys - - -def test_v3_and_https_cert_message(tmpdir, capsys): - args = argparse.Namespace(site_config='UNKNOWN', - ansible_path='tests/files', - app_path=dirname(__file__)) - site_config = securedrop_admin.SiteConfig(args) - site_config.config = {"v3_onion_services": False, - "securedrop_app_https_certificate_cert_src": "ab.crt"} # noqa: E501 - # This should return True as v3 is not setup - assert site_config.validate_https_and_v3() - - # This should return False as v3 and https are both setup - site_config.config.update({"v3_onion_services": True}) - assert not site_config.validate_https_and_v3() - - # This should return True as https is not setup - site_config.config.update({"securedrop_app_https_certificate_cert_src": ""}) # noqa: E501 - assert site_config.validate_https_and_v3() diff --git a/install_files/ansible-base/group_vars/staging.yml b/install_files/ansible-base/group_vars/staging.yml index a4dc5d6c48..b7c9dd6b9d 100644 --- a/install_files/ansible-base/group_vars/staging.yml +++ b/install_files/ansible-base/group_vars/staging.yml @@ -52,9 +52,6 @@ postfix_enable_service: no # Otherwise, all SSH connections would be forced over Tor. enable_ssh_over_tor: false -# v3 onion services should be available in staging for testing. -v3_onion_services: true - install_local_packages: true # Don't install app-code package from the FPF apt repo, since we want to run diff --git a/install_files/ansible-base/inventory-dynamic b/install_files/ansible-base/inventory-dynamic index 56c564503a..d3471d9f02 100755 --- a/install_files/ansible-base/inventory-dynamic +++ b/install_files/ansible-base/inventory-dynamic @@ -92,29 +92,6 @@ def lookup_admin_username(): return admin_username -def lookup_tor_v2_hostname(hostname): - """ - Extract Onion v2 URL from HidServAuth file that was fetched back locally. - Returns Onion URL for given inventory hostname. - """ - aths_path = os.path.join(SECUREDROP_ANSIBLE_DIRECTORY, - "{}-ssh-aths".format(hostname)) - with io.open(aths_path, 'r') as f: - tor_config = f.readline().rstrip().split() - try: - # 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_v2_hostname = tor_config[1] - except IndexError: - msg = ("Tor v2 config file for '{}' ", - "appears to be empty").format(hostname) - raise Exception(msg=msg) - - return tor_v2_hostname - - def lookup_tor_v3_hostname(hostname): """ Extract Onion v3 URL from .auth_private file that was fetched back locally. @@ -144,10 +121,7 @@ def lookup_ssh_address(hostname): ssh_address = lookup_tor_v3_hostname(hostname) # Don't assume ATHS files are present; they won't be on first run. except (IndexError, EnvironmentError): - try: - ssh_address = lookup_tor_v2_hostname(hostname) - except (IndexError, EnvironmentError): - pass + pass return ssh_address diff --git a/install_files/ansible-base/roles/app/defaults/main.yml b/install_files/ansible-base/roles/app/defaults/main.yml index a249840add..130734c262 100644 --- a/install_files/ansible-base/roles/app/defaults/main.yml +++ b/install_files/ansible-base/roles/app/defaults/main.yml @@ -75,9 +75,3 @@ apache_disabled_modules: securedrop_default_locale: en_US # The subset of the available locales that will be proposed to the user securedrop_supported_locales: [] - -# v2 Tor onion services are on / v3 Tor onion services are off by default for backwards -# compatibility. Note that new installs after 1.0 will have v3 enabled by sdconfig which -# will override these variables. -v2_onion_services: true -v3_onion_services: false diff --git a/install_files/ansible-base/roles/app/tasks/copy_tor_url_info_to_app_dir.yml b/install_files/ansible-base/roles/app/tasks/copy_tor_url_info_to_app_dir.yml index 07137d31b5..64f7cb3679 100644 --- a/install_files/ansible-base/roles/app/tasks/copy_tor_url_info_to_app_dir.yml +++ b/install_files/ansible-base/roles/app/tasks/copy_tor_url_info_to_app_dir.yml @@ -1,39 +1,10 @@ --- -- name: Look up Tor v2 URL info - command: cat /var/lib/tor/services/source/hostname - changed_when: false - register: v2_onion_url_lookup_result - # File may not exist, depending on host config - failed_when: false - when: v2_onion_services - - name: Look up Tor v3 URL info command: cat /var/lib/tor/services/sourcev3/hostname changed_when: false register: v3_onion_url_lookup_result # File may not exist, depending on host config failed_when: false - when: v3_onion_services - -- name: Expose source v2 onion service info to app - copy: - dest: /var/lib/securedrop/source_v2_url - owner: www-data - group: www-data - mode: "0644" - content: | - {{ v2_onion_url_lookup_result.stdout|default('') }} - notify: - - restart apache2 - when: v2_onion_services - -- name: Remove source v2 onion service info if not enabled - file: - path: /var/lib/securedrop/source_v2_url - state: absent - notify: - - restart apache2 - when: not v2_onion_services - name: Expose source v3 onion service info to app copy: @@ -45,12 +16,3 @@ {{ v3_onion_url_lookup_result.stdout|default('') }} notify: - restart apache2 - when: v3_onion_services - -- name: Remove source v3 onion service info if not enabled - file: - path: /var/lib/securedrop/source_v3_url - state: absent - notify: - - restart apache2 - when: not v3_onion_services diff --git a/install_files/ansible-base/roles/restrict-direct-access/defaults/main.yml b/install_files/ansible-base/roles/restrict-direct-access/defaults/main.yml index d1fa879a83..6faaaaf88c 100644 --- a/install_files/ansible-base/roles/restrict-direct-access/defaults/main.yml +++ b/install_files/ansible-base/roles/restrict-direct-access/defaults/main.yml @@ -26,12 +26,6 @@ admin_net_int: # required for the ssh-over-lan strategy. fetch_tor_client_auth_configs: true -# v2 Tor onion services are on / v3 Tor onion services are off by default for backwards -# compatibility. Note that new install after 1.0 will have v3 enabled by sdconfig which -# will override these variables. -v2_onion_services: true -v3_onion_services: false - # Lookup table for querying keypair info from the local JSON # file on the Admin Workstation, required for configuring client # auth on Tor v3 Onion URLs. See the tor_v3_keys.json file for diff --git a/install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml b/install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml index 557bdd8439..761afaa8c2 100644 --- a/install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml +++ b/install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml @@ -1,46 +1,10 @@ --- -- name: Wait for all Tor onion services hostname files. - wait_for: - state: present - path: "{{ tor_hidden_services_parent_dir }}/{{ item.service }}/hostname" - delay: 5 - with_items: "{{ tor_instances }}" - when: "v2_onion_services" - tags: - - tor - -- name: Collect Tor Onion Service hostnames. - command: cat /var/lib/tor/services/{{ item.service }}/hostname - register: tor_hidden_service_hostname_lookup - # Read-only task, so don't report changed. - changed_when: false - with_items: "{{ tor_instances }}" - when: "v2_onion_services" - tags: - - tor - - admin - -- name: Write Tor Onion Service hostname files to Admin Workstation. - local_action: - module: template - dest: "{{ role_path }}/../../{{ item.item.filename }}" - src: ths_config.j2 - # Local action, so we don't want elevated privileges - become: no - with_items: "{{ tor_hidden_service_hostname_lookup.results }}" - when: "v2_onion_services" - tags: - - tor - - admin - - - name: Wait for all Tor v3 onion services hostname files. wait_for: state: present path: "{{ tor_hidden_services_parent_dir }}/{{ item.service }}/hostname" delay: 5 with_items: "{{ tor_instances_v3 }}" - when: "v3_onion_services" tags: - tor @@ -50,7 +14,6 @@ # Read-only task, so don't report changed. changed_when: false with_items: "{{ tor_instances_v3 }}" - when: "v3_onion_services" tags: - tor - admin @@ -63,7 +26,6 @@ # Local action, so we don't want elevated privileges become: no with_items: "{{ tor_hidden_service_hostnamev3_lookup.results }}" - when: "v3_onion_services" tags: - tor - admin diff --git a/install_files/ansible-base/roles/tails-config/defaults/main.yml b/install_files/ansible-base/roles/tails-config/defaults/main.yml index d02d229292..3d468feecb 100644 --- a/install_files/ansible-base/roles/tails-config/defaults/main.yml +++ b/install_files/ansible-base/roles/tails-config/defaults/main.yml @@ -41,9 +41,3 @@ tails_config_deprecated_directories: tails_config_deprecated_config_files: - 70-tor-reload.sh - 99-tor-reload.sh - -# v2 Tor onion services are on / v3 Tor onion services are off by default for backwards -# compatibility. Note that new installs after 1.0 will have v3 enabled by sdconfig which -# will override these variables. -v2_onion_services: true -v3_onion_services: false diff --git a/install_files/ansible-base/roles/tails-config/tasks/configure_torrc_additions.yml b/install_files/ansible-base/roles/tails-config/tasks/configure_torrc_additions.yml index 69d9d3ce88..1fa8457e3e 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/configure_torrc_additions.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/configure_torrc_additions.yml @@ -1,14 +1,4 @@ --- -- 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 - - name: Find V3 Authenticated Onion Service info for SecureDrop interfaces. find: paths: @@ -19,31 +9,17 @@ - '*.auth_private' register: find_v3_aths_info_result -# We need at least one v2 or v3 ATHS value, for the Journalist Interface. -# If v2 is enabled, there will be 3 v2 `-aths` files on the Admin Interface. -# If v3 is enabled, there will be 3 v3 `.auth_private` files on the Admin Interface. -# If both are enabled, the Admin Interface will have 6 files in total. -# This task simply validates that at least one suitable file was found; +# This task validates that at least one suitable Tor service file was found; # if not, then the playbooks haven't been run, so fail with instructions. -- name: Confirm ATHS info was found. +- name: Confirm Tor service info was found. assert: that: - - find_aths_info_result.matched + find_v3_aths_info_result.matched >= 1 + - find_v3_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` and/or `.auth_private` files are located in: + Failed to find Tor service info locally. Make sure you've installed SecureDrop + on the servers, and that the `.auth_private` 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" - - name: Append ClientOnionAuthDir directive to torrc additions become: yes lineinfile: diff --git a/install_files/ansible-base/roles/tails-config/tasks/create_desktop_shortcuts.yml b/install_files/ansible-base/roles/tails-config/tasks/create_desktop_shortcuts.yml index 3b229ed201..bd1a2f65ab 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/create_desktop_shortcuts.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/create_desktop_shortcuts.yml @@ -3,9 +3,6 @@ # 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. -# Desktop shortcuts default to v3 URLs when available - as `site-specific` -# is not copied to Journalist Workstations, the {v2,v3}_onion_service -# booleans can't be used to choose a preference. - name: Check for v3 Source Interface file stat: @@ -17,24 +14,12 @@ path: app-journalist.auth_private register: v3_journalist_file -- name: Look up v2 Source Interface URL. - command: grep -Po '.{16}\.onion' app-source-ths - changed_when: false - register: source_interface_lookup_result - when: v3_source_file.stat.exists == false - - name: Look up v3 Source Interface URL. command: grep -Po '.{56}\.onion' app-sourcev3-ths changed_when: false register: sourcev3_interface_lookup_result when: v3_source_file.stat.exists == true -- name: Look up v2 Journalist Interface URL. - command: grep -Po '.{16}\.onion' app-journalist-aths - changed_when: false - register: journalist_interface_lookup_result - when: v3_source_file.stat.exists == false - - name: Look up v3 Journalist Interface URL. command: awk -F ':' '{print $1 ".onion"}' app-journalist.auth_private changed_when: false @@ -60,11 +45,11 @@ - name: Set the right variable for source set_fact: - source_iface: "{{ sourcev3_interface_lookup_result if (v3_source_file.stat.exists == true) else source_interface_lookup_result }}" + source_iface: "{{ sourcev3_interface_lookup_result }}" - name: Set the right variable for journalist set_fact: - journalist_iface: "{{ journalistv3_interface_lookup_result if (v3_source_file.stat.exists == true) else journalist_interface_lookup_result }}" + journalist_iface: "{{ journalistv3_interface_lookup_result }}" - debug: var: source_iface diff --git a/install_files/ansible-base/roles/tails-config/tasks/create_ssh_aliases.yml b/install_files/ansible-base/roles/tails-config/tasks/create_ssh_aliases.yml index c47aecce3d..c708b7f6d4 100644 --- a/install_files/ansible-base/roles/tails-config/tasks/create_ssh_aliases.yml +++ b/install_files/ansible-base/roles/tails-config/tasks/create_ssh_aliases.yml @@ -2,14 +2,6 @@ - name: Import variables include_vars: "group_vars/all/site-specific" -- name: Lookup v2 onion ssh files - stat: - path: "{{ item }}-ssh-aths" - register: "ssh_onion_lookup" - with_items: - - app - - mon - - name: Lookup v3 onion ssh files stat: path: "{{ item }}-ssh.auth_private" @@ -22,17 +14,10 @@ set_fact: mon_ip: "{{ monitor_ip }}" -- name: Confirm that either the app onion ssh file exists or site-specific file exists - assert: - that: "item.stat.exists or {{item.item}}_ip is defined" - with_items: "{{ ssh_onion_lookup.results }}" - when: v2_onion_services == True - - name: Confirm that either the app v3 onion ssh file exists or site-specific file exists assert: that: "item.stat.exists or {{item.item}}_ip is defined" with_items: "{{ ssh_v3_onion_lookup.results }}" - when: v3_onion_services == True - name: Create SSH config directory. become: yes diff --git a/install_files/ansible-base/roles/tails-config/templates/ssh_config.j2 b/install_files/ansible-base/roles/tails-config/templates/ssh_config.j2 index 6bba3212db..ad2e01230f 100644 --- a/install_files/ansible-base/roles/tails-config/templates/ssh_config.j2 +++ b/install_files/ansible-base/roles/tails-config/templates/ssh_config.j2 @@ -1,23 +1,5 @@ -{% set svc_grep = "grep -Po '.{16}\.onion' svc-ssh-aths" %} {% set svc_awk = "awk -F ':' '{print $1 \".onion\"}' svc-ssh.auth_private" %} -{% if v2_onion_services and not v3_onion_services -%} -{% for svc in ssh_onion_lookup.results %} -Host {{ svc.item }} - {% set svc_grep = "grep -Po '.{16}\.onion' "+svc.item+"-ssh-aths" -%} - {% set direct_ip = hostvars[inventory_hostname][svc.item+'_ip'] -%} - User {{ ssh_users }} - Hostname {{ lookup('pipe', svc_grep) if (svc.stat.exists and enable_ssh_over_tor) else direct_ip }} - {% if enable_ssh_over_tor and svc.stat.exists -%} - ProxyCommand /bin/nc -X 5 -x 127.0.0.1:9050 %h %p - {% else -%} - ProxyCommand none - {% endif %} - -{% endfor %} -{% endif %} - -{% if v3_onion_services -%} {% for svc in ssh_v3_onion_lookup.results %} Host {{ svc.item }} {% set svc_awk = "awk -F ':' '{print $1 \".onion\"}' "+svc.item+"-ssh.auth_private" -%} @@ -31,20 +13,3 @@ Host {{ svc.item }} {% endif %} {% endfor %} -{% endif %} - -{% if v2_onion_services and v3_onion_services -%} -{% for svc in ssh_onion_lookup.results %} -Host {{ svc.item + "-legacy" }} - {% set svc_grep = "grep -Po '.{16}\.onion' "+svc.item+"-ssh-aths" -%} - {% set direct_ip = hostvars[inventory_hostname][svc.item+'_ip'] -%} - User {{ ssh_users }} - Hostname {{ lookup('pipe', svc_grep) if (svc.stat.exists and enable_ssh_over_tor) else direct_ip }} - {% if enable_ssh_over_tor and svc.stat.exists -%} - ProxyCommand /bin/nc -X 5 -x 127.0.0.1:9050 %h %p - {% else -%} - ProxyCommand none - {% endif %} - -{% endfor %} -{% endif %} diff --git a/install_files/ansible-base/roles/tor-hidden-services/defaults/main.yml b/install_files/ansible-base/roles/tor-hidden-services/defaults/main.yml index 47359a2292..132b257e5a 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/defaults/main.yml +++ b/install_files/ansible-base/roles/tor-hidden-services/defaults/main.yml @@ -3,9 +3,3 @@ tor_hidden_services_parent_dir: /var/lib/tor/services tor_user: debian-tor enable_ssh_over_tor: true sd_root_dir: "{{ lookup('pipe','git rev-parse --show-toplevel') }}" - -# v2 Tor onion services are on / v3 Tor onion services are off by default for backwards -# compatibility. Note that new install after 1.0 will have v3 enabled by sdconfig which -# will override these variables. -v2_onion_services: true -v3_onion_services: false diff --git a/install_files/ansible-base/roles/tor-hidden-services/tasks/check_tor_service_config_for_admins.yml b/install_files/ansible-base/roles/tor-hidden-services/tasks/check_tor_service_config_for_admins.yml deleted file mode 100644 index 28705e4c6d..0000000000 --- a/install_files/ansible-base/roles/tor-hidden-services/tasks/check_tor_service_config_for_admins.yml +++ /dev/null @@ -1,39 +0,0 @@ ---- -# The migration from Tor v2 -> v3 services requires Admins to opt-in -# via `securedrop-admin sdconfig`, then rerun the install action to enable -# v3 services. If a *different* Admin Workstation is subsequently used, -# without the corresponding sdconfig changes, we halt the play, otherwise -# the v3 client auth config will be clobbered, locking out the first Admin. - -- name: Check whether v3 services exist on server - stat: - path: "{{ tor_hidden_services_parent_dir }}/{{ item.service }}" - register: _v3_services_existence_check_result - with_items: "{{ tor_instances_v3 }}" - - # Returns a list of booleans, one boolean for each v3 service, denoting whether - # a config currently exists for that service. -- name: Store info about existing v3 service state - set_fact: - _v3_services_state_info: "{{ _v3_services_existence_check_result.results|map(attribute='stat')|map(attribute='exists')|list }}" - - # Fail if v3 service configs exist, but v3_onion_services is not enabled. - # If v3 service configs do not exist, but v3_onion_services is enabled, - # we're configuring the v3 services for the first time, so don't fail. -- name: Confirm service state matches declared config - assert: - that: > - not (not v3_onion_services and true in _v3_services_state_info) - msg: > - ERROR. The 'sdconfig' settings do not specify v3 onion services, - but v3 onion services were found on the server. If your SecureDrop - instance has multiple Administrators, contact the other Administrators - to request the Tor v3 onion service config information. You must copy - the 'tor_v3_keys.json' and '*.auth_private' files to this workstation, - then re-run the install action. - when: - # In staging, Monitor Server will have 0 (SSH-over-Tor disabled) - - tor_instances_v3|length > 0 - # Only run if we're connected over Tor (i.e. enabling v3 after v2). - # If we're not connected over Tor, this is a first-run. - - (ansible_host|default(ansible_host)).endswith('.onion') diff --git a/install_files/ansible-base/roles/tor-hidden-services/tasks/configure_tor_hidden_services.yml b/install_files/ansible-base/roles/tor-hidden-services/tasks/configure_tor_hidden_services.yml index 361656b02c..22e11b3df5 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/tasks/configure_tor_hidden_services.yml +++ b/install_files/ansible-base/roles/tor-hidden-services/tasks/configure_tor_hidden_services.yml @@ -17,8 +17,7 @@ group: "{{ tor_user }}" mode: "0700" with_flattened: - - "{{ tor_instances if v2_onion_services else [] }}" - - "{{ tor_instances_v3 if v3_onion_services else [] }}" + - "{{ tor_instances_v3 }}" tags: - tor @@ -31,8 +30,6 @@ mode: "0700" with_items: "{{ tor_instances_v3 }}" when: - - v3_onion_services - # Source Interface is always public, don't configure client auth - "'source' not in item.service" tags: - tor @@ -57,7 +54,6 @@ delegate_to: localhost # Local action, so we don't want elevated privileges become: no - when: "v3_onion_services" register: onion_v3_generation changed_when: "'onion service keys generated' in onion_v3_generation.stdout" tags: @@ -72,7 +68,6 @@ become: no # Suppress output since it contains Tor keys no_log: true - when: "v3_onion_services" tags: - tor - admin @@ -81,7 +76,6 @@ set_fact: tor_v3_ssh_pubkey: "{{ v3_local_key_info.app_ssh_public_key if 'securedrop_application_server' in group_names else v3_local_key_info.mon_ssh_public_key }}" when: - - v3_onion_services - "'sshv3' in tor_auth_instances_v3" - enable_ssh_over_tor tags: @@ -98,7 +92,6 @@ notify: - restart tor when: - - v3_onion_services - "'journalistv3' in tor_auth_instances_v3" tags: - tor @@ -114,7 +107,6 @@ notify: - restart tor when: - - v3_onion_services - "'sshv3' in tor_auth_instances_v3" - enable_ssh_over_tor tags: @@ -122,7 +114,6 @@ - name: Flush handlers to restart Tor. meta: flush_handlers - when: "v3_onion_services" tags: - tor @@ -130,6 +121,5 @@ service: name: tor state: started - when: "v3_onion_services" tags: - tor diff --git a/install_files/ansible-base/roles/tor-hidden-services/tasks/main.yml b/install_files/ansible-base/roles/tor-hidden-services/tasks/main.yml index baa1012094..3e24b6a0ff 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/tasks/main.yml +++ b/install_files/ansible-base/roles/tor-hidden-services/tasks/main.yml @@ -1,6 +1,4 @@ --- - include: install_tor.yml -- include: check_tor_service_config_for_admins.yml - - include: configure_tor_hidden_services.yml diff --git a/install_files/ansible-base/roles/tor-hidden-services/templates/torrc b/install_files/ansible-base/roles/tor-hidden-services/templates/torrc index a00a91d936..cf382df041 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/templates/torrc +++ b/install_files/ansible-base/roles/tor-hidden-services/templates/torrc @@ -2,29 +2,7 @@ SocksPort 0 SafeLogging 1 RunAsDaemon 1 -{% if 'securedrop_application_server' in group_names and v2_onion_services %} -HiddenServiceDir /var/lib/tor/services/source -HiddenServiceVersion 2 -HiddenServicePort 80 127.0.0.1:80 -{% if securedrop_app_https_on_source_interface|default(False) %} -HiddenServicePort 443 127.0.0.1:443 -{% endif %} - -HiddenServiceDir /var/lib/tor/services/journalist -HiddenServiceVersion 2 -HiddenServicePort 80 127.0.0.1:8080 -HiddenServiceAuthorizeClient stealth journalist -{% endif %} - -{% if enable_ssh_over_tor and v2_onion_services %} -HiddenServiceDir /var/lib/tor/services/ssh -HiddenServiceVersion 2 -HiddenServicePort 22 127.0.0.1:22 -HiddenServiceAuthorizeClient stealth admin -{% endif %} - - -{% if 'securedrop_application_server' in group_names and v3_onion_services %} +{% if 'securedrop_application_server' in group_names %} HiddenServiceDir /var/lib/tor/services/sourcev3 HiddenServicePort 80 127.0.0.1:80 @@ -36,7 +14,7 @@ HiddenServiceDir /var/lib/tor/services/journalistv3 HiddenServicePort 80 127.0.0.1:8080 {% endif %} -{% if enable_ssh_over_tor and v3_onion_services %} +{% if enable_ssh_over_tor %} HiddenServiceDir /var/lib/tor/services/sshv3 HiddenServicePort 22 127.0.0.1:22 {% endif %} diff --git a/install_files/ansible-base/roles/validate/tasks/validate_tails_environment.yml b/install_files/ansible-base/roles/validate/tasks/validate_tails_environment.yml index 04938e0993..d3de0bbcc3 100644 --- a/install_files/ansible-base/roles/validate/tasks/validate_tails_environment.yml +++ b/install_files/ansible-base/roles/validate/tasks/validate_tails_environment.yml @@ -33,10 +33,6 @@ to `~/Persistent/securedrop`. with_items: "{{ tails_persistence_check_result.results }}" -- name: Default v3_onion_services to false - set_fact: - v3_onion_services: "{{ v3_onion_services | default(False) }}" - - name: Check for v3 SSH auth files stat: path: "/home/amnesia/Persistent/securedrop/install_files/ansible-base/{{ item }}" @@ -68,7 +64,6 @@ file under `~/Persistent/securedrop/install_files/ansible-base/ and retry the install command. when: - - v3_onion_services - name: Confirm that the Journalist auth file is present assert: @@ -79,7 +74,6 @@ file under `~/Persistent/securedrop/install_files/ansible-base/ and retry the install command. when: - - v3_onion_services - enable_ssh_over_tor - v3_ssh_auth_file_count == "2" @@ -93,5 +87,4 @@ to an existing SecureDrop instance, please add this file under `~/Persistent/securedrop/install_files/ansible-base`. when: - - v3_onion_services - v3_journalist_auth_file.stat.exists diff --git a/install_files/ansible-base/securedrop-prod.yml b/install_files/ansible-base/securedrop-prod.yml index 53809c8688..706a28ab78 100755 --- a/install_files/ansible-base/securedrop-prod.yml +++ b/install_files/ansible-base/securedrop-prod.yml @@ -28,15 +28,6 @@ max_fail_percentage: 0 any_errors_fatal: yes pre_tasks: - - name: Verify that v2 onion services are not enabled on a Focal install - assert: - that: - - "v2_onion_services|bool != true" - fail_msg: >- - V2 services were enabled via ./securedrop-admin sdconfig, but are not - available on Focal. Please run sdconfig again, disabling v2 services. - when: ansible_distribution_release == 'focal' - - name: Check if install has been done before stat: path: /var/www/securedrop From ac1d150f75b7783ff8e52313a6a8e88d1f2032d3 Mon Sep 17 00:00:00 2001 From: Kevin O'Gorman Date: Fri, 23 Apr 2021 13:23:58 -0400 Subject: [PATCH 2/3] removed v2 auth token from staging facts --- .../roles/app-test/files/tor_app.fact | 28 +++++++++---------- .../tasks/extract_apptor_test_config.yml | 1 - 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/install_files/ansible-base/roles/app-test/files/tor_app.fact b/install_files/ansible-base/roles/app-test/files/tor_app.fact index b4818591b5..d457c83dee 100644 --- a/install_files/ansible-base/roles/app-test/files/tor_app.fact +++ b/install_files/ansible-base/roles/app-test/files/tor_app.fact @@ -8,8 +8,8 @@ import json import os TOR_SVC_PATH = "/var/lib/tor/services/" -JOURNALIST_DIR = "journalist" -SOURCE_DIR = "source" +JOURNALIST_DIR = "journalistv3" +SOURCE_DIR = "sourcev3" def extract_sd_onion_data(tor_path=TOR_SVC_PATH, @@ -17,27 +17,25 @@ def extract_sd_onion_data(tor_path=TOR_SVC_PATH, source_dir=SOURCE_DIR, protocol="http"): - for interface in [journalist_dir, source_dir]: + def get_int_addr(interface): hostname_file = os.path.join(TOR_SVC_PATH, interface, 'hostname') try: with open(hostname_file) as f: tor_config = f.readline().rstrip().split() - onion_addr = "{p}://{a}".format(p=protocol, a=tor_config[0]) - auth_token = tor_config[1] - - # This must be a source interface because we dont see hidservauth info - except IndexError: - source_int = onion_addr - # One of the files doesn't exist :| Maybe tor setup hasnt run yet. + return onion_addr + # The file doesn't exist :/ Maybe tor setup hasn't run yet. except IOError: - return dict() - else: - journalist_int = onion_addr + pass + + try: + journalist_int = get_int_addr(JOURNALIST_DIR) + source_int = get_int_addr(SOURCE_DIR) + except IOError: + return dict() return dict(journalist_location=journalist_int, - source_location=source_int, - hidserv_token=auth_token) + source_location=source_int) if __name__ == '__main__': diff --git a/install_files/ansible-base/roles/app-test/tasks/extract_apptor_test_config.yml b/install_files/ansible-base/roles/app-test/tasks/extract_apptor_test_config.yml index b99f7e9868..728af0ec10 100644 --- a/install_files/ansible-base/roles/app-test/tasks/extract_apptor_test_config.yml +++ b/install_files/ansible-base/roles/app-test/tasks/extract_apptor_test_config.yml @@ -21,7 +21,6 @@ - name: Gather apptest facts to dict to prepare for output set_fact: _tbb_selenium_dict: - hidserv_token: "{{ ansible_local.tor_app.hidserv_token }}" journalist_location: "{{ ansible_local.tor_app.journalist_location }}" source_location: "{{ ansible_local.tor_app.source_location }}" timeout: "{{ tbb_timeout }}" From 0e74ac2ecd28c47dfbc302a1fb8044263bf110ba Mon Sep 17 00:00:00 2001 From: Kevin O'Gorman Date: Sat, 24 Apr 2021 13:01:32 -0400 Subject: [PATCH 3/3] Updated testinfra tests and vars to remove v2 references --- .../ansible-base/securedrop-tails.yml | 2 +- molecule/testinfra/app/test_tor_config.py | 7 +--- .../testinfra/app/test_tor_hidden_services.py | 41 ++----------------- molecule/testinfra/vars/app-prod.yml | 12 ++---- molecule/testinfra/vars/app-qubes-staging.yml | 14 ------- molecule/testinfra/vars/app-staging.yml | 14 ------- molecule/testinfra/vars/mon-prod.yml | 6 +-- molecule/testinfra/vars/prod.yml | 14 ------- molecule/testinfra/vars/prodVM.yml | 14 ------- molecule/testinfra/vars/qubes-staging.yml | 14 ------- molecule/testinfra/vars/staging.yml | 14 ------- 11 files changed, 11 insertions(+), 141 deletions(-) diff --git a/install_files/ansible-base/securedrop-tails.yml b/install_files/ansible-base/securedrop-tails.yml index 818bcf4356..07909a939f 100755 --- a/install_files/ansible-base/securedrop-tails.yml +++ b/install_files/ansible-base/securedrop-tails.yml @@ -22,6 +22,6 @@ The Journalist Interface's Tor onion URL is: http://{{ journalist_iface.stdout }} The Source Interfaces's Tor onion URL is: http://{{ source_iface.stdout }} - {% if find_aths_info_result.matched > 1 %} + {% if find_v3_aths_info_result.matched > 1 %} SSH aliases are set up. You can use them with 'ssh app' and 'ssh mon'. {% endif %} diff --git a/molecule/testinfra/app/test_tor_config.py b/molecule/testinfra/app/test_tor_config.py index a3f769d476..9c0a57e3c4 100644 --- a/molecule/testinfra/app/test_tor_config.py +++ b/molecule/testinfra/app/test_tor_config.py @@ -64,14 +64,11 @@ def test_tor_torrc_sandbox(host): @pytest.mark.skip_in_prod -def test_tor_v2_onion_url_readable_by_app(host): +def test_tor_v2_onion_url_file_absent(host): v2_url_filepath = "/var/lib/securedrop/source_v2_url" with host.sudo(): f = host.file(v2_url_filepath) - assert f.is_file - assert f.user == "www-data" - assert f.mode == 0o644 - assert re.search(r"^[a-z0-9]{16}\.onion$", f.content_string) + assert not f.exists @pytest.mark.skip_in_prod diff --git a/molecule/testinfra/app/test_tor_hidden_services.py b/molecule/testinfra/app/test_tor_hidden_services.py index 1b74e59800..6a95288249 100644 --- a/molecule/testinfra/app/test_tor_hidden_services.py +++ b/molecule/testinfra/app/test_tor_hidden_services.py @@ -26,9 +26,8 @@ def test_tor_service_directories(host, tor_service): @pytest.mark.parametrize('tor_service', sdvars.tor_services) def test_tor_service_hostnames(host, tor_service): """ - Check contents of Tor service hostname file. For normal onion services, - the file should contain only hostname (.onion URL). For authenticated - onion services, it should also contain the HidServAuth cookie. + Check contents of Tor service hostname file. For v3 onion services, + the file should contain only hostname (.onion URL). """ # Declare regex only for THS; we'll build regex for ATHS only if # necessary, since we won't have the required values otherwise. @@ -46,22 +45,13 @@ def test_tor_service_hostnames(host, tor_service): # All hostnames should contain at *least* the hostname. assert re.search(ths_hostname_regex, f.content_string) - if tor_service['authenticated'] and tor_service['version'] == 2: - # HidServAuth regex is approximately [a-zA-Z0-9/+], but validating - # the entire entry is sane, and we don't need to nitpick the - # charset. - aths_hostname_regex = ths_hostname_regex + " .{22} # client: " + \ - tor_service['client'] - assert re.search("^{}$".format(aths_hostname_regex), f.content_string) - elif tor_service['authenticated'] and tor_service['version'] == 3: + if tor_service['authenticated'] and tor_service['version'] == 3: # For authenticated version 3 onion services, the authorized_client # directory will exist and contain a file called client.auth. client_auth = host.file( "/var/lib/tor/services/{}/authorized_clients/client.auth".format( tor_service['name'])) assert client_auth.is_file - elif tor_service['version'] == 2: - assert re.search("^{}$".format(ths_hostname_regex), f.content_string) else: assert re.search("^{}$".format(ths_hostname_regex_v3), f.content_string) @@ -75,12 +65,6 @@ def test_tor_services_config(host, tor_service): * HiddenServiceDir * HiddenServicePort - - Only v2 authenticated onion services must also include: - - * HiddenServiceAuthorizeClient - - Check for each as appropriate. """ f = host.file("/etc/tor/torrc") dir_regex = "HiddenServiceDir /var/lib/tor/services/{}".format( @@ -94,29 +78,12 @@ def test_tor_services_config(host, tor_service): except IndexError: local_port = remote_port - # Ensure that service is hardcoded to v2, for compatibility - # with newer versions of Tor, which default to v3. - if tor_service['version'] == 2: - version_string = "HiddenServiceVersion 2" - else: - version_string = "" - port_regex = "HiddenServicePort {} 127.0.0.1:{}".format( remote_port, local_port) assert f.contains("^{}$".format(dir_regex)) assert f.contains("^{}$".format(port_regex)) - if version_string: - service_regex = "\n".join([dir_regex, version_string, port_regex]) - else: - service_regex = "\n".join([dir_regex, port_regex]) - - if tor_service['authenticated'] and tor_service['version'] == 2: - auth_regex = "HiddenServiceAuthorizeClient stealth {}".format( - tor_service['client']) - assert f.contains("^{}$".format(auth_regex)) - service_regex += "\n{}".format(auth_regex) - # Check for block in file, to ensure declaration order + service_regex = "\n".join([dir_regex, port_regex]) assert service_regex in f.content_string diff --git a/molecule/testinfra/vars/app-prod.yml b/molecule/testinfra/vars/app-prod.yml index 9543eb97fb..f525a6e995 100644 --- a/molecule/testinfra/vars/app-prod.yml +++ b/molecule/testinfra/vars/app-prod.yml @@ -2,15 +2,9 @@ mon_ip: 10.0.1.5 tor_services: - - ssh - - source - - journalist - -tor_stealth_services: - - service: "HiddenServicePort 22 127.0.0.1:22" - stealth: admin - - service: "HiddenServicePort 80 127.0.0.1:8080" - stealth: journalist + - sshv3 + - sourcev3 + - journalistv3 app_directories: - /var/www/securedrop diff --git a/molecule/testinfra/vars/app-qubes-staging.yml b/molecule/testinfra/vars/app-qubes-staging.yml index 8e2a218e40..434e506704 100644 --- a/molecule/testinfra/vars/app-qubes-staging.yml +++ b/molecule/testinfra/vars/app-qubes-staging.yml @@ -40,20 +40,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80" diff --git a/molecule/testinfra/vars/app-staging.yml b/molecule/testinfra/vars/app-staging.yml index 39fafc5d7f..ee58e2a5f4 100644 --- a/molecule/testinfra/vars/app-staging.yml +++ b/molecule/testinfra/vars/app-staging.yml @@ -63,20 +63,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80" diff --git a/molecule/testinfra/vars/mon-prod.yml b/molecule/testinfra/vars/mon-prod.yml index 3228fa51df..76def8ca0a 100644 --- a/molecule/testinfra/vars/mon-prod.yml +++ b/molecule/testinfra/vars/mon-prod.yml @@ -7,11 +7,7 @@ app_hostname: app-prod app_ip: 10.0.1.4 tor_services: - - ssh - -tor_stealth_services: - - service: "HiddenServicePort 22 127.0.0.1:22" - stealth: admin + - sshv3 # Postfix should indeed be running on prod hosts, otherwise # OSSEC alerts cannot be delivered. It's disabled in staging. diff --git a/molecule/testinfra/vars/prod.yml b/molecule/testinfra/vars/prod.yml index 9ccd6fe5fe..79dc33ee60 100644 --- a/molecule/testinfra/vars/prod.yml +++ b/molecule/testinfra/vars/prod.yml @@ -63,20 +63,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80" diff --git a/molecule/testinfra/vars/prodVM.yml b/molecule/testinfra/vars/prodVM.yml index 660cee5936..3f0cff5751 100644 --- a/molecule/testinfra/vars/prodVM.yml +++ b/molecule/testinfra/vars/prodVM.yml @@ -62,20 +62,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80" diff --git a/molecule/testinfra/vars/qubes-staging.yml b/molecule/testinfra/vars/qubes-staging.yml index 4f681ea542..9c5f47aa04 100644 --- a/molecule/testinfra/vars/qubes-staging.yml +++ b/molecule/testinfra/vars/qubes-staging.yml @@ -64,20 +64,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80" diff --git a/molecule/testinfra/vars/staging.yml b/molecule/testinfra/vars/staging.yml index 6582a1042c..8dfe408e06 100644 --- a/molecule/testinfra/vars/staging.yml +++ b/molecule/testinfra/vars/staging.yml @@ -64,20 +64,6 @@ app_directories: - /var/lib/securedrop/tmp tor_services: - - name: source - ports: - - "80" - authenticated: no - version: 2 - - - name: journalist - ports: - - "80" - - "8080" - authenticated: yes - client: journalist - version: 2 - - name: journalistv3 ports: - "80"