Changeset - ddcc0a5f7312
[Not reviewed]
4 7 4
Branko Majic (branko) - 5 years ago 2020-07-26 22:35:29
branko@majic.rs
MAR-162: Make the default_https_tls_certificate and default_https_tls_key parameters mandatory:

- Dropped the defaults from web_server role.
- Updated group variables in role tests.
- Changed the key/certificate file extensions to be more descriptive.
- Updated role reference documentation.
- Updated usage instructions to include the mandatory parameters.
11 files changed with 19 insertions and 18 deletions:
0 comments (0 inline, 0 general)
docs/rolereference.rst
Show inline comments
 
@@ -1365,53 +1365,53 @@ The role implements the following:
 
  incoming connections.
 
* Configures firewall to allow incoming connections to the web server.
 
* Installs and configures virtualenv and virtualenvwrapper as a common base for
 
  Python apps.
 
* Installs and configures PHP FPM as a common base for PHP apps.
 

	
 

	
 
Role dependencies
 
~~~~~~~~~~~~~~~~~
 

	
 
Depends on the following roles:
 

	
 
* **common**
 

	
 

	
 
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, optional, ``{{ lookup('file', tls_certificate_dir + '/' + ansible_fqdn + '_https.pem') }}``)
 
**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``.
 

	
 
**default_https_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + ansible_fqdn + '_https.key') }}``)
 
**default_https_tls_key** (string, mandatory)
 
  Private key used for TLS for HTTPS service. The file will be stored in
 
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_https.key``.
 

	
 
**web_default_title** (string, optional, ``Welcome``)
 
  Title for the default web page shown to users (if no other vhosts were matched).
 

	
 
**web_default_message** (string, optional, ``You are attempting to access the web server using a wrong name or an IP address. Please check your URL.``)
 
  Message for the default web page shown to users (if no other vhosts were
 
  matched).
 

	
 
**web_server_tls_protocols** (list, optional, ``[ "TLSv1.2" ]``)
 
  List of TLS protocols the web server should support. Each value specified
 
  should be compatible with Nginx configuration option ``ssl_protocols``.
 

	
 
**web_server_tls_ciphers** (string, optional ``DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!MD5:!EXPORT``)
 
  TLS ciphers to enable on the web server. This should be an OpenSSL-compatible
 
  cipher specification. Value should be compatible with Nginx configuration
 
  option ``ssl_ciphers``. Default value allows only TLSv1.2 and strong PFS
 
  ciphers.
 

	
 

	
 
Distribution compatibility
 
~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
docs/usage.rst
Show inline comments
 
@@ -1200,58 +1200,62 @@ With all the above noted, let us finally move on to the next step.
 
Setting-up the web server
 
-------------------------
 

	
 
Finally we are moving on to the web server deployment, and we shell start
 
with... Well, erm, web server deployment! To be more precise, we will set-up
 
Nginx.
 

	
 
1. Update the playbook for web server to include the web server role.
 

	
 

	
 
    :file:`~/mysite/playbooks/web.yml`
 
    ::
 

	
 
      ---
 

	
 
      - hosts: web
 
        remote_user: ansible
 
        become: yes
 
        roles:
 
          - common
 
          - ldap_client
 
          - mail_forwarder
 
          - web_server
 

	
 
2. You know the drill, role configuration comes up next. Actually... The web
 
   server role parameters are all optional, and they default to some ok-ish
 
   values. But let us spicen up things a bit nevertheless. No configuration has
 
   been deployed before for the web server, so we will be creating a new file.
 
2. You know the drill, role configuration comes up next. No
 
   configuration has been deployed before for the web server, so we
 
   will be creating a new file. Only the TLS parameters are really
 
   necessary, but we'll spice things up a bit by setting custom title
 
   and message for default virtual host.
 

	
 
   :file:`~/mysite/group_vars/web.yml`
 
   ::
 

	
 
      ---
 

	
 
      default_https_tls_certificate: "{{ lookup('file', 'tls/www.example.com_https.pem') }}"
 
      default_https_tls_key: "{{ lookup('file', 'tls/www.example.com_https.key') }}"
 

	
 
      web_default_title: "Welcome to default page!"
 
      web_default_message: "Nothing to see here, move along..."
 

	
 
