diff --git a/roles/nginx/README.md b/roles/nginx/README.md new file mode 100644 index 0000000000..f760a289b0 --- /dev/null +++ b/roles/nginx/README.md @@ -0,0 +1,72 @@ +Overview +======== + +Role for using nginx. Sets up ssl certs in known locations and inactive +template for application use. + + +Role options +------------ +* `update_ssl_certs` - Only push the SSL key and PEM files and restart Nginx + + +SSL +--- +This role will copy over key/crt by default. +It can be disabled by setting `httpd_no_ssl` to true + +You will still need to configure the application to use ssl. A reference template templates/example_ssl.conf.j2 is provided + +The script will look for keys and certs in the paths specified by the +`httpd_ssl_key_file`, `httpd_ssl_crt_file` and `httpd_ssl_pem_file` variables. + +If that fails, it will attempt to create key/crt pair if there isn't one already installed. + +If a pem file exists in the location specified by `httpd_ssl_pem_file`, +it will be copied across as `ssl.pem`. Applications that required the certificate +chain should point at `/etc/nginx/conf.d/ssl.pem`. + +Caveats +------- +The key, crt and pem will always be stored on the host under `/etc/nginx/conf.d/{{ +inventory_hostname }}.{key,crt,pem}` due to the multi-sourcing nature of the setup. +Use `httpd_no_ssl` and setup as desired if it deviates from what is covered here. + +Logrotate +--------- + +A default template is configured. + +SELinux +------- + +selinux contexts are application specific. Enable the following as needed by your setup: + +``` +httpd_can_network_relay +httpd_can_network_memcache +httpd_can_network_connect * +httpd_can_network_connect_db * +httpd_can_sendmail +``` + +- * commonly used items enabled by default + +Handlers +-------- + +restart nginx - restart the nginx service + +Variables +--------- + +* `service_name` - canonical name for service +* `httpd_no_ssl` - don't set up ssl +* `httpd_ssl_key_file` - local path to use as source for ssl.key file +* `httpd_ssl_crt_file` - local path to use as source for ssl.crt file +* `httpd_ssl_pem_file` - local path to use as source for ssl.pem file +* `ssl_fast_dh` - whether to use a speedy method to generate Diffie Hellman + parameters +* `ssl_intermediate_ca_pattern` - pattern to check if certificate is + self-signed +* `ssl_self_signed_string` - location and CN settings for self signed cert diff --git a/roles/nginx/defaults/main.yml b/roles/nginx/defaults/main.yml new file mode 100644 index 0000000000..0758337b9d --- /dev/null +++ b/roles/nginx/defaults/main.yml @@ -0,0 +1,18 @@ +--- +## set some defaults with the expectation that they will be set in/from calling role +service_name: "{{ inventory_hostname }}" + +## nginx core configuration defaults +nginx_default_port: 80 +nginx_error_level: "warn" +nginx_worker_processes: 1 +nginx_gzip_status: "on" + +## variables unset by default +httpd_no_ssl: false +httpd_ssl_key_file: "{{ ssl_key_file | default('/THIS/FILE/PROBABLY/DOESNT/EXIST') }}" +httpd_ssl_crt_file: "{{ ssl_crt_file | default('/THIS/FILE/PROBABLY/DOESNT/EXIST') }}" +httpd_ssl_pem_file: "{{ ssl_pem_file | default('/THIS/FILE/PROBABLY/DOESNT/EXIST') }}" +ssl_self_signed_string: "/C=US/ST=New York/L=New York City/O=My Department/CN={{ service_name }}" +ssl_fast_dh: false +nginx_ssl_ca_line: "#ssl_client_certificate /path/to/ca/file;" diff --git a/roles/nginx/files/etc/logrotate.d/nginx b/roles/nginx/files/etc/logrotate.d/nginx new file mode 100644 index 0000000000..b02b626368 --- /dev/null +++ b/roles/nginx/files/etc/logrotate.d/nginx @@ -0,0 +1,13 @@ +/var/log/nginx/*.log { + daily + missingok + rotate 30 + compress + delaycompress + notifempty + create 640 nginx adm + sharedscripts + postrotate + [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` + endscript +} diff --git a/roles/nginx/files/etc/nginx/conf.d/default.conf b/roles/nginx/files/etc/nginx/conf.d/default.conf new file mode 100644 index 0000000000..f2afdc2866 --- /dev/null +++ b/roles/nginx/files/etc/nginx/conf.d/default.conf @@ -0,0 +1,44 @@ +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/log/host.access.log main; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} diff --git a/roles/nginx/handlers/main.yml b/roles/nginx/handlers/main.yml new file mode 100644 index 0000000000..6deed0cd07 --- /dev/null +++ b/roles/nginx/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart nginx + service: + name: nginx + state: restarted diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml new file mode 100644 index 0000000000..83f24cdee5 --- /dev/null +++ b/roles/nginx/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- include: nginx.yml + +- include: ssl-setup.yml + when: not httpd_no_ssl diff --git a/roles/nginx/tasks/nginx.yml b/roles/nginx/tasks/nginx.yml new file mode 100644 index 0000000000..6cb2eea432 --- /dev/null +++ b/roles/nginx/tasks/nginx.yml @@ -0,0 +1,33 @@ +- name: install nginx + dnf: + name: nginx + state: present + +- name: Ensure nginx is started and enabled to start at boot. + service: name=nginx state=started enabled=yes + +- name: install nginx logrotation file + copy: + src: etc/logrotate.d/nginx + dest: /etc/logrotate.d/nginx + owner: root + group: root + mode: 0644 + +- name: install /etc/nginx/nginx.conf + template: + src: etc/nginx/nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: 0644 + notify: restart nginx + +- name: install /etc/nginx/conf.d/default.conf + copy: + src: etc/nginx/conf.d/default.conf + dest: /etc/nginx/conf.d/default.conf + owner: root + group: root + mode: 0644 + notify: restart nginx diff --git a/roles/nginx/tasks/ssl-setup.yml b/roles/nginx/tasks/ssl-setup.yml new file mode 100644 index 0000000000..a0e138f540 --- /dev/null +++ b/roles/nginx/tasks/ssl-setup.yml @@ -0,0 +1,45 @@ +- name: copy over ssl key + copy: + src: "{{ item }}" + dest: "/etc/nginx/conf.d/ssl.key" + with_first_found: + - files: + - "{{ httpd_ssl_key_file }}" + skip: True + register: setup_ssl_key + notify: restart nginx service + no_log: True + tags: + - update_ssl_certs + +- name: copy over ssl pem file + copy: + src: "{{ item }}" + dest: "/etc/nginx/conf.d/ssl.pem" + with_first_found: + - files: + - "{{ httpd_ssl_pem_file }}" + - "{{ httpd_ssl_crt_file }}" + skip: True + register: setup_ssl_pem + when: setup_ssl_key|success + tags: + - update_ssl_certs + + # generate our own key/crt if pem is missing +- name: generate self signed ssl certificate + command: openssl req -new -nodes -x509 -subj "{{ ssl_self_signed_string }}" -days 3650 -keyout /etc/nginx/conf.d/ssl.key -out /etc/nginx/conf.d/ssl.pem -extensions v3_ca + args: + creates: /etc/nginx/conf.d/ssl.pem + when: setup_ssl_key|failed or setup_ssl_pem|failed + +- name: warn that the next step takes a while + debug: + msg: "the next step can take around 15 minutes if it hasn't already been done" + +- name: create Diffie Hellman ephemeral parameters + # https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + command: openssl dhparam {{ '-dsaparam' if ssl_fast_dh else '' }} -out dhparam.pem 4096 + args: + chdir: /etc/ssl/certs + creates: /etc/ssl/certs/dhparam.pem diff --git a/roles/nginx/templates/etc/nginx/nginx.conf.j2 b/roles/nginx/templates/etc/nginx/nginx.conf.j2 new file mode 100644 index 0000000000..0f396060cf --- /dev/null +++ b/roles/nginx/templates/etc/nginx/nginx.conf.j2 @@ -0,0 +1,50 @@ +user nginx; +worker_processes {{ nginx_worker_processes }}; + +error_log /var/log/nginx/error.log {{ nginx_error_level }}; +{% if ansible_distribution_major_version == "7" %} +pid /run/nginx.pid; +{% else %} +pid /var/run/nginx.pid; +{% endif %} + +# Load dynamic modules. See /usr/share/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + + +events { + worker_connections 1024; +} + + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + server_names_hash_bucket_size 128; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + gzip {{ nginx_gzip_status }}; + + include /etc/nginx/conf.d/*.conf; + + # bind server context for status explicitly to loopback to allow local only actions + server { + listen [::1]:{{ nginx_default_port }} default_server; + listen 127.0.0.1:{{ nginx_default_port }} default_server; + server_name _; + root /usr/share/nginx/html; + # Load configuration files for the default server block. + include /etc/nginx/default.d/*.conf; + } +} diff --git a/roles/nginx/templates/example_ssl.conf.2 b/roles/nginx/templates/example_ssl.conf.2 new file mode 100644 index 0000000000..42bc897225 --- /dev/null +++ b/roles/nginx/templates/example_ssl.conf.2 @@ -0,0 +1,29 @@ + + +# HTTPS server +# +#server { +# listen 443; +# server_name {{ service_name }}; + +# ssl on; +# ssl_certificate /etc/nginx/conf.d/ssl.pem; +# ssl_certificate_key /etc/nginx/conf.d/ssl.key; +# {{ nginx_ssl_ca_line }} + +# ssl_session_timeout 5m; + +# # https://mozilla.github.io/server-side-tls/ssl-config-generator/ +# # modern configuration. tweak to your needs. +# ssl_protocols TLSv1.1 TLSv1.2; +# ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; +# ssl_prefer_server_ciphers on; +# +# # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) +# add_header Strict-Transport-Security max-age=15768000; + +# location / { +# root /usr/share/nginx/html; +# index index.html index.htm; +# } +#}