Skip to content

Commit

Permalink
added additional tests to prod run, added prod VM vars
Browse files Browse the repository at this point in the history
  • Loading branch information
zenmonkeykstop committed Jul 31, 2020
1 parent b2d2dfd commit add8e6e
Show file tree
Hide file tree
Showing 28 changed files with 341 additions and 77 deletions.
3 changes: 2 additions & 1 deletion devops/scripts/run_prod_testinfra
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ fi

cd ~/Persistent/securedrop
source admin/.venv3/bin/activate
echo "Installing test dependencies, this may take a while..."
torify python3 -m pip install --quiet --no-deps --require-hashes -r securedrop/requirements/python3/develop-requirements.txt

cd molecule/testinfra
CI_SD_ENV=prod SECUREDROP_TESTINFRA_TARGET_HOST=prod py.test -n 2 --disable-warnings -m "run_in_prod"
CI_SD_ENV=${TEST_ENV:-prod} SECUREDROP_TESTINFRA_TARGET_HOST=${TEST_ENV:-prod} py.test -v -n 4 --disable-warnings -m "not skip_in_prod"

deactivate
echo "--------"
Expand Down
3 changes: 0 additions & 3 deletions molecule/testinfra/app-code/test_haveged.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
def test_haveged_config(host):
"""
Ensure haveged's low entrop watermark is sufficiently high.
Expand All @@ -17,7 +16,6 @@ def test_haveged_config(host):
assert f.contains('^DAEMON_ARGS="-w 2400"$')


@pytest.mark.run_in_prod
def test_haveged_no_duplicate_lines(host):
"""
Regression test to check for duplicate entries. Earlier playbooks
Expand All @@ -30,7 +28,6 @@ def test_haveged_no_duplicate_lines(host):
assert c.stdout == ""


@pytest.mark.run_in_prod
def test_haveged_is_running(host):
"""
Ensure haveged service is running, to provide additional entropy.
Expand Down
5 changes: 2 additions & 3 deletions molecule/testinfra/app-code/test_securedrop_app_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
testinfra_hosts = [securedrop_test_vars.app_hostname]


@pytest.mark.run_in_prod
def test_apache_default_docroot_is_absent(host):
"""
Ensure that the default docroot for Apache, containing static HTML
Expand All @@ -15,7 +14,6 @@ def test_apache_default_docroot_is_absent(host):
assert not host.file('/var/www/html').exists


