Changeset - 51c92f71fa0a
[Not reviewed]
0 8 0
Branko Majic (branko) - 3 years ago 2020-11-16 16:32:14
branko@majic.rs
MAR-170: Always enforce use of HTTPS in the web_server role:

- Dropped the default_enforce_https parameter.
- Updated tests.
- Updated release notes.
8 files changed with 31 insertions and 53 deletions:
0 comments (0 inline, 0 general)
docs/releasenotes.rst
Show inline comments
 
@@ -77,6 +77,9 @@ Breaking changes:
 
    dropped. This could introduce incompatibility with older clients
 
    trying to connect to the server.
 

	
 
  * Parameter ``default_enforce_https`` has been deprecated and
 
    removed. HTTPS is now mandatory in all cases.
 

	
 
* ``wsgi_website`` role
 

	
 
  * Parameters ``gunicorn_version`` and ``futures_version`` have been
docs/rolereference.rst
Show inline comments
 
@@ -1374,6 +1374,17 @@ The role implements the following:
 
  Python apps.
 
* Installs and configures PHP FPM as a common base for PHP apps.
 

	
 
The web server is configured as follows:
 

	
 
* No plaintext HTTP is allowed, HTTPS is mandatory. Clients connecting
 
  via plaintext HTTP are redirected to HTTPS.
 
* Clients are served with ``Strict-Transport-Security`` header with
 
  value of ``max-age=31536000; includeSubDomains``. This forces
 
  compliant clients to always connect using HTTPS to the web server
 
  when accessing its default domain, as well as any subdomains served
 
  by this web server or any other. The (client-side) cached header
 
  value expires after one year.
 

	
 

	
 
Role dependencies
 
~~~~~~~~~~~~~~~~~
 
@@ -1386,12 +1397,6 @@ Depends on the following roles:
 
Parameters
 
~~~~~~~~~~
 

	
 
**default_enforce_https** (boolean, optional, ``True``)
 
  Specify if HTTPS should be enforced for the default virtual host or not. If
 
  enforced, clients connecting via plaintext will be redirected to HTTPS, and
 
  clients will be served with ``Strict-Transport-Security`` header with value of
 
  ``max-age=31536000; includeSubDomains``.
 

	
 
**default_https_tls_certificate** (string, mandatory)
 
  X.509 certificate used for TLS for HTTPS service. The file will be stored in
 
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_https.pem``.
roles/web_server/defaults/main.yml
Show inline comments
 
---
 

	
 
default_enforce_https: true
 
web_default_title: "Welcome"
 
web_default_message: "You are attempting to access the web server using a wrong name or an IP address. Please check your URL."
 
web_server_tls_protocols:
roles/web_server/molecule/default/group_vars/parameters-optional.yml
Show inline comments
 
---
 

	
 
default_enforce_https: false
 
default_https_tls_certificate: "{{ lookup('file', 'tests/data/x509/server/{{ inventory_hostname }}_https.cert.pem') }}"
 
default_https_tls_key: "{{ lookup('file', 'tests/data/x509/server/{{ inventory_hostname }}_https.key.pem') }}"
 
web_default_title: "Optional Welcome"
roles/web_server/molecule/default/tests/test_default.py
Show inline comments
 
@@ -328,3 +328,20 @@ def test_tls_enabled(host):
 

	
 
    tls = host.run('wget -q -O - https://%s/', fqdn)
 
    assert tls.rc == 0
 

	
 

	
 
def test_https_enforcement(host):
 
    """
 
    Tests if HTTPS is being enforced.
 
    """
 

	
 
    https_enforcement = host.run('curl -I http://parameters-mandatory/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'HTTP/1.1 301 Moved Permanently' in https_enforcement.stdout
 
    assert 'Location: https://parameters-mandatory/' in https_enforcement.stdout
 

	
 
    https_enforcement = host.run('curl -I https://parameters-mandatory/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'Strict-Transport-Security: max-age=31536000; includeSubDomains' in https_enforcement.stdout
roles/web_server/molecule/default/tests/test_mandatory.py
Show inline comments
 
@@ -48,23 +48,6 @@ def test_tls_version_and_ciphers(host):
 
    assert tls_ciphers == expected_tls_ciphers
 

	
 

	
 
def test_https_enforcement(host):
 
    """
 
    Tests if HTTPS is being enforced.
 
    """
 

	
 
    https_enforcement = host.run('curl -I http://parameters-mandatory/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'HTTP/1.1 301 Moved Permanently' in https_enforcement.stdout
 
    assert 'Location: https://parameters-mandatory/' in https_enforcement.stdout
 

	
 
    https_enforcement = host.run('curl -I https://parameters-mandatory/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'Strict-Transport-Security: max-age=31536000; includeSubDomains' in https_enforcement.stdout
 

	
 

	
 
def test_default_vhost_index_page(host):
 
    """
 
    Tests content of default vhost index page.
roles/web_server/molecule/default/tests/test_optional.py
Show inline comments
 
@@ -51,24 +51,6 @@ def test_tls_version_and_ciphers(host):
 
    assert tls_ciphers == expected_tls_ciphers
 

	
 

	
 
def test_https_enforcement(host):
 
    """
 
    Tests if HTTPS is (not) being enforced.
 
    """
 

	
 
    https_enforcement = host.run('curl -I http://parameters-optional/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'HTTP/1.1 200 OK' in https_enforcement.stdout
 
    assert 'HTTP/1.1 301 Moved Permanently' not in https_enforcement.stdout
 
    assert 'Location: https://parameters-optional/' not in https_enforcement.stdout
 

	
 
    https_enforcement = host.run('curl -I https://parameters-optional/')
 

	
 
    assert https_enforcement.rc == 0
 
    assert 'Strict-Transport-Security' not in https_enforcement.stdout
 

	
 

	
 
def test_default_vhost_index_page(host):
 
    """
 
    Tests content of default vhost index page.
roles/web_server/templates/nginx-default.j2
Show inline comments
 
#
 
# Default server (vhost) configuration.
 
#
 
{% if default_enforce_https -%}
 
server {
 
    # HTTP (plaintext) configuration.
 
    listen 80 default_server;
 
@@ -14,25 +13,16 @@ server {
 
    return 301 https://$host$request_uri;
 
}
 

	
 
{% endif -%}
 
server {
 
{% if not default_enforce_https %}
 
    # HTTP (plaintext) configuration.
 
    listen 80 default_server;
 
    listen [::]:80 default_server;
 

	
 
{% endif %}
 
    # HTTPS (TLS) configuration.
 
    listen 443 ssl default_server;
 
    listen [::]:443 ssl default_server;
 
    ssl_certificate_key /etc/ssl/private/{{ ansible_fqdn }}_https.key;
 
    ssl_certificate /etc/ssl/certs/{{ ansible_fqdn }}_https.pem;
 

	
 
{% if default_enforce_https %}
 
    # Set-up HSTS header for preventing downgrades for users that visited the
 
    # site via HTTPS at least once.
 
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
 
{% endif %}
 

	
 
    # Set-up the serving of default page.
 
    root /var/www/default/;
0 comments (0 inline, 0 general)