From ebba1a12482f55d3210c1a0dbac9143cc3936937 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Thu, 24 Oct 2019 00:22:13 +0100 Subject: [PATCH] added: support for generating SSL certs from Let's Encrypt. --- defaults/main.yml | 14 ++ tasks/nginx.yml | 160 ++++++++++++++++++++-- templates/etc_ngnix_confd_pleroma.conf.j2 | 14 +- vars/main.yml | 11 +- 4 files changed, 175 insertions(+), 24 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index dc7377e..785692b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -34,3 +34,17 @@ pleroma_defaults: user: "{{ pleroma.config.db.user }}" address: 127.0.0.1/32 method: md5 + ssl: + csr: + countryName: "" + emailAddress: "{{ pleroma.config.email }}" + localityName: "" + organizationName: "" + organizationUnitName: "" + stateOrProvinceName: "" + letsEncrypt: + enable: false + acmeAccountEmail: "{{ pleroma.config.email }}" + acmeDirectory: "https://acme-v02.api.letsencrypt.org/directory" + remainingDays: 10 + termsAgreed: no diff --git a/tasks/nginx.yml b/tasks/nginx.yml index 8c135f2..1f626d5 100644 --- a/tasks/nginx.yml +++ b/tasks/nginx.yml @@ -1,12 +1,18 @@ --- -# py-cryptography is needed for self-signed certificates -# we could probably do away with certbot. - name: Nginx -- Ensuring Nginx dependencies are installed. apk: - name: nginx, certbot, py-cryptography + name: "{{ pleroma_deps_nginx }}" state: present -- name: Nginx -- Ensuring that the ssl folder exists +- name: Nginx -- Ensuring the Nginx configuration is present. + template: + src: etc_ngnix_confd_pleroma.conf.j2 + dest: "{{ pleroma_nginx_conf_file }}" + owner: root + group: root + mode: '0600' + +- name: Nginx -- Ensuring that the SSL folder exists file: name: "{{ pleroma_ssl_folder }}" state: directory @@ -26,30 +32,160 @@ - name: Nginx -- Ensuring that the certificate signing request is generated. openssl_csr: + common_name: "{{ pleroma.config.host }}" + country_name: "{{ pleroma.ssl.csr.countryName }}" + email_address: "{{ pleroma.ssl.csr.emailAddress }}" + locality_name: "{{ pleroma.ssl.csr.localityName }}" + organization_name: "{{ pleroma.ssl.csr.organizationName }}" + organizational_unit_name: "{{ pleroma.ssl.csr.organizationUnitName }}" + state_or_province_name: "{{ pleroma.ssl.csr.stateOrProvinceName }}" mode: '0400' group: root owner: root path: "{{ pleroma_ssl_csrPath }}" privatekey_path: "{{ pleroma_ssl_privateKeyPath }}" - common_name: "{{ pleroma.config.host }}" - name: Nginx -- Ensuring the self-signed certificate is generated. openssl_certificate: path: "{{ pleroma_ssl_selfSignedCertPath }}" + mode: '0400' + group: root + owner: root privatekey_path: "{{ pleroma_ssl_privateKeyPath }}" csr_path: "{{ pleroma_ssl_csrPath }}" provider: selfsigned -- name: Nginx -- Ensuring the Nginx configuration is present. - template: - src: etc_ngnix_confd_pleroma.conf.j2 - dest: /etc/nginx/conf.d/pleroma.conf +- name: Nginx -- Ensuring Nginx configuration references the self signed certificate + lineinfile: + path: "{{ pleroma_nginx_conf_file }}" owner: root group: root - mode: '0400' + mode: '0600' + insertafter: '^\s+#\s\[\[PLACEHOLDER\sFOR\sSSL\sCERTIFICATE\]\].*$' + line: ' ssl_certificate {{ pleroma_ssl_selfSignedCertPath }};' + state: present + when: not pleroma.ssl.letsEncrypt.enable -- name: Nginx -- Ensuring that Nginx is enabled and started. +- name: Nginx -- Ensuring that the Let's encrypt challenge directory is present. + file: + name: "{{ pleroma_letsEncrypt_baseDir }}/.well-known/acme-challenge" + state: directory + mode: '0700' + owner: nginx + group: nginx + recurse: yes + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Ensuring that the private ACME account key is present. + openssl_privatekey: + mode: '0400' + group: root + owner: root + path: "{{ pleroma_ssl_privateAcmeAccountKeyPath }}" + size: 4096 + state: present + type: RSA + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Ensuring the location block for the ACME challenge is configured. + blockinfile: + path: "{{ pleroma_nginx_conf_file }}" + state: present + mode: '0600' + owner: root + group: root + insertafter: '^\s+#\s\[\[PLACEHOLDER\sFOR\sLETS\sENCRYPT\sFOLDER\]\].*$' + block: |2 + location ~/\.well-known/acme-challenge { + root {{ pleroma_letsEncrypt_baseDir }}/; + try_files $uri @forward_https; + } + location @forward_https { + return 301 https://$server_name$request_uri; + } + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Checking if certificate file exists. + stat: + path: "{{ pleroma_ssl_fullChainCert }}" + register: certificate_file + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Temporarily adding the reference to the self signed certificate for ACME challenge. + lineinfile: + path: "{{ pleroma_nginx_conf_file }}" + owner: root + group: root + mode: '0600' + insertafter: '^\s+#\s\[\[PLACEHOLDER\sFOR\sSSL\sCERTIFICATE\]\].*$' + line: ' ssl_certificate {{ pleroma_ssl_selfSignedCertPath }};' + state: present + when: pleroma.ssl.letsEncrypt.enable and certificate_file.stat.exists == false + +- name: Nginx -- Ensuring that Nginx is running for the ACME challenge. + service: + name: nginx + state: started + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Acme challenge part 1 - Creating Acme challenge. + acme_certificate: + account_key_src: "{{ pleroma_ssl_privateAcmeAccountKeyPath }}" + account_email: "{{ pleroma.ssl.letsEncrypt.acmeAccountEmail }}" + acme_directory: "{{ pleroma.ssl.letsEncrypt.acmeDirectory }}" + acme_version: 2 + challenge: http-01 + csr: "{{ pleroma_ssl_csrPath }}" + fullchain_dest: "{{ pleroma_ssl_fullChainCert }}" + remaining_days: "{{ pleroma.ssl.letsEncrypt.remainingDays }}" + select_crypto_backend: cryptography + terms_agreed: "{{ pleroma.ssl.letsEncrypt.termsAgreed }}" + register: acme_challenge + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Creating the Acme challenge file + copy: + dest: "{{ pleroma_letsEncrypt_baseDir }}/{{ acme_challenge['challenge_data'][pleroma.config.host]['http-01']['resource'] }}" + content: "{{ acme_challenge['challenge_data'][pleroma.config.host]['http-01']['resource_value'] }}" + when: pleroma.ssl.letsEncrypt.enable and acme_challenge is changed + +- name: Nginx -- Acme challenge part 2 - Validating the Acme challenge to create the SSL certificate. + acme_certificate: + account_key_src: "{{ pleroma_ssl_privateAcmeAccountKeyPath }}" + account_email: "{{ pleroma.ssl.letsEncrypt.acmeAccountEmail }}" + acme_directory: "{{ pleroma.ssl.letsEncrypt.acmeDirectory }}" + acme_version: 2 + challenge: http-01 + csr: "{{ pleroma_ssl_csrPath }}" + fullchain_dest: "{{ pleroma_ssl_fullChainCert }}" + remaining_days: "{{ pleroma.ssl.letsEncrypt.remainingDays }}" + select_crypto_backend: cryptography + terms_agreed: "{{ pleroma.ssl.letsEncrypt.termsAgreed }}" + data: "{{ acme_challenge }}" + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Updating file permissions of the SSL certificate. + file: + path: "{{ pleroma_ssl_fullChainCert }}" + owner: root + group: root + mode: 0400 + state: file + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Ensuring the ssl_ceritificate option is up to date in the Nginx configuration. + lineinfile: + path: "{{ pleroma_nginx_conf_file }}" + owner: root + group: root + mode: '0600' + regexp: '^\s+ssl_certificate.*$' + line: ' ssl_certificate {{ pleroma_ssl_fullChainCert }};' + state: present + when: pleroma.ssl.letsEncrypt.enable + +- name: Nginx -- Ensuring that Nginx is enabled and restarted. service: name: nginx enabled: yes - state: started + state: restarted diff --git a/templates/etc_ngnix_confd_pleroma.conf.j2 b/templates/etc_ngnix_confd_pleroma.conf.j2 index fbf1044..be0e973 100644 --- a/templates/etc_ngnix_confd_pleroma.conf.j2 +++ b/templates/etc_ngnix_confd_pleroma.conf.j2 @@ -7,15 +7,8 @@ server { listen 80; listen [::]:80; - # Uncomment this if you need to use the 'webroot' method with certbot. Make sure - # that the directory exists and that it is accessible by the webserver. If you followed - # the guide, you already ran 'mkdir -p /var/lib/letsencrypt' to create the folder. - # You may need to load this file with the ssl server block commented out, run certbot - # to get the certificate, and then uncomment it. - # - # location ~ /\.well-known/acme-challenge { - # root /var/lib/letsencrypt/; - # } + # [[PLACEHOLDER FOR LETS ENCRYPT FOLDER]] + location / { return 301 https://$server_name$request_uri; } @@ -31,9 +24,8 @@ server { listen [::]:443 ssl http2; ssl_session_timeout 5m; - # ssl_trusted_certificate /etc/letsencrypt/live/{{ pleroma.config.host }}/chain.pem; - ssl_certificate {{ pleroma_ssl_selfSignedCertPath }}; ssl_certificate_key {{ pleroma_ssl_privateKeyPath }}; + # [[PLACEHOLDER FOR SSL CERTIFICATE]] ssl_protocols TLSv1.2; 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:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; diff --git a/vars/main.yml b/vars/main.yml index 416fc0e..15bd338 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -6,15 +6,24 @@ pleroma_user: name: pleroma shell: /bin/false +pleroma_deps_nginx: nginx, py-cryptography + pleroma_config_dir: /etc/pleroma +pleroma_nginx_conf_dir: /etc/nginx/conf.d +pleroma_nginx_conf_file: "{{ pleroma_nginx_conf_dir }}/pleroma.conf" + pleroma_base_data_dir: /var/lib/pleroma pleroma_static_dir: "{{ pleroma_base_data_dir }}/static" pleroma_uploads_dir: "{{ pleroma_base_data_dir }}/uploads" pleroma_ssl_folder: /etc/ssl/pleroma pleroma_ssl_privateKeyPath: "{{ pleroma_ssl_folder }}/pleroma.key" +pleroma_ssl_privateAcmeAccountKeyPath: "{{ pleroma_ssl_folder}}/acme_account.key" pleroma_ssl_csrPath: "{{ pleroma_ssl_folder }}/pleroma.csr" -pleroma_ssl_selfSignedCertPath: "{{ pleroma_ssl_folder }}/pleroma.crt" +pleroma_ssl_selfSignedCertPath: "{{ pleroma_ssl_folder }}/pleroma-self-signed.crt" +pleroma_ssl_fullChainCert: "{{ pleroma_ssl_folder }}/{{ pleroma.config.host }}-fullchain.pem" + +pleroma_letsEncrypt_baseDir: /var/lib/letsencrypt pleroma_postgres_log_dir: /var/log/postgresql pleroma_postgres_base_conf: /etc/postgresql