From be33260c475bac1309232dcc2a81aa706f4da521 Mon Sep 17 00:00:00 2001 From: Mathieu Gauthier-Pilote Date: Thu, 27 Apr 2023 14:49:12 -0400 Subject: [PATCH] Now installs a LE SSL cert via certbot by default + configurable base path for user's home --- webapps/mattermost/defaults/main.yml | 2 + webapps/mattermost/tasks/main.yml | 80 +++++++++++-------- .../mattermost/templates/letsencrypt.conf.j2 | 5 ++ .../templates/mattermost.service.j2 | 4 +- webapps/mattermost/templates/ssl.conf.j2 | 22 +++++ webapps/mattermost/templates/vhost.conf.j2 | 31 +++++-- 6 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 webapps/mattermost/templates/letsencrypt.conf.j2 create mode 100644 webapps/mattermost/templates/ssl.conf.j2 diff --git a/webapps/mattermost/defaults/main.yml b/webapps/mattermost/defaults/main.yml index 0334ce94..ceb0e33e 100644 --- a/webapps/mattermost/defaults/main.yml +++ b/webapps/mattermost/defaults/main.yml @@ -4,6 +4,8 @@ system_dep: "['git', 'nginx', 'postgresql', 'python3-psycopg2', 'certbot', 'acl' version: '7.8.1' download_url: "https://releases.mattermost.com/{{ version }}/mattermost-team-{{ version }}-linux-amd64.tar.gz" domains: ['example.domain.org'] +certbot_admin_email: 'mgauthier@evolix.ca' +home_base: '/home' mm_port: '8065' db_host: '127.0.0.1' db_name: "{{ service }}" diff --git a/webapps/mattermost/tasks/main.yml b/webapps/mattermost/tasks/main.yml index 0fcf1c67..89391443 100644 --- a/webapps/mattermost/tasks/main.yml +++ b/webapps/mattermost/tasks/main.yml @@ -4,11 +4,13 @@ - name: Install main system dependencies apt: name: "{{ system_dep }}" + update_cache: yes - name: Add UNIX account user: name: "{{ service }}" shell: /bin/bash + home: "{{ home_base }}/{{ service }}" - name: Add PostgreSQL user postgresql_user: @@ -51,41 +53,55 @@ - name: Start mattermost systemd unit service: name: "mattermost@{{ service }}" - state: started + state: restarted -#~ - name: Check if SSL certificate is present and register result - #~ stat: - #~ path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" - #~ register: ssl +- name: Template nginx snippet for Let's Encrypt/Certbot + template: + src: "letsencrypt.conf.j2" + dest: "/etc/nginx/snippets/letsencrypt.conf" -#~ - name: Generate certificate only if required (first time) - #~ block: - #~ - name: Template vhost without SSL for successfull LE challengce - #~ template: - #~ src: "vhost.conf.j2" - #~ dest: "/etc/nginx/sites-available/{{ service }}.conf" - #~ - name: Enable temporary nginx vhost for mattermost - #~ file: - #~ src: "/etc/nginx/sites-available/{{ service }}.conf" - #~ dest: "/etc/nginx/sites-enabled/{{ service }}.conf" - #~ state: link - #~ - name: Reload nginx conf - #~ service: - #~ name: nginx - #~ state: reloaded - #~ - name: Make sure /var/lib/letsencrypt exists and has correct permissions - #~ file: - #~ path: /var/lib/letsencrypt - #~ state: directory - #~ mode: '0755' - #~ - name: Generate certificate with certbot - #~ shell: certbot certonly --webroot --webroot-path /var/lib/letsencrypt -d {{ domains |first }} - #~ when: ssl.stat.exists == true +- name: Check if SSL certificate is present and register result + stat: + path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" + register: ssl -#~ - name: (Re)check if SSL certificate is present and register result - #~ stat: - #~ path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" - #~ register: ssl +- name: Generate certificate only if required (first time) + block: + - name: Template vhost without SSL for successfull LE challengce + template: + src: "vhost.conf.j2" + dest: "/etc/nginx/sites-available/{{ service }}.conf" + - name: Enable temporary nginx vhost for mattermost + file: + src: "/etc/nginx/sites-available/{{ service }}.conf" + dest: "/etc/nginx/sites-enabled/{{ service }}.conf" + state: link + - name: Reload nginx conf + service: + name: nginx + state: reloaded + - name: Make sure /var/lib/letsencrypt exists and has correct permissions + file: + path: /var/lib/letsencrypt + state: directory + mode: '0755' + - name: Generate certificate with certbot + shell: certbot certonly --webroot --webroot-path /var/lib/letsencrypt --non-interactive --agree-tos --email {{ certbot_admin_email }} -d {{ domains |first }} + - name: Create the ssl dir if needed + file: + path: /etc/nginx/ssl + state: directory + mode: '0750' + - name: Template ssl bloc for nginx vhost + template: + src: "ssl.conf.j2" + dest: "/etc/nginx/ssl/{{ domains |first }}.conf" + when: ssl.stat.exists != true + +- name: (Re)check if SSL certificate is present and register result + stat: + path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" + register: ssl - name: (Re)template conf file for nginx vhost with SSL template: diff --git a/webapps/mattermost/templates/letsencrypt.conf.j2 b/webapps/mattermost/templates/letsencrypt.conf.j2 new file mode 100644 index 00000000..6b33847e --- /dev/null +++ b/webapps/mattermost/templates/letsencrypt.conf.j2 @@ -0,0 +1,5 @@ +location ~ /.well-known/acme-challenge { + alias /var/lib/letsencrypt/; + try_files $uri =404; + allow all; +} diff --git a/webapps/mattermost/templates/mattermost.service.j2 b/webapps/mattermost/templates/mattermost.service.j2 index 59668476..5bbd7710 100644 --- a/webapps/mattermost/templates/mattermost.service.j2 +++ b/webapps/mattermost/templates/mattermost.service.j2 @@ -7,8 +7,8 @@ Requires=postgresql.service [Service] Type=notify Restart=always -WorkingDirectory=/home/%i/mattermost -ExecStart=/home/%i/mattermost/bin/mattermost +WorkingDirectory={{ home_base }}/%i/mattermost +ExecStart=/{{ home_base }}/%i/mattermost/bin/mattermost TimeoutStartSec=3600 LimitNOFILE=49152 RestartSec=10 diff --git a/webapps/mattermost/templates/ssl.conf.j2 b/webapps/mattermost/templates/ssl.conf.j2 new file mode 100644 index 00000000..86194389 --- /dev/null +++ b/webapps/mattermost/templates/ssl.conf.j2 @@ -0,0 +1,22 @@ +## +# Certificates +# you need a certificate to run in production. see https://letsencrypt.org/ +## +ssl_certificate /etc/letsencrypt/live/{{ domains | first }}/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/{{ domains | first }}/privkey.pem; + +## +# Security hardening (as of Nov 15, 2020) +# based on Mozilla Guideline v5.6 +## + +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers on; +ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; # add ECDHE-RSA-AES256-SHA if you want compatibility with Android 4 +ssl_session_timeout 1d; # defaults to 5m +ssl_session_cache shared:SSL:10m; # estimated to 40k sessions +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; +# HSTS (https://hstspreload.org), requires to be copied in 'location' sections that have add_header directives +#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; diff --git a/webapps/mattermost/templates/vhost.conf.j2 b/webapps/mattermost/templates/vhost.conf.j2 index 4f5525c0..1228cd12 100644 --- a/webapps/mattermost/templates/vhost.conf.j2 +++ b/webapps/mattermost/templates/vhost.conf.j2 @@ -3,18 +3,31 @@ upstream backend_{{ service }} { keepalive 32; } -#proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off; - server { - listen 80; - listen [::]:80; - #listen 443 ssl; - #listen [::]:443 ssl; + listen 80; + listen [::]:80; + server_name {{ domains | first }}; + + # For certbot + include /etc/nginx/snippets/letsencrypt.conf; + + {% if ssl.stat.exists %} + location / { return 301 https://$host$request_uri; } + {% endif %} +} + +{% if ssl.stat.exists %} +server { + listen 443 ssl; + listen [::]:443 ssl; server_name {{ domains | first }}; + + access_log /var/log/nginx/{{ service }}.access.log; + error_log /var/log/nginx/{{ service }}.error.log; - #ssl_certificate /etc/ssl/certs/mattermost.example.com.pem; - #ssl_certificate_key /etc/ssl/private/mattermost.example.com.pem; + include /etc/nginx/snippets/letsencrypt.conf; + include /etc/nginx/ssl/{{ domains | first }}.conf; location ~ /api/v[0-9]+/(users/)?websocket$ { proxy_set_header Upgrade $http_upgrade; @@ -47,6 +60,7 @@ server { proxy_buffers 256 16k; proxy_buffer_size 16k; proxy_read_timeout 600s; + #proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off; #proxy_cache mattermost_cache; #proxy_cache_revalidate on; #proxy_cache_min_uses 2; @@ -56,3 +70,4 @@ server { proxy_pass http://backend_{{ service }}; } } +{% endif %}