3. The only thing left now is to create the TLS private key/certificate pair
 
   that should be used for default virtual host.
 

	
 
   1. Create new template for ``certtool``:
 

	
 
      :file:`~/mysite/tls/www.example.com_https.cfg`
 
      ::
 

	
 
         organization = "Example Inc."
 
         country = SE
 
         cn = "Exampe Inc. Web Server"
 
         expiration_days = 365
 
         dns_name = "www.example.com"
 
         tls_www_server
 
         signing_key
 
         encryption_key
 

	
 
   2. Create the keys and certificates for default web server virtual host based
 
      on the template::
 

	
 
        certtool --sec-param normal --generate-privkey --outfile ~/mysite/tls/www.example.com_https.key
roles/web_server/defaults/main.yml
Show inline comments
 
---
 

	
 
default_enforce_https: true
 
default_https_tls_certificate: "{{ lookup('file', tls_certificate_dir + '/' + ansible_fqdn + '_https.pem') }}"
 
default_https_tls_key: "{{ lookup('file', tls_private_key_dir + '/' + ansible_fqdn + '_https.key') }}"
 
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:
 
  - "TLSv1.2"
 
web_server_tls_ciphers: "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:\
 
DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:\
 
ECDHE-RSA-AES256-SHA384:!aNULL:!MD5:!EXPORT"
 

	
 
# Internal parameters
 
php_fpm_package_name: "php-fpm"
 
php_fpm_service_name: "php7.0-fpm"
 
php_base_config_dir: "/etc/php/7.0"
roles/web_server/molecule/default/group_vars/parameters-mandatory.yml
Show inline comments
 
---
 

	
 
default_https_tls_certificate: "{{ lookup('file', 'tests/data/x509/{{ inventory_hostname }}_https.cert.pem') }}"
 
default_https_tls_key: "{{ lookup('file', 'tests/data/x509/{{ inventory_hostname }}_https.key.pem') }}"
 

	
 
# common
 
ca_certificates:
 
  testca: "{{ lookup('file', 'tests/data/x509/ca.cert.pem') }}"
 

	
 
# Common parameters (general, not role).
 
tls_certificate_dir: tests/data/x509/
 
tls_private_key_dir: tests/data/x509/
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/parameters-optional_https.cert.pem') }}"
 
default_https_tls_key: "{{ lookup('file', 'tests/data/x509/parameters-optional_https.key.pem') }}"
 
default_https_tls_certificate: "{{ lookup('file', 'tests/data/x509/{{ inventory_hostname }}_https.cert.pem') }}"
 
default_https_tls_key: "{{ lookup('file', 'tests/data/x509/{{ inventory_hostname }}_https.key.pem') }}"
 
web_default_title: "Optional Welcome"
 
web_default_message: "Welcome to parameters-optional, default virtual host."
 
web_server_tls_protocols:
 
  - TLSv1.1
 
  - TLSv1.2
 
web_server_tls_ciphers: "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:\
 
DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:\
 
ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:!aNULL:!MD5:!EXPORT"
 

	
 
# common
 
ca_certificates:
 
  testca: "{{ lookup('file', 'tests/data/x509/ca.cert.pem') }}"
roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.cert.pem
Show inline comments
 
file renamed from roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.pem to roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.cert.pem
roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.key.pem
Show inline comments
 
file renamed from roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.key to roles/web_server/molecule/default/tests/data/x509/parameters-mandatory-stretch64_https.key.pem
roles/web_server/molecule/default/tests/data/x509/parameters-optional-stretch64_https.cert.pem
Show inline comments
 
