Skip to content

Commit

Permalink
Audit, clean up, and annotate Apache configs
Browse files Browse the repository at this point in the history
Reviews the Apache virtual host configurations, makes a few changes for
clarity's sake, but mostly adds comments throughout. A few takeaways:

Removes custom ErrorDocument

These config lines were inactive. In order to activate them, we'd need
to set "WSGIErrorOverride On", which would cause non-200 HTTP status
codes to be handled by Apache directly. That can work, especially in the
case of 404, but it isn't really what we want: we already have a fairly
nice 404 handler inside the app. For a 500, that's almost certainly a
failure in the Flask app somewhere, so Apache will handle it anyway.

Removes redundant server blocks

It's important to restrict access to the root volume, which is required
because [0]:

    Note that the default access for <Directory "/"> is to permit all access.
    This means that Apache httpd will serve any file mapped from an URL.
    It is recommended that you change this with a block such as

We were still using the old-style access syntax, so updated that according
to the latest 2.4.x "require" statements, following guidance in [1].

Make Apache configs distro-specific

Out of an abundance of caution, I preserved the Xenial configs as
written, since we're approaching EOL for Xenial in a month or two.
The new changes will be Focal-specific.

[0] http://httpd.apache.org/docs/current/mod/core.html#directory
[1] https://httpd.apache.org/docs/2.4/howto/access.html
  • Loading branch information
Conor Schaefer authored and emkll committed Feb 18, 2021
1 parent 88ac049 commit 3544167
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 3 deletions.
4 changes: 2 additions & 2 deletions install_files/ansible-base/roles/app/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ apache_packages:

apache_templates:
- ports.conf
- sites-available/journalist.conf
- sites-available/source.conf
- sites-available/{{ ansible_distribution_release }}/journalist.conf
- sites-available/{{ ansible_distribution_release }}/source.conf

# Apache modules required for the SecureDrop application. Will be enabled.
apache_modules:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- name: Install apache packages.
apt:
pkg: "{{ apache_packages }}"
state: latest
state: present
update_cache: yes
cache_valid_time: 3600
tags:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
ServerName {{ securedrop_app_apache_listening_address }}
<VirtualHost {{ securedrop_app_apache_listening_address }}:8080>

# WSGI settings for Flask app for Source Interface
WSGIDaemonProcess journalist processes=2 threads=30 display-name=%{GROUP} python-path=/var/www/securedrop
WSGIScriptAlias / /var/www/journalist.wsgi process-group=journalist application-group=journalist
WSGIPassAuthorization On

# Tell the browser not to cache HTML responses in order to minimize the chance
# of the inadvertent release or retention of sensitive data. For more, see
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2.
Header set Cache-Control "no-store"

# Configure X-Sendfile for more efficient large file downloads.
# Modern versions of WSGI wrapper may make this obsolete, more
# research required.
XSendFile On
XSendFilePath /var/lib/securedrop/store/
XSendFilePath /var/lib/securedrop/tmp/

Header edit Set-Cookie ^(.*)$ $1;HttpOnly
Header always append X-Frame-Options: DENY
Header set Referrer-Policy "no-referrer"
Header set X-XSS-Protection: "1; mode=block"
Header set X-Content-Type-Options: nosniff
Header set X-Download-Options: noopen
Header set Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

# Limit the max submitted size of requests.
LimitRequestBody 524288000

# Set default to deny all access from all filepaths.
<Directory />
Options None
AllowOverride None
Require all denied
</Directory>

# Permit limited access specifically to the SecureDrop application directory.
<Directory /var/www/securedrop>
Options None
AllowOverride None
<Limit GET POST HEAD>
Require ip {{ securedrop_app_apache_allow_from }}
</Limit>
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
</Directory>

Alias /static /var/www/securedrop/static
<Directory /var/www/securedrop/static>
Require all granted
# Cache static resources for 1 hour
Header set Cache-Control "max-age=3600"
</Directory>

# Deny all non-HTTP traffic, as a precaution
RewriteEngine On
RewriteCond %{THE_REQUEST} !HTTP/1\.1$
RewriteRule .* - [F]

# Configure logging for Journalist Interface
ErrorLog /var/log/apache2/journalist-error.log
CustomLog /var/log/apache2/journalist-access.log combined
LogLevel info

</VirtualHost>
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
ServerName {{ securedrop_app_apache_listening_address }}
<VirtualHost {{ securedrop_app_apache_listening_address }}:80>
{% if securedrop_app_https_on_source_interface %}
# Optional HTTPS settings for Source Interface. Requires opt-in
# via 'securedrop-admin sdconfig', as well as an active certificate.
# If enabled, all HTTP connections will be redirected to HTTPS.
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

<VirtualHost 127.0.0.1:443>
# HTTPS config
SSLEngine on
SSLCertificateFile /var/lib/ssl/{{ securedrop_app_https_certificate_cert_src|basename }}
SSLCertificateKeyFile /var/lib/ssl/{{ securedrop_app_https_certificate_key_src|basename }}
SSLCertificateChainFile /var/lib/ssl/{{ securedrop_app_https_certificate_chain_src|basename }}

# Evaluate support for TLSv1.3 in Tor Browser for Onions, conservatively
# we'll continue to support TLSv1.2 for now.
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite {{ securedrop_app_https_ssl_ciphers|join(':') }}
SSLHonorCipherOrder on
SSLCompression off
{% endif %}

# WSGI settings for Flask app for Source Interface
WSGIDaemonProcess source processes=2 threads=30 display-name=%{GROUP} python-path=/var/www/securedrop
WSGIProcessGroup source
WSGIScriptAlias / /var/www/source.wsgi

# Tell the browser not to cache HTML responses in order to minimize the chance
# of the inadvertent release or retention of sensitive data. For more, see
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2.
Header set Cache-Control "no-store"

XSendFile Off

# Prevent cookies from being accessed from Javascript. XSS mitigation.
Header edit Set-Cookie ^(.*)$ $1;HttpOnly

# Don't allow SecureDrop to be framed. Clickjacking mitigation.
Header always append X-Frame-Options: DENY

Header set X-XSS-Protection: "1; mode=block"
Header set X-Content-Type-Options: nosniff

# Set a strict CSP; "default-src 'self'" prevents 3rd party subresources from
# loading and prevents inline script from executing.
Header set Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"
Header set X-Download-Options: noopen

Header unset Etag

# Limit the max submitted size of requests to help prevent DoS.
LimitRequestBody 524288000

# Set default to deny all access from all filepaths.
<Directory />
Options None
AllowOverride None
Require all denied
</Directory>

# Permit limited access specifically to the SecureDrop application directory.
<Directory /var/www/securedrop>
Options None
AllowOverride None
<Limit GET POST HEAD>
Require ip {{ securedrop_app_apache_allow_from }}
</Limit>
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
</Directory>

# Allow dropping txt files here for onion server validation
Alias /.well-known/pki-validation /var/www/securedrop/.well-known/pki-validation
<Directory /var/www/securedrop/.well-known/pki-validation>
Require all granted
</Directory>

Alias /static /var/www/securedrop/static
<Directory /var/www/securedrop/static>
Require all granted
# Cache static resources for 1 hour
Header set Cache-Control "max-age=3600"
</Directory>

# Deny all non-HTTP traffic, as a precaution
RewriteEngine On
RewriteCond %{THE_REQUEST} !HTTP/1\.1$
RewriteRule .* - [F]

ErrorLog {{ source_apache_log_location | default('/dev/null') }}
LogLevel {{ apache_logging_level | default('crit') }}

</VirtualHost>

0 comments on commit 3544167

Please sign in to comment.