From 5ddcacc28105cf872bf70664e856d4aa9000d023 Mon Sep 17 00:00:00 2001
From: MichiK <michik@michik.net>
Date: Fri, 21 Jun 2019 20:14:19 +0200
Subject: [PATCH] Add nginx and acmetool basics

---
 group_vars/all                            |  3 ++
 host_vars/test01.heaven.michik.net        | 19 ++++++++++
 roles/acmetool/defaults/main.yml          | 13 +++++++
 roles/acmetool/meta/main.yml              |  2 ++
 roles/acmetool/tasks/main.yml             | 28 +++++++++++++++
 roles/acmetool/templates/responses.j2     | 13 +++++++
 roles/nginx-http/defaults/main.yml        |  8 +++++
 roles/nginx-http/handlers/main.yml        |  4 +++
 roles/nginx-http/tasks/main.yml           | 39 ++++++++++++++++++++
 roles/nginx-http/templates/default.j2     | 18 ++++++++++
 roles/nginx-http/templates/nginx.conf.j2  | 43 +++++++++++++++++++++++
 roles/nginx-https/defaults/main.yml       | 14 ++++++++
 roles/nginx-https/handlers/main.yml       |  4 +++
 roles/nginx-https/meta/main.yml           |  3 ++
 roles/nginx-https/tasks/main.yml          | 20 +++++++++++
 roles/nginx-https/templates/https-site.j2 | 35 ++++++++++++++++++
 services-base.yml                         | 10 ++++++
 17 files changed, 276 insertions(+)
 create mode 100644 host_vars/test01.heaven.michik.net
 create mode 100644 roles/acmetool/defaults/main.yml
 create mode 100644 roles/acmetool/meta/main.yml
 create mode 100644 roles/acmetool/tasks/main.yml
 create mode 100644 roles/acmetool/templates/responses.j2
 create mode 100644 roles/nginx-http/defaults/main.yml
 create mode 100644 roles/nginx-http/handlers/main.yml
 create mode 100644 roles/nginx-http/tasks/main.yml
 create mode 100644 roles/nginx-http/templates/default.j2
 create mode 100644 roles/nginx-http/templates/nginx.conf.j2
 create mode 100644 roles/nginx-https/defaults/main.yml
 create mode 100644 roles/nginx-https/handlers/main.yml
 create mode 100644 roles/nginx-https/meta/main.yml
 create mode 100644 roles/nginx-https/tasks/main.yml
 create mode 100644 roles/nginx-https/templates/https-site.j2
 create mode 100644 services-base.yml

diff --git a/group_vars/all b/group_vars/all
index 3570ddc..5627b34 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 0000000..f05c00c
--- /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 0000000..5bfba53
--- /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 0000000..d62540b
--- /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 0000000..6abd4a8
--- /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 0000000..39e53ca
--- /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 0000000..a57ba03
--- /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 0000000..f70b46a
--- /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 0000000..e9f5f11
--- /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 0000000..d058552
--- /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 0000000..83ce97c
--- /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 0000000..c4f49c2
--- /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 0000000..f70b46a
--- /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 0000000..de5887b
--- /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 0000000..a27f500
--- /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 0000000..e24fb3c
--- /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 0000000..631d869
--- /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
-- 
GitLab