@pytest.mark.run_in_prod
@pytest.mark.parametrize('package', [
'apache2',
'apparmor-utils',
Expand All @@ -40,6 +38,7 @@ def test_securedrop_application_apt_dependencies(host, package):
assert host.package(package).is_installed


@pytest.mark.skip_in_prod
def test_securedrop_application_test_locale(host):
"""
Ensure both SecureDrop DEFAULT_LOCALE and SUPPORTED_LOCALES are present.
Expand All @@ -54,6 +53,7 @@ def test_securedrop_application_test_locale(host):
assert "\nSUPPORTED_LOCALES = ['el', 'ar', 'en_US']\n" in securedrop_config.content_string


@pytest.mark.skip_in_prod
def test_securedrop_application_test_journalist_key(host):
"""
Ensure the SecureDrop Application GPG public key file is present.
Expand Down Expand Up @@ -85,7 +85,6 @@ def test_securedrop_application_test_journalist_key(host):
"^JOURNALIST_KEY = '65A1B5FF195B56353CC63DFFCC40EF1228271441'$")


@pytest.mark.run_in_prod
def test_securedrop_application_sqlite_db(host):
"""
Ensure sqlite database exists for application. The database file should be
Expand Down
1 change: 0 additions & 1 deletion molecule/testinfra/app-code/test_securedrop_rqrequeue.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
def test_securedrop_rqrequeue_service(host):
"""
Verify configuration of securedrop_rqrequeue systemd service.
Expand Down
1 change: 0 additions & 1 deletion molecule/testinfra/app-code/test_securedrop_rqworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
def test_securedrop_rqworker_service(host):
"""
Verify configuration of securedrop_rqworker systemd service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
def test_securedrop_shredder_service(host):
"""
Verify configuration of securedrop_shredder systemd service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
def test_securedrop_source_deleter_service(host):
"""
Verify configuration of securedrop_source_deleter systemd service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'Header set Referrer-Policy "no-referrer"',
]


# Test is not DRY; haven't figured out how to parametrize on
# multiple inputs, so explicitly redeclaring test logic.
@pytest.mark.parametrize("header", wanted_apache_headers)
Expand Down
44 changes: 44 additions & 0 deletions molecule/testinfra/app/iptables-app-prodVM.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
*filter
:INPUT DROP
:FORWARD DROP
:OUTPUT DROP
:LOGNDROP -
-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -m comment --comment "Allow traffic back for tor" -j ACCEPT
-A INPUT -i lo -p tcp -m tcp --dport 80 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "Allow tor connection from local loopback to connect to source int" -j ACCEPT
-A INPUT -i lo -p tcp -m tcp --dport 8080 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "Allow tor connection from local loopback to connect to journalist int" -j ACCEPT
-A INPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -i lo -p tcp -m state --state RELATED,ESTABLISHED -m comment --comment "for redis worker all application user local loopback user" -j ACCEPT
{% for address in dns_server -%}
-A INPUT -s {{ address }}/32 -p tcp -m tcp --sport 53 -m state --state RELATED,ESTABLISHED -m comment --comment "tcp/udp dns" -j ACCEPT
-A INPUT -s {{ address }}/32 -p udp -m udp --sport 53 -m state --state RELATED,ESTABLISHED -m comment --comment "tcp/udp dns" -j ACCEPT
{% endfor -%}
-A INPUT -p udp -m udp --sport 123 --dport 123 -m state --state RELATED,ESTABLISHED -m comment --comment ntp -j ACCEPT
-A INPUT -p tcp -m multiport --sports 80,8080,443 -m state --state RELATED,ESTABLISHED -m comment --comment "apt updates" -j ACCEPT
-A INPUT -s {{ mon_ip }}/32 -p udp -m udp --sport 1514 -m state --state RELATED,ESTABLISHED -m comment --comment "OSSEC server agent" -j ACCEPT
-A INPUT -s {{ mon_ip }}/32 -p tcp -m tcp --dport 22 -m comment --comment "Block explicitly SSH from the adjacent SD component" -j DROP
-A INPUT -s 10.0.1.0/24 -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m limit --limit 3/min --limit-burst 3 -m comment --comment "Rate limit incoming ssh traffic" -j ACCEPT
-A INPUT -s 10.0.1.0/24 -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -m comment --comment "Allow lo to lo traffic all protocols" -j ACCEPT
-A INPUT -p tcp -m state --state INVALID -m comment --comment "drop but do not log inbound invalid state packets" -j DROP
-A INPUT -m comment --comment "Drop and log all other incoming traffic" -j LOGNDROP
-A OUTPUT -p tcp -m owner --uid-owner {{ tor_user_id }} -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "Allow tor outbound" -j ACCEPT
-A OUTPUT -m owner --uid-owner {{ tor_user_id }} -m comment --comment "Drop all other traffic for tor" -j LOGNDROP
-A OUTPUT -o lo -p tcp -m tcp --sport 80 -m owner --uid-owner {{ securedrop_user_id }} -m state --state RELATED,ESTABLISHED -m comment --comment "Restrict the apache user outbound connections" -j ACCEPT
-A OUTPUT -o lo -p tcp -m tcp --sport 8080 -m owner --uid-owner {{ securedrop_user_id }} -m state --state RELATED,ESTABLISHED -m comment --comment "Restrict the apache user outbound connections" -j ACCEPT
-A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -o lo -p tcp -m owner --uid-owner {{ securedrop_user_id }} -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "for redis worker all application user local loopback user" -j ACCEPT
-A OUTPUT -m owner --uid-owner {{ securedrop_user_id }} -m comment --comment "Drop all other traffic by the securedrop user" -j LOGNDROP
-A OUTPUT -m owner --gid-owner {{ ssh_group_gid }} -m comment --comment "Drop all other outbound traffic for ssh user" -j LOGNDROP
{% for address in dns_server -%}
-A OUTPUT -d {{ address }}/32 -p tcp -m tcp --dport 53 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "tcp/udp dns" -j ACCEPT
-A OUTPUT -d {{ address }}/32 -p udp -m udp --dport 53 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "tcp/udp dns" -j ACCEPT
{% endfor -%}
-A OUTPUT -p udp -m udp --sport 123 --dport 123 -m owner --uid-owner 0 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment ntp -j ACCEPT
-A OUTPUT -p tcp -m multiport --dports 80,8080,443 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "apt updates" -j ACCEPT
-A OUTPUT -d {{ mon_ip }}/32 -p udp -m udp --dport 1514 -m state --state NEW,RELATED,ESTABLISHED -m comment --comment "OSSEC server agent" -j ACCEPT
-A OUTPUT -o eth1 -p tcp -m owner --uid-owner 0 -m tcp --sport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -o lo -m comment --comment "Allow lo to lo traffic all protocols" -j ACCEPT
-A OUTPUT -m comment --comment "Drop all other outgoing traffic" -j DROP
-A LOGNDROP -p tcp -m limit --limit 5/min -j LOG --log-tcp-options --log-ip-options --log-uid
-A LOGNDROP -p udp -m limit --limit 5/min -j LOG --log-ip-options --log-uid
-A LOGNDROP -p icmp -m limit --limit 5/min -j LOG --log-ip-options --log-uid
-A LOGNDROP -j DROP
COMMIT
1 change: 0 additions & 1 deletion molecule/testinfra/app/test_app_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
testinfra_hosts = [securedrop_test_vars.app_hostname]


@pytest.mark.run_in_prod
def test_app_iptables_rules(host):

# Build a dict of variables to pass to jinja for iptables comparison
Expand Down
13 changes: 0 additions & 13 deletions molecule/testinfra/app/test_apparmor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
testinfra_hosts = [sdvars.app_hostname]


@pytest.mark.run_in_prod
@pytest.mark.parametrize('pkg', ['apparmor', 'apparmor-utils'])
def test_apparmor_pkg(host, pkg):
""" Apparmor package dependencies """
assert host.package(pkg).is_installed


@pytest.mark.run_in_prod
def test_apparmor_enabled(host):
""" Check that apparmor is enabled """
with host.sudo():
Expand All @@ -27,7 +25,6 @@ def test_apparmor_enabled(host):
]


@pytest.mark.run_in_prod
@pytest.mark.parametrize('cap', apache2_capabilities)
def test_apparmor_apache_capabilities(host, cap):
""" check for exact list of expected app-armor capabilities for apache2 """
Expand All @@ -37,7 +34,6 @@ def test_apparmor_apache_capabilities(host, cap):
assert cap in c.stdout


@pytest.mark.run_in_prod
def test_apparmor_apache_exact_capabilities(host):
""" ensure no extra capabilities are defined for apache2 """
c = host.check_output("grep -ic capability /etc/apparmor.d/usr.sbin.apache2")
Expand All @@ -47,23 +43,20 @@ def test_apparmor_apache_exact_capabilities(host):
tor_capabilities = ['setgid']


@pytest.mark.run_in_prod
@pytest.mark.parametrize('cap', tor_capabilities)
def test_apparmor_tor_capabilities(host, cap):
""" check for exact list of expected app-armor capabilities for tor """
c = host.run(r"perl -nE '/^\s+capability\s+(\w+),$/ && say $1' /etc/apparmor.d/usr.sbin.tor")
assert cap in c.stdout


@pytest.mark.run_in_prod
def test_apparmor_tor_exact_capabilities(host):
""" ensure no extra capabilities are defined for tor """
c = host.check_output("grep -ic capability "
"/etc/apparmor.d/usr.sbin.tor")
assert str(len(tor_capabilities)) == c


@pytest.mark.run_in_prod
@pytest.mark.parametrize('profile', [
'ntpd',
'apache2',
Expand All @@ -81,7 +74,6 @@ def test_apparmor_ensure_not_disabled(host, profile):
assert not f.exists


@pytest.mark.run_in_prod
@pytest.mark.parametrize('complain_pkg', sdvars.apparmor_complain)
def test_app_apparmor_complain(host, complain_pkg):
""" Ensure app-armor profiles are in complain mode for staging """
Expand All @@ -92,15 +84,13 @@ def test_app_apparmor_complain(host, complain_pkg):
assert complain_pkg in c


@pytest.mark.run_in_prod
def test_app_apparmor_complain_count(host):
""" Ensure right number of app-armor profiles are in complain mode """
with host.sudo():
c = host.check_output("aa-status --complaining")
assert c == str(len(sdvars.apparmor_complain))


@pytest.mark.run_in_prod
@pytest.mark.parametrize('aa_enforced', sdvars.apparmor_enforce)
def test_apparmor_enforced(host, aa_enforced):
awk = ("awk '/[0-9]+ profiles.*enforce./"
Expand All @@ -110,7 +100,6 @@ def test_apparmor_enforced(host, aa_enforced):
assert aa_enforced in c


@pytest.mark.run_in_prod
def test_apparmor_total_profiles(host):
""" Ensure number of total profiles is sum of enforced and
complaining profiles """
Expand All @@ -122,7 +111,6 @@ def test_apparmor_total_profiles(host):
assert host.check_output("aa-status --profiled") >= total_expected


@pytest.mark.run_in_prod
def test_aastatus_unconfined(host):
""" Ensure that there are no processes that are unconfined but have
a profile """
Expand All @@ -137,7 +125,6 @@ def test_aastatus_unconfined(host):
assert unconfined_chk in aa_status_output


@pytest.mark.run_in_prod
def test_aa_no_denies_in_syslog(host):
""" Ensure that there are no apparmor denials in syslog """
with host.sudo():
Expand Down
2 changes: 2 additions & 0 deletions molecule/testinfra/app/test_appenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def test_app_pip_deps(host, exp_pip_pkg):
assert pip[exp_pip_pkg['name']]['version'] == exp_pip_pkg['version']


@pytest.mark.skip_in_prod
def test_app_wsgi(host):
""" ensure logging is enabled for source interface in staging """
f = host.file("/var/www/source.wsgi")
Expand Down Expand Up @@ -53,6 +54,7 @@ def test_supervisor_not_installed(host):
assert host.package("supervisor").is_installed is False


@pytest.mark.skip_in_prod
def test_gpg_key_in_keyring(host):
""" ensure test gpg key is present in app keyring """
with host.sudo(sdvars.securedrop_user):
Expand Down
2 changes: 2 additions & 0 deletions molecule/testinfra/app/test_tor_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def test_tor_torrc_sandbox(host):
assert not f.contains("^.*Sandbox.*$")


@pytest.mark.skip_in_prod
def test_tor_v2_onion_url_readable_by_app(host):
v2_url_filepath = "/var/lib/securedrop/source_v2_url"
with host.sudo():
Expand All @@ -71,6 +72,7 @@ def test_tor_v2_onion_url_readable_by_app(host):
assert re.search(r"^[a-z0-9]{16}\.onion$", f.content_string)


@pytest.mark.skip_in_prod
def test_tor_v3_onion_url_readable_by_app(host):
v3_url_filepath = "/var/lib/securedrop/source_v3_url"
with host.sudo():
Expand Down
6 changes: 5 additions & 1 deletion molecule/testinfra/app/test_tor_hidden_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
sdvars = pytest.securedrop_test_vars
testinfra_hosts = [sdvars.app_hostname]


# Prod Tor services may have unexpected configs
# TODO: read from admin workstation site-specific file if available
@pytest.mark.skip_in_prod
@pytest.mark.parametrize('tor_service', sdvars.tor_services)
def test_tor_service_directories(host, tor_service):
"""
Expand All @@ -19,6 +21,7 @@ def test_tor_service_directories(host, tor_service):
assert f.group == "debian-tor"


@pytest.mark.skip_in_prod
@pytest.mark.parametrize('tor_service', sdvars.tor_services)
def test_tor_service_hostnames(host, tor_service):
"""
Expand Down Expand Up @@ -62,6 +65,7 @@ def test_tor_service_hostnames(host, tor_service):
assert re.search("^{}$".format(ths_hostname_regex_v3), f.content_string)


@pytest.mark.skip_in_prod
@pytest.mark.parametrize('tor_service', sdvars.tor_services)
def test_tor_services_config(host, tor_service):
"""
Expand Down
Loading

0 comments on commit add8e6e

Please sign in to comment.