From cf297217aa86f6398004d912b969f40808bd0793 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Wed, 29 May 2024 15:18:37 -0700 Subject: [PATCH 1/5] feat(sdconfig): prompt for "securedrop_app_pow_on_source_interface" --- admin/securedrop_admin/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/admin/securedrop_admin/__init__.py b/admin/securedrop_admin/__init__.py index 96e07db423..988f0eedb8 100755 --- a/admin/securedrop_admin/__init__.py +++ b/admin/securedrop_admin/__init__.py @@ -375,6 +375,15 @@ def __init__(self, args: argparse.Namespace) -> None: None, lambda config: True, ), + ( + "securedrop_app_pow_on_source_interface", + True, + bool, + "Whether Tor proof of work should be enabled on Source Interface", + SiteConfig.ValidateYesNo(), + lambda x: x.lower() == "yes", + lambda config: True, + ), ( "securedrop_app_https_on_source_interface", False, From a232a54e5f64f24432fd32a53592c5a8717a7396 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Wed, 29 May 2024 15:25:37 -0700 Subject: [PATCH 2/5] deploy(tor-hidden-services): set HiddenServicePoWDefensesEnabled for the Source Interface --- .../ansible-base/roles/tor-hidden-services/templates/torrc | 4 ++++ 1 file changed, 4 insertions(+) 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 cf382df041..529564429d 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/templates/torrc +++ b/install_files/ansible-base/roles/tor-hidden-services/templates/torrc @@ -6,6 +6,10 @@ RunAsDaemon 1 HiddenServiceDir /var/lib/tor/services/sourcev3 HiddenServicePort 80 127.0.0.1:80 +{% if securedrop_app_pow_on_source_interface|default(True) %} +HiddenServicePoWDefensesEnabled 1 +{% endif %} + {% if securedrop_app_https_on_source_interface|default(False) %} HiddenServicePort 443 127.0.0.1:443 {% endif %} From b253e1631ac2391a07aa81815a38c4ac2d0053a1 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Tue, 11 Jun 2024 16:07:35 -0700 Subject: [PATCH 3/5] chore(SiteConfig): clarify settings scoped to the Source Interface - https://github.com/freedomofpress/securedrop/pull/7175#discussion_r1628358093 - https://github.com/freedomofpress/securedrop/pull/7175#discussion_r1637008028 --- admin/securedrop_admin/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/admin/securedrop_admin/__init__.py b/admin/securedrop_admin/__init__.py index 988f0eedb8..be35b16a66 100755 --- a/admin/securedrop_admin/__init__.py +++ b/admin/securedrop_admin/__init__.py @@ -379,7 +379,8 @@ def __init__(self, args: argparse.Namespace) -> None: "securedrop_app_pow_on_source_interface", True, bool, - "Whether Tor proof of work should be enabled on Source Interface", + "Enable Tor's proof-of-work defense against denial-of-service attacks for the " + "Source Interface?", SiteConfig.ValidateYesNo(), lambda x: x.lower() == "yes", lambda config: True, @@ -388,7 +389,7 @@ def __init__(self, args: argparse.Namespace) -> None: "securedrop_app_https_on_source_interface", False, bool, - "Whether HTTPS should be enabled on " + "Source Interface (requires EV cert)", + "Enable HTTPS for the Source Interface (requires EV certificate)?", SiteConfig.ValidateYesNo(), lambda x: x.lower() == "yes", lambda config: True, From 1a66400331d2c66adc2462e681f8d168f0017ff0 Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Wed, 12 Jun 2024 09:38:54 -0700 Subject: [PATCH 4/5] test: test prompts and expected output for "securedrop_app_pow_on_source_interface" --- admin/tests/test_integration.py | 31 +++++++++++++++++++++++----- admin/tests/test_securedrop-admin.py | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/admin/tests/test_integration.py b/admin/tests/test_integration.py index 8df0322e58..618b547659 100644 --- a/admin/tests/test_integration.py +++ b/admin/tests/test_integration.py @@ -41,6 +41,7 @@ securedrop_app_https_certificate_chain_src: '' securedrop_app_https_certificate_key_src: '' securedrop_app_https_on_source_interface: false +securedrop_app_pow_on_source_interface: true securedrop_supported_locales: - de_DE - es_ES @@ -73,6 +74,7 @@ securedrop_app_https_certificate_chain_src: '' securedrop_app_https_certificate_key_src: '' securedrop_app_https_on_source_interface: false +securedrop_app_pow_on_source_interface: true securedrop_supported_locales: - de_DE - es_ES @@ -81,7 +83,7 @@ ssh_users: sd """ -HTTPS_OUTPUT = """app_hostname: app +HTTPS_OUTPUT_NO_POW = """app_hostname: app app_ip: 10.20.2.2 daily_reboot_time: 5 dns_server: @@ -105,6 +107,7 @@ securedrop_app_https_certificate_chain_src: ca.crt securedrop_app_https_certificate_key_src: key.asc securedrop_app_https_on_source_interface: true +securedrop_app_pow_on_source_interface: false securedrop_supported_locales: - de_DE - es_ES @@ -188,9 +191,16 @@ def verify_app_gpg_key_prompt(child): ) +def verify_tor_pow_prompt(child): + # We don't need child.expect()'s regex matching, but the prompt is too long + # to match on the whole thing. + child.expect_exact("Enable Tor's proof-of-work defense", timeout=2) + + def verify_https_prompt(child): - child.expect( - rb"Whether HTTPS should be enabled on Source Interface \(requires EV cert\)\:", timeout=2 + # We don't need child.expect()'s regex matching. + child.expect_exact( + "Enable HTTPS for the Source Interface (requires EV certificate)?:", timeout=2 ) @@ -312,6 +322,9 @@ def test_sdconfig_on_first_run(): child.sendline("") verify_app_gpg_key_prompt(child) child.sendline("\b" * 14 + "sd_admin_test.pub") + verify_tor_pow_prompt(child) + # Default answer is yes + child.sendline("") verify_https_prompt(child) # Default answer is no child.sendline("") @@ -375,7 +388,11 @@ def test_sdconfig_enable_journalist_alerts(): child.sendline("") verify_app_gpg_key_prompt(child) child.sendline("\b" * 14 + "sd_admin_test.pub") + verify_tor_pow_prompt(child) + # Default answer is yes + child.sendline("") verify_https_prompt(child) + child.sendline("") # Default answer is no child.sendline("") verify_app_gpg_fingerprint_prompt(child) @@ -422,7 +439,7 @@ def test_sdconfig_enable_journalist_alerts(): verify_install_has_valid_config() -def test_sdconfig_enable_https_on_source_interface(): +def test_sdconfig_enable_https_disable_pow_on_source_interface(): cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py") child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} sdconfig") verify_username_prompt(child) @@ -441,6 +458,10 @@ def test_sdconfig_enable_https_on_source_interface(): child.sendline("") verify_app_gpg_key_prompt(child) child.sendline("\b" * 14 + "sd_admin_test.pub") + verify_tor_pow_prompt(child) + # Default answer is yes + # We will press backspace thrice and type no + child.sendline("\b\b\bno") verify_https_prompt(child) # Default answer is no # We will press backspace twice and type yes @@ -490,7 +511,7 @@ def test_sdconfig_enable_https_on_source_interface(): os.path.join(SD_DIR, "install_files/ansible-base/group_vars/all/site-specific") ) as fobj: data = fobj.read() - assert data == HTTPS_OUTPUT + assert data == HTTPS_OUTPUT_NO_POW verify_install_has_valid_config() diff --git a/admin/tests/test_securedrop-admin.py b/admin/tests/test_securedrop-admin.py index 2689832c7f..5b55807c40 100644 --- a/admin/tests/test_securedrop-admin.py +++ b/admin/tests/test_securedrop-admin.py @@ -916,6 +916,7 @@ def auto_prompt(prompt, default, **kwargs): verify_prompt_monitor_hostname = verify_desc_consistency verify_prompt_dns_server = verify_desc_consistency + verify_prompt_securedrop_app_pow_on_source_interface = verify_prompt_boolean verify_prompt_securedrop_app_https_on_source_interface = verify_prompt_boolean verify_prompt_enable_ssh_over_tor = verify_prompt_boolean From 02a81f1421496deeea7be2d22eac99e59854747a Mon Sep 17 00:00:00 2001 From: Cory Francis Myers Date: Thu, 13 Jun 2024 08:58:47 -0700 Subject: [PATCH 5/5] fix: set HiddenServicePoWDefensesEnabled only on explicit securedrop_app_pow_on_source_interface=True Otherwise a "securedrop-admin install" without a prior "securedrop-admin sdconfig" will default to enabling this feature. Let's not surprise an administrator who likely intended to enforce the existing configuration. Co-authored-by: Kevin O'Gorman --- .../ansible-base/roles/tor-hidden-services/templates/torrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 529564429d..dfc89e33f6 100644 --- a/install_files/ansible-base/roles/tor-hidden-services/templates/torrc +++ b/install_files/ansible-base/roles/tor-hidden-services/templates/torrc @@ -6,7 +6,7 @@ RunAsDaemon 1 HiddenServiceDir /var/lib/tor/services/sourcev3 HiddenServicePort 80 127.0.0.1:80 -{% if securedrop_app_pow_on_source_interface|default(True) %} +{% if securedrop_app_pow_on_source_interface|default(False) %} HiddenServicePoWDefensesEnabled 1 {% endif %}