import os import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-*') def test_installed_packages(host, php_info): """ Tests if the required packages have been installed. """ assert host.package('nginx').is_installed assert host.package('python3-setuptools').is_installed assert host.package('virtualenv').is_installed assert host.package('virtualenvwrapper').is_installed assert host.package(php_info.fpm_package).is_installed def test_nginx_user(host): """ Tests if Nginx user has been set-up correctly to traverse TLS directories. """ assert 'ssl-cert' in host.user('www-data').groups def test_default_tls_configuration_removed(host): """ Tests if TLS configuration has been removed from the main (default) configuration file. """ assert 'ssl_protocols' not in host.file('/etc/nginx/nginx.conf').content_string def test_nginx_configuration_verification_script(host): """ Tests if script used for verifying Nginx configuration is deployed correctly. """ script = host.file('/usr/local/bin/nginx_verify_site.sh') assert script.is_file assert script.user == 'root' assert script.group == 'root' assert script.mode == 0o755 def test_tls_configuration_file(host): """ Tests permissions of TLS configuration file. """ config = host.file('/etc/nginx/conf.d/tls.conf') assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 def test_default_vhost_file(host): """ Tests permissions of default vhost configuration file. """ config = host.file('/etc/nginx/sites-available/default') assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o640 def test_default_website_enabled(host): """ Tests if default website has been enabled. """ config = host.file('/etc/nginx/sites-enabled/default') assert config.is_symlink assert config.linked_to == '/etc/nginx/sites-available/default' def test_firewall_configuration_file(host): """ Tests if firewall configuration file has been deployed correctly. """ with host.sudo(): config = host.file('/etc/ferm/conf.d/30-web.conf') assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o640 def test_default_debian_index_removed(host): """ Tests if default HTML pages provided by debian are removed. """ with host.sudo(): assert not host.file('/var/www/html').exists def test_default_vhost_root_directory(host): """ Tests if the default vhost root directory exists. """ directory = host.file('/var/www/default') assert directory.is_directory assert directory.user == 'root' assert directory.group == 'www-data' assert directory.mode == 0o750 def test_default_vhost_index_page_file(host): """ Tests permissions of default vhost index page. """ with host.sudo(): page = host.file('/var/www/default/index.html') assert page.is_file assert page.user == 'root' assert page.group == 'www-data' assert page.mode == 0o640 def test_services(host, php_info): """ Tests if services are enabled at boot and running. """ service = host.service('nginx') assert service.is_enabled assert service.is_running service = host.service(php_info.fpm_service) assert service.is_enabled assert service.is_running def test_sockets(host): """ Tests if web server is listening on correct ports. """ assert host.socket("tcp://80").is_listening assert host.socket("tcp://443").is_listening def test_wsgi_socket_directory(host): """ Tests if directory containing socket for WSGI applications has been created correctly. """ socket_directory = "/run/wsgi" tmpfiles_d_path = "/etc/tmpfiles.d/wsgi.conf" tmpfiles_d_content = "d /run/wsgi/ 0750 root www-data - -" directory = host.file(socket_directory) assert directory.is_directory assert directory.user == 'root' assert directory.group == 'www-data' assert directory.mode == 0o750 config = host.file(tmpfiles_d_path) assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 assert config.content_string == tmpfiles_d_content def test_php_fpm_socket_directory(host, php_info): """ Tests if directory containing socket for WSGI applications has been created correctly. """ socket_directory = "/run/php" tmpfiles_d_path = "/etc/tmpfiles.d/%s.conf" % php_info.fpm_service tmpfiles_d_content = "d /run/php/ 0750 root www-data - -" directory = host.file(socket_directory) assert directory.is_directory assert directory.user == 'root' assert directory.group == 'www-data' assert directory.mode == 0o750 config = host.file(tmpfiles_d_path) assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 assert config.content_string == tmpfiles_d_content def test_php_fpm_service_overrides(host, php_info): """ Tests if overrides for PHP-FPM service are deployed correctly. """ directory = host.file('/etc/systemd/system/%s.service.d' % php_info.fpm_service) assert directory.is_directory assert directory.user == 'root' assert directory.group == 'root' assert directory.mode == 0o755 config = host.file('/etc/systemd/system/%s.service.d/umask.conf' % php_info.fpm_service) assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 def test_php_timezone_configuration(host, php_info): """ Tests if PHP timezone configuration has been set correctly. """ server_timezone = host.file("/etc/timezone").content_string.strip() config = host.file('%s/cli/conf.d/30-timezone.ini' % php_info.base_config_dir) assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 config = host.file('%s/fpm/conf.d/30-timezone.ini' % php_info.base_config_dir) assert config.is_file assert config.user == 'root' assert config.group == 'root' assert config.mode == 0o644 timezone = host.run("php --php-ini %s -r %s", "%s/cli/php.ini" % php_info.base_config_dir, "echo ini_get('date.timezone');") assert timezone.rc == 0 assert timezone.stdout == server_timezone timezone = host.run("php --php-ini %s -r %s", "%s/fpm/php.ini" % php_info.base_config_dir, "echo ini_get('date.timezone');") assert timezone.rc == 0 assert timezone.stdout == server_timezone def test_https_server_dh_parameters_file(host): """ Tests if the Diffie-Hellman parameter file has been generated correctly. """ hostname = host.run('hostname').stdout.strip() dhparam_file_path = '/etc/ssl/private/%s_https.dh.pem' % hostname with host.sudo(): dhparam_file = host.file(dhparam_file_path) assert dhparam_file.is_file assert dhparam_file.user == 'root' assert dhparam_file.group == 'root' assert dhparam_file.mode == 0o640 dhparam_info = host.run("openssl dhparam -noout -text -in %s", dhparam_file_path) assert "DH Parameters: (2048 bit)" in dhparam_info.stdout def test_https_server_uses_correct_dh_parameters(host): """ Tests if the HTTP server uses the generated Diffie-Hellman parameter. """ hostname = host.run('hostname').stdout.strip() with host.sudo(): expected_dhparam = host.file('/etc/ssl/private/%s_https.dh.pem' % hostname).content_string.rstrip() connection = host.run("gnutls-cli --no-ca-verification --starttls-proto=https --port 443 " "--priority 'NONE:+VERS-TLS1.2:+CTYPE-X509:+COMP-NULL:+SIGN-RSA-SHA384:+DHE-RSA:+SHA384:+AEAD:+AES-256-GCM' --verbose localhost") output = connection.stdout begin_marker = "-----BEGIN DH PARAMETERS-----" end_marker = "-----END DH PARAMETERS-----" used_dhparam = output[output.find(begin_marker):output.find(end_marker) + len(end_marker)] assert used_dhparam == expected_dhparam 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/server/%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/server/%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_enabled(host): """ Tests if TLS has been enabled. """ hostname = host.ansible.get_variables()['inventory_hostname'] tls = host.run('curl https://%s/', hostname) assert tls.rc == 0 def test_https_enforcement(host): """ Tests if HTTPS is being enforced. """ hostname = host.ansible.get_variables()['inventory_hostname'] https_enforcement = host.run('curl -I http://%s/', hostname) assert https_enforcement.rc == 0 assert 'HTTP/1.1 301 Moved Permanently' in https_enforcement.stdout assert 'Location: https://%s/' % hostname in https_enforcement.stdout https_enforcement = host.run('curl -I https://%s/', hostname) assert https_enforcement.rc == 0 assert 'Strict-Transport-Security: max-age=31536000; includeSubDomains' in https_enforcement.stdout