file renamed from roles/web_server/molecule/default/tests/data/x509/parameters-optional_https.cert.pem to roles/web_server/molecule/default/tests/data/x509/parameters-optional-stretch64_https.cert.pem
roles/web_server/molecule/default/tests/data/x509/parameters-optional-stretch64_https.key.pem
Show inline comments
 
file renamed from roles/web_server/molecule/default/tests/data/x509/parameters-optional_https.key.pem to roles/web_server/molecule/default/tests/data/x509/parameters-optional-stretch64_https.key.pem
roles/web_server/molecule/default/tests/test_mandatory.py
Show inline comments
 
import os
 

	
 
import testinfra.utils.ansible_runner
 

	
 

	
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
 
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-mandatory')
 

	
 

	
 
def test_nginx_tls_files(host):
 
    """
 
    Tests if TLS private key and certificate have been deployed correctly.
 
    """
 

	
 
    hostname = host.run('hostname').stdout.strip()
 

	
 
    with host.sudo():
 

	
 
        tls_file = host.file('/etc/ssl/private/%s_https.key' % hostname)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o640
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.key" % hostname, "r").read().rstrip()
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.key.pem" % hostname, "r").read().rstrip()
 

	
 
        tls_file = host.file('/etc/ssl/certs/%s_https.pem' % hostname)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o644
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.pem" % hostname, "r").read().rstrip()
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.cert.pem" % hostname, "r").read().rstrip()
 

	
 

	
 
def test_certificate_validity_check_configuration(host):
 
    """
 
    Tests if certificate validity check configuration file has been deployed
 
    correctly.
 
    """
 

	
 
    hostname = host.run('hostname').stdout.strip()
 

	
 
    config = host.file('/etc/check_certificate/%s_https.conf' % hostname)
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 
    assert config.content_string == "/etc/ssl/certs/%s_https.pem" % hostname
 

	
 

	
 
def test_tls_configuration(host):
 
    """
 
    Tests if the TLS has been configured correctly and works.
 
    """
 

	
 
    tls = host.run('wget -q -O - https://parameters-mandatory/')
roles/web_server/molecule/default/tests/test_optional.py
Show inline comments
 
import os
 

	
 
import testinfra.utils.ansible_runner
 

	
 

	
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
 
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-optional')
 

	
 

	
 
def test_nginx_tls_files(host):
 
    """
 
    Tests if TLS private key and certificate have been deployed correctly.
 
    """
 

	
 
    hostname = host.run('hostname').stdout.strip()
 

	
 
    with host.sudo():
 

	
 
        tls_file = host.file('/etc/ssl/private/%s_https.key' % hostname)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o640
 
        assert tls_file.content_string == open("tests/data/x509/parameters-optional_https.key.pem", "r").read().rstrip()
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.key.pem" % hostname, "r").read().rstrip()
 

	
 
        tls_file = host.file('/etc/ssl/certs/%s_https.pem' % hostname)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o644
 
        assert tls_file.content_string == open("tests/data/x509/parameters-optional_https.cert.pem", "r").read().rstrip()
 
        assert tls_file.content_string == open("tests/data/x509/%s_https.cert.pem" % hostname, "r").read().rstrip()
 

	
 

	
 
def test_certificate_validity_check_configuration(host):
 
    """
 
    Tests if certificate validity check configuration file has been deployed
 
    correctly.
 
    """
 

	
 
    hostname = host.run('hostname').stdout.strip()
 

	
 
    config = host.file('/etc/check_certificate/%s_https.conf' % hostname)
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 
    assert config.content_string == "/etc/ssl/certs/%s_https.pem" % hostname
 

	
 

	
 
def test_tls_configuration(host):
 
    """
 
    Tests if the TLS has been configured correctly and works.
 
    """
 

	
 
    tls = host.run('wget -q -O - https://parameters-optional/')
0 comments (0 inline, 0 general)