diff --git a/group_vars/all b/group_vars/all index 3570ddc81576b1f4249b9f5a58285688721f35c2..5627b340f337b492a8402d6d4f92c02c93f8990a 100644 --- a/group_vars/all +++ b/group_vars/all @@ -1,3 +1,6 @@ +# This should be some e-mail address where technical messages may go. +admin_email: "michik@michik.net" + # Please feel free to add your favorite software you need absolutely everywhere # here. However, please do not leave too much stuff nobody else might use or # stuff that could be handy for an attacker. diff --git a/host_vars/test01.heaven.michik.net b/host_vars/test01.heaven.michik.net new file mode 100644 index 0000000000000000000000000000000000000000..f05c00c7a39e892f7e24b0c58d11a5de5cbf09c5 --- /dev/null +++ b/host_vars/test01.heaven.michik.net @@ -0,0 +1,19 @@ +acmetool_cert_domains: + - "test01.heaven.michik.net" + +#acmetool_server: "https://acme-staging.api.letsencrypt.org/directory" + +nginx_http_locations: + - location: "/" + config: | + return 301 https://$host$request_uri; + +nginx_https_sites: + - name: "test01.heaven.michik.net" + locations: + - location: "/" + config: | + root /var/www/html; + headers: null + +# vim: set ft=yaml: diff --git a/roles/acmetool/defaults/main.yml b/roles/acmetool/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..5bfba53a9e765875cc13df6bafdcf3ac6f5ef2f3 --- /dev/null +++ b/roles/acmetool/defaults/main.yml @@ -0,0 +1,13 @@ +# Please note that acmetool_webroot is defined in the defaults of the +# nginx-http role as it is needed for the default HTTP configuration of +# nginx (much simpler that way). + +acmetool_cert_domains: + - "{{ ansible_fqdn }}" + +# This is the production environment. To use the staging environment, please +# override for the host(s) in question with the following URL: +# https://acme-staging.api.letsencrypt.org/directory +# +# When this changes, you need to delete /var/lib/acme/conf/target manually! +acmetool_server: "https://acme-v01.api.letsencrypt.org/directory" diff --git a/roles/acmetool/meta/main.yml b/roles/acmetool/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..d62540b0b93fdd23b66be10108519909a64c583c --- /dev/null +++ b/roles/acmetool/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - nginx-http diff --git a/roles/acmetool/tasks/main.yml b/roles/acmetool/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..6abd4a80cb58f53a7186f479cf82d35ed3bfd434 --- /dev/null +++ b/roles/acmetool/tasks/main.yml @@ -0,0 +1,28 @@ +- name: install acmetool + apt: + package: acmetool + state: present + +- name: create acmetool conf and webroot directories + file: + dest: "/var/lib/acme/{{ item }}" + state: directory + with_items: + - "conf" + - "webroot" + +- name: install acmetool response file + template: + src: "responses.j2" + dest: "/var/lib/acme/conf/responses" + +- name: execute acmetool quickstart + command: "acmetool quickstart --batch" + args: + creates: "/var/lib/acme/conf/target" + +- name: request a certificate + command: 'acmetool want --batch {{ item }}' + args: + creates: "/var/lib/acme/live/{{ item }}" + with_items: "{{ acmetool_cert_domains }}" diff --git a/roles/acmetool/templates/responses.j2 b/roles/acmetool/templates/responses.j2 new file mode 100644 index 0000000000000000000000000000000000000000..39e53cac9689f7a6968f18def2c36c6b93316ae0 --- /dev/null +++ b/roles/acmetool/templates/responses.j2 @@ -0,0 +1,13 @@ +# {{ ansible_managed }} + +"acme-enter-email": "{{ admin_email }}" +"acme-agreement:https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf": true +"acmetool-quickstart-choose-server": {{ acmetool_server }} +"acmetool-quickstart-choose-method": webroot +"acmetool-quickstart-webroot-path": "{{ acmetool_webroot }}/acme-challenge" +"acmetool-quickstart-complete": true +"acmetool-quickstart-install-cronjob": true +"acmetool-quickstart-install-haproxy-script": true +"acmetool-quickstart-install-redirector-systemd": true +"acmetool-quickstart-key-type": rsa +"acmetool-quickstart-rsa-key-size": 4096 diff --git a/roles/nginx-http/defaults/main.yml b/roles/nginx-http/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..a57ba03ee28f18f73e86e37408711386f8d155e1 --- /dev/null +++ b/roles/nginx-http/defaults/main.yml @@ -0,0 +1,8 @@ +acmetool_webroot: "/var/lib/acme/webroot" + +nginx_http_locations: + - location: "/" + config: | + root /var/www/html; + +nginx_worker_processes: "auto" diff --git a/roles/nginx-http/handlers/main.yml b/roles/nginx-http/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..f70b46a0f423d58ec5d4019b721bb352454005af --- /dev/null +++ b/roles/nginx-http/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart nginx + systemd: + name: nginx + state: restarted diff --git a/roles/nginx-http/tasks/main.yml b/roles/nginx-http/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..e9f5f11dd617c3631a7e94220e368a7ef90344e2 --- /dev/null +++ b/roles/nginx-http/tasks/main.yml @@ -0,0 +1,39 @@ +- name: install nginx + apt: + package: nginx + state: present + +- name: enable nginx + systemd: + name: "nginx" + enabled: yes + +- name: configure nginx + template: + src: "nginx.conf.j2" + dest: "/etc/nginx/nginx.conf" + register: nginx_conf + +- name: configure the default site + template: + src: "default.j2" + dest: "/etc/nginx/sites-available/default" + register: nginx_default_config + +- name: enable the default site + file: + src: "/etc/nginx/sites-available/default" + dest: "/etc/nginx/sites-enabled/default" + state: link + register: nginx_default_enabled + +# We do this here instead of using the handler so that when the a role that +# depends on this as well as on acmetool (e.g. nginx-https) is used in a +# playbook, nginx is restarted with the proper configuration before the +# acmetool tasks are run. + +- name: restart nginx + systemd: + name: "nginx" + state: restarted + when: nginx_conf.changed or nginx_default_config.changed or nginx_default_enabled.changed diff --git a/roles/nginx-http/templates/default.j2 b/roles/nginx-http/templates/default.j2 new file mode 100644 index 0000000000000000000000000000000000000000..d058552133f05044590277f3313eee41d2572e99 --- /dev/null +++ b/roles/nginx-http/templates/default.j2 @@ -0,0 +1,18 @@ +# {{ ansible_managed }} + +server { + + listen 80; + listen [::]:80; + +{% for location in nginx_http_locations %} + location {{ location.location }} { +{{ location.config | indent(width=4, indentfirst=True) }} + } +{% endfor %} + + location ^~ /.well-known { + alias {{ acmetool_webroot }}; + } + +} diff --git a/roles/nginx-http/templates/nginx.conf.j2 b/roles/nginx-http/templates/nginx.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..83ce97c28c8adadbf4a27069a116100df70fc273 --- /dev/null +++ b/roles/nginx-http/templates/nginx.conf.j2 @@ -0,0 +1,43 @@ +# {{ ansible_managed }} + +user www-data; +worker_processes {{ nginx_worker_processes }}; + +pid /run/nginx.pid; + +include /etc/nginx/modules-enabled/*.conf; + +events { + + worker_connections 1024; + accept_mutex off; + use epoll; + +} + +http { + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + server_tokens off; + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + gzip_types *; + gzip_comp_level 6; + gzip_disable "msie6"; + + #large_client_header_buffers 8 128k; + #http2_max_field_size 128k; + #http2_max_header_size 256k; + + include /etc/nginx/sites-enabled/*; + +} diff --git a/roles/nginx-https/defaults/main.yml b/roles/nginx-https/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..c4f49c2f72d60009959f8183cbd844e8cb6e1011 --- /dev/null +++ b/roles/nginx-https/defaults/main.yml @@ -0,0 +1,14 @@ +nginx_ssl_protocols: "TLSv1.2" +nginx_ssl_ciphers: "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256" +nginx_ssl_dhparam: "/etc/ssl/certs/dh4096.pem" +nginx_ssl_dhparam_bits: 4096 + +nginx_https_default_headers: null + +nginx_https_sites: + - name: "{{ ansible_fqdn }}" + locations: + - location: "/" + config: | + root /var/www/html; + headers: null diff --git a/roles/nginx-https/handlers/main.yml b/roles/nginx-https/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..f70b46a0f423d58ec5d4019b721bb352454005af --- /dev/null +++ b/roles/nginx-https/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart nginx + systemd: + name: nginx + state: restarted diff --git a/roles/nginx-https/meta/main.yml b/roles/nginx-https/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..de5887ba86ac93d90c9d3fccc1896f523f628433 --- /dev/null +++ b/roles/nginx-https/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - nginx-http + - acmetool diff --git a/roles/nginx-https/tasks/main.yml b/roles/nginx-https/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..a27f5007a5fa39d67e2488fbf7e72be09e4e29d5 --- /dev/null +++ b/roles/nginx-https/tasks/main.yml @@ -0,0 +1,20 @@ +- name: create dh parameters + command: 'openssl dhparam -out "{{ nginx_ssl_dhparam }}" {{ nginx_ssl_dhparam_bits }}' + args: + creates: "{{ nginx_ssl_dhparam }}" + when: nginx_hmi_ssl_dhparam is not none + +- name: configure the https sites + template: + src: "https-site.j2" + dest: "/etc/nginx/sites-available/{{ item.name }}" + with_items: "{{ nginx_https_sites }}" + notify: restart nginx + +- name: enable the https sites + file: + src: "/etc/nginx/sites-available/{{ item.name }}" + dest: "/etc/nginx/sites-enabled/{{ item.name }}" + state: link + with_items: "{{ nginx_https_sites }}" + notify: restart nginx diff --git a/roles/nginx-https/templates/https-site.j2 b/roles/nginx-https/templates/https-site.j2 new file mode 100644 index 0000000000000000000000000000000000000000..e24fb3cbd14e1b08cbbd627ebeddef59a638d924 --- /dev/null +++ b/roles/nginx-https/templates/https-site.j2 @@ -0,0 +1,35 @@ +# {{ ansible_managed }} + +server { + + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ item.name }}; + + ssl_certificate /var/lib/acme/live/{{ item.name }}/fullchain; + ssl_certificate_key /var/lib/acme/live/{{ item.name }}/privkey; + ssl_dhparam {{ nginx_ssl_dhparam }}; + ssl_protocols {{ nginx_ssl_protocols }}; + ssl_ciphers {{ nginx_ssl_ciphers }}; + ssl_prefer_server_ciphers on; + +{% if nginx_https_default_headers %} +{% for header in nginx_https_default_headers %} + add_header {{ header }}; +{% endfor %} +{% endif %} + +{% if item.headers %} +{% for header in item.headers %} + add_header {{ header }}; +{% endfor %} +{% endif %} + +{% for location in item.locations %} + location {{ location.location }} { +{{ location.config | indent(width=4, indentfirst=True) }} + } +{% endfor %} + +} diff --git a/services-base.yml b/services-base.yml new file mode 100644 index 0000000000000000000000000000000000000000..631d869aaddb5a5be85c303fbdb061a735ddac81 --- /dev/null +++ b/services-base.yml @@ -0,0 +1,10 @@ +# Install the base services like our web and mail server +# as well as the management of SSL certificates. + +- name: install nginx, acmetool and postfix + hosts: all + become: yes + roles: + - nginx-http + - acmetool + - nginx-https