From d7d4a083e2d429d678121c471f6cf0d165e48d43 Mon Sep 17 00:00:00 2001 From: Sven-Hendrik Haase <svenstaro@gmail.com> Date: Mon, 20 Jun 2016 03:00:53 +0200 Subject: [PATCH] Add letsencrypt/certbot stuff --- README.md | 10 ++++++- playbooks/orion.yml | 3 ++- roles/dbscripts/templates/nginx.d.conf.j2 | 6 +++-- roles/nginx/files/certbot-renewal.service | 7 +++++ roles/nginx/files/certbot-renewal.timer | 9 +++++++ roles/nginx/tasks/main.yml | 28 +++++++++++++++++++- roles/nginx/templates/letsencrypt.conf | 5 ++++ roles/nginx/templates/sslsettings.conf | 9 +++++++ roles/sources/tasks/main.yml | 9 +++++++ roles/sources/templates/nginx.d.conf.j2 | 32 +++++++++++++++++++++++ 10 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 roles/nginx/files/certbot-renewal.service create mode 100644 roles/nginx/files/certbot-renewal.timer create mode 100644 roles/nginx/templates/letsencrypt.conf create mode 100644 roles/nginx/templates/sslsettings.conf create mode 100644 roles/sources/tasks/main.yml create mode 100644 roles/sources/templates/nginx.d.conf.j2 diff --git a/README.md b/README.md index 72ac0c5fb..dd5e859aa 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,14 @@ After the provisioning script has run, it is safe to reboot. Once in the new system, run the regular playbook: `ansible-playbook playbooks/$hostname.yml`. This playbook is the one regularily used for adminstrating the server and is entirely idempotent. +##### Note about first time certificates + +The first time a certificate is issued, you'll have to do this manually by yourself. First, configure the DNS to +point to the new server and then run a playbook onto the server which includes the nginx role. Then on the server, +it is necessary to run the following once: + +certbot certonly --email webmaster@archlinux.org --agree-tos --rsa-key-size 4096 --renew-by-default --webroot -w /var/lib/letsencrypt/ <domain-name> + ## Servers ### vostok @@ -22,7 +30,7 @@ playbook is the one regularily used for adminstrating the server and is entirely #### Services - repos/sync (repos.archlinux.org) -- sources +- sources (sources.archlinux.org) - archive (archive.archlinux.org) ### apollo diff --git a/playbooks/orion.yml b/playbooks/orion.yml index 38a51cdbd..0d1e381bc 100644 --- a/playbooks/orion.yml +++ b/playbooks/orion.yml @@ -12,7 +12,8 @@ - { role: opendkim, dkim_selector: orion, tags: ['mail'] } - { role: postfix, tags: ['mail'] } - { role: archusers, tags: ['archusers'] } - - { role: nginx, tags: ["nginx"] } + - { role: nginx, letsencrypt_validation_dir: "/var/lib/letsencrypt", tags: ["nginx"] } - { role: dbscripts, repos_domain: "repos.archlinux.org", svntogit_repos: "/srv/svntogit/repos", tags: ['dbscripts', 'archusers'] } - { role: sudo, tags: ['sudo', 'archusers'] } - { role: archweb, archweb_home: "/srv/http/archweb", tags: ['archweb'] } + - { role: sources, sources_domain: "sources.archlinux.org", tags: ['sources'] } diff --git a/roles/dbscripts/templates/nginx.d.conf.j2 b/roles/dbscripts/templates/nginx.d.conf.j2 index 53da46e39..9b1331bb9 100644 --- a/roles/dbscripts/templates/nginx.d.conf.j2 +++ b/roles/dbscripts/templates/nginx.d.conf.j2 @@ -1,6 +1,6 @@ server { - listen 80 default_server; - listen [::]; + listen 80; + listen [::]:80; server_name {{ repos_domain }}; root /srv/ftp; @@ -10,6 +10,8 @@ server { allow all; } + include snippets/letsencrypt.conf; + # Server at velocitynet allow 66.211.214.130; # dom0.archlinux.org. allow 66.211.214.131; # gudrun.archlinux.org. diff --git a/roles/nginx/files/certbot-renewal.service b/roles/nginx/files/certbot-renewal.service new file mode 100644 index 000000000..74b1841ca --- /dev/null +++ b/roles/nginx/files/certbot-renewal.service @@ -0,0 +1,7 @@ +[Unit] +Description=Let's Encrypt renewal + +[Service] +Type=oneshot +ExecStart=/usr/bin/certbot renew --rsa-key-size 4096 +ExecStartPost=/bin/systemctl reload nginx.service diff --git a/roles/nginx/files/certbot-renewal.timer b/roles/nginx/files/certbot-renewal.timer new file mode 100644 index 000000000..d5bebba69 --- /dev/null +++ b/roles/nginx/files/certbot-renewal.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Daily renewal of Let's Encrypt's certificates + +[Timer] +OnCalendar=daily +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml index ae4f43131..920b7b0c2 100644 --- a/roles/nginx/tasks/main.yml +++ b/roles/nginx/tasks/main.yml @@ -1,13 +1,22 @@ --- - name: install nginx - pacman: name=nginx-mainline state=present + pacman: name=nginx-mainline,certbot state=present - name: configure nginx template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644 notify: - restart nginx +- name: snippets directory + file: state=directory path=/etc/nginx/snippets owner=root group=root mode=755 + +- name: copy snippets + template: src={{ item }} dest=/etc/nginx/snippets owner=root group=root mode=644 + with_items: + - letsencrypt.conf + - sslsettings.conf + - name: create nginx.d directory file: state=directory path=/etc/nginx/nginx.d owner=root group=root mode=755 @@ -17,5 +26,22 @@ - name: create default nginx log directory file: state=directory path=/var/log/nginx/default owner=http group=log mode=750 +- name: create unique DH group + command: openssl dhparam -out /etc/ssl/dhparams.pem 2048 creates=/etc/ssl/dhparams.pem + +- name: create directory to store validation stuff in + file: owner=root group=http mode=750 path={{ letsencrypt_validation_dir }} state=directory + +- name: install letsencrypt renewal service + copy: src={{ item }} dest=/etc/systemd/system/{{ item }} owner=root group=root mode=644 + with_items: + - certbot-renewal.service + - certbot-renewal.timer + notify: + - daemon reload + +- name: activate letsencrypt renewal service + service: name=certbot-renewal.timer enabled=yes state=started + - name: enable nginx service: name=nginx enabled=yes diff --git a/roles/nginx/templates/letsencrypt.conf b/roles/nginx/templates/letsencrypt.conf new file mode 100644 index 000000000..99dd6c628 --- /dev/null +++ b/roles/nginx/templates/letsencrypt.conf @@ -0,0 +1,5 @@ +location /.well-known/acme-challenge { + root {{ letsencrypt_validation_dir }}; + default_type "text/plain"; + try_files $uri =404; +} diff --git a/roles/nginx/templates/sslsettings.conf b/roles/nginx/templates/sslsettings.conf new file mode 100644 index 000000000..27b7f30b6 --- /dev/null +++ b/roles/nginx/templates/sslsettings.conf @@ -0,0 +1,9 @@ +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'; +ssl_protocols TLSv1.2; +ssl_prefer_server_ciphers on; +ssl_dhparam /etc/ssl/dhparams.pem; +ssl_session_timeout 5m; +ssl_session_cache shared:SSL:10m; +ssl_stapling on; +ssl_stapling_verify on; +add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; diff --git a/roles/sources/tasks/main.yml b/roles/sources/tasks/main.yml new file mode 100644 index 000000000..6bb046372 --- /dev/null +++ b/roles/sources/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +- name: set up nginx + template: src=nginx.d.conf.j2 dest=/etc/nginx/nginx.d/sources.conf owner=root group=root mode=644 + notify: + - restart nginx + +- name: make nginx log dir + file: path=/var/log/nginx/{{ sources_domain }} state=directory owner=http group=log mode=755 diff --git a/roles/sources/templates/nginx.d.conf.j2 b/roles/sources/templates/nginx.d.conf.j2 new file mode 100644 index 000000000..c885d61dd --- /dev/null +++ b/roles/sources/templates/nginx.d.conf.j2 @@ -0,0 +1,32 @@ +server { + listen 80; + listen [::]:80; + server_name {{ sources_domain }}; + + access_log /var/log/nginx/{{ sources_domain }}/access.log; + error_log /var/log/nginx/{{ sources_domain }}/error.log; + + include snippets/letsencrypt.conf; + + location / { + rewrite ^(.*) https://$server_name$1 permanent; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {{ sources_domain }}; + + access_log /var/log/nginx/{{ sources_domain }}/access.log; + error_log /var/log/nginx/{{ sources_domain }}/error.log; + + ssl_certificate /etc/letsencrypt/live/{{ sources_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ sources_domain }}/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/{{ sources_domain }}/chain.pem; + include snippets/sslsettings.conf; + + root /srv/ftp/sources; + + autoindex on; +} -- GitLab