From c0638a8d6478ae9d8c3be9d7a65c636bc4262f54 Mon Sep 17 00:00:00 2001
From: Robin Sonnabend <robin@fsmpi.rwth-aachen.de>
Date: Sat, 22 Feb 2020 16:42:32 +0100
Subject: [PATCH] Finish acmebot role

---
 acmebot/defaults/main.yml           | 22 +++----
 acmebot/files/acmebot.service       | 26 ++++++++
 acmebot/files/acmebot.timer         | 11 ++++
 acmebot/files/service-after.conf    |  2 -
 acmebot/tasks/main.yml              | 96 +++++++++++++++++------------
 webserver/templates/ssl-certificate |  6 +-
 6 files changed, 105 insertions(+), 58 deletions(-)
 create mode 100644 acmebot/files/acmebot.service
 create mode 100644 acmebot/files/acmebot.timer
 delete mode 100644 acmebot/files/service-after.conf

diff --git a/acmebot/defaults/main.yml b/acmebot/defaults/main.yml
index edc0c96..23557df 100644
--- a/acmebot/defaults/main.yml
+++ b/acmebot/defaults/main.yml
@@ -1,7 +1,8 @@
 ---
 
 acmebot_account_mail: "{{ adminaddr }}"
-acmebot_after_nginx_proxy: true
+acmebot_version: "v2.6.0"
+acmebot_enable_update_check: true
 
 acmebot_settings: {}
 acmebot_default_settings:
@@ -20,9 +21,8 @@ acmebot_default_settings:
     - "google_pilot"
 
   file_user: root
-  file_group: ssl-cert
+  file_group: root
 
-  # TODO default to both key types or single one? default to non-/custom params?
   key_size: 4096  # null to turn off RSA certificates
   key_curve: "secp384r1"  # null to turn off ECDSA certificates
   key_cipher: null
@@ -63,12 +63,11 @@ acmebot_default_key_suffixes:
 #   set to null for specified certs to use dns-01 for those
 acmebot_directories: {}
 acmebot_default_directories:
-  pid: "/run"
+  pid: "/run/acmebot"
   log: "/var/log/acmebot"
   resource: "/var/lib/acmebot"
   temp: null
 
-  # TODO layout equivalent to acmetool
   private_key: /etc/ssl/acmebot/privkey
   backup_key: /etc/ssl/acmebot/backup_privkey
   previous_key: null
@@ -78,7 +77,7 @@ acmebot_default_directories:
   chain: /etc/ssl/acmebot/chain  # maybe null
   param: /etc/ssl/acmebot/params  # maybe null
   challenge: /etc/ssl/acmebot/challenges  # for dns-01 only
-  http_challenge: /var/www/acme-challenge  # maybe null
+  http_challenge: "/var/run/acme/acme-challenge"  # maybe null
   hpkp: /etc/ssl/acmebot/hpkp  # maybe null
   ocsp: /etc/ssl/acmebot/ocsp  # maybe null
   sct: "/etc/ssl/acmebot/scts/{name}/{key_type}"  # maybe null
@@ -90,13 +89,12 @@ acmebot_file_names: {}
 acmebot_default_file_names:
   log: "acmebot.log"
 
-  # TODO layout equivalent to acmetool
-  private_key: "{name}{suffix}.key"
-  backup_key: "{name}_backup{suffix}.key"
-  previous_key: "{name}_previous{suffix}.key"
-  full_key: "{name}_full{suffix}.key"
+  private_key: "{name}{suffix}.pem"
+  backup_key: "{name}_backup{suffix}.pem"
+  previous_key: "{name}_previous{suffix}.pem"
+  full_key: "{name}_full{suffix}.pem"
   certificate: "{name}{suffix}.pem"
-  full_certificate: "{name}+root{suffix}.pem"
+  full_certificate: "{name}{suffix}.pem"
   chain: "{name}_chain{suffix}.pem"
   param: "{name}_param.pem"
   challenge: "{name}"
diff --git a/acmebot/files/acmebot.service b/acmebot/files/acmebot.service
new file mode 100644
index 0000000..8ba466a
--- /dev/null
+++ b/acmebot/files/acmebot.service
@@ -0,0 +1,26 @@
+[Unit]
+Description=Reconcile Let's Encrypt certificates
+Documentation=file:/usr/share/doc/acmebot/README.rst.gz
+After=nss-lookup.target
+After=apache2.service nginx.service bind9.service nginx-proxy.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/sbin/acmebot --accept
+TimeoutStartSec=5min
+CapabilityBoundingSet=CAP_CHOWN
+NoNewPrivileges=yes
+PrivateTmp=yes
+PrivateDevices=yes
+ProtectSystem=strict
+ReadWritePaths=/etc/ssl
+ConfigurationDirectory=acmebot
+RuntimeDirectory=acmebot acme/acme-challenge
+StateDirectory=acmebot
+LogsDirectory=acmebot
+ProtectHome=yes
+ProtectKernelTunables=yes
+ProtectControlGroups=yes
+RestrictRealtime=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+
diff --git a/acmebot/files/acmebot.timer b/acmebot/files/acmebot.timer
new file mode 100644
index 0000000..02c80b1
--- /dev/null
+++ b/acmebot/files/acmebot.timer
@@ -0,0 +1,11 @@
+[Unit]
+Description=Reconcile Let's Encrypt certificates twice daily
+
+[Timer]
+OnCalendar=*-*-* 00,12:00:00
+RandomizedDelaySec=1h
+Persistent=yes
+
+[Install]
+WantedBy=timers.target
+
diff --git a/acmebot/files/service-after.conf b/acmebot/files/service-after.conf
deleted file mode 100644
index a54ec72..0000000
--- a/acmebot/files/service-after.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-[Unit]
-After=nginx-proxy.service
diff --git a/acmebot/tasks/main.yml b/acmebot/tasks/main.yml
index 5cb2fcb..dfb7b45 100644
--- a/acmebot/tasks/main.yml
+++ b/acmebot/tasks/main.yml
@@ -1,40 +1,53 @@
 ---
-# TODO import account info from acmetool if present
 
-- name: ensure acmebot is installed
+- name: ensure requirements for acmebot are installed
   apt:
-    name: acmebot
+    name:
+      - python3-appdirs
+      - python3-pyparsing
+      - python3-packaging
+      - python3-openssl
+      - python3-dns
+      - python3-cryptography
+      - python3-asn1crypto
+      - python3-acme
+      - python3-yaml
     state: present
 
-- name: ensure we can modify the systemd unit
+- name: get the acmebot repository
+  git:
+    repo: https://github.com/plinss/acmebot.git
+    dest: /opt/acmebot
+    version: "{{acmebot_version}}"
+  environment:
+    TMPDIR: /root/.ansible/tmp
+
+- name: add acmebot to path
   file:
-    path: /etc/systemd/system/acmebot.service.d
-    state: directory
-    owner: root
-    group: root
-    mode: '0755'
-  notify:
-    - reload systemd service files
-  when: acmebot_after_nginx_proxy
+    src: /opt/acmebot/acmebot
+    dest: /usr/local/sbin/acmebot
+    state: link
 
-- name: ensure systemd waits for proxy service
+- name: install systemd units
   copy:
-    src: service-after.conf
-    dest: /etc/systemd/system/acmebot.service.d/nginx-proxy.conf
+    src: "{{item}}"
+    dest: /etc/systemd/system/
     owner: root
     group: root
     mode: '0644'
+  with_items:
+    - "acmebot.service"
+    - "acmebot.timer"
   notify:
     - reload systemd service files
-  when: acmebot_after_nginx_proxy
 
-- name: ensure systemd does not wait for proxy service
+- name: create the acmebot config directory
   file:
-    path: /etc/systemd/system/acmebot.service.d/nginx-proxy.conf
-    state: absent
-  notify:
-    - reload systemd service files
-  when: not acmebot_after_nginx_proxy
+    path: /etc/acmebot
+    state: directory
+    owner: root
+    group: root
+    mode: '0755'
 
 - name: ensure the acmebot is configured
   template:
@@ -57,27 +70,28 @@
   notify:
     - update certificates
 
-# TODO initial run accepting TOS
-- name: check if acmebot is configured
-  command: acmetool status
-  register: acmetool_status
-  changed_when: false
-- name: initially configure acmebot
-  command: acmebot --detail
-  when: not acmetool_status.stdout is search(acmetool_endpoint)
-
-# TODO force run when cert store does not match configured certificates
-- name: test if the desired certificates are present
-  stat:
-    path: "/var/lib/acme/live/{{item.hostnames[0]}}"
-  register: live_stat
-  changed_when: not live_stat.stat.exists
-  with_items: "{{acmetool_certificates}}"
-  notify:
-    - update certificates
-
 - name: ensure certificates are updated regularly
   systemd:
     name: acmebot.timer
     enabled: true
     state: started
+
+- name: check for updates daily
+  file:
+    src: /opt/acmebot/update-check.sh
+    dest: /etc/cron.daily/acmebot-update-check.sH
+    state: link
+  when: acmebot_enable_update_check
+
+- name: don't check for updates daily
+  file:
+    path: /etc/cron.daily/acmebot-update-check.sh
+    state: absent
+  when: not acmebot_enable_update_check
+
+- name: rotate acmebot logs
+  file:
+    src: /opt/acmebot/logrotate.d/acmebot
+    dest: /etc/logrotate.d/acmebot
+    state: link
+    
diff --git a/webserver/templates/ssl-certificate b/webserver/templates/ssl-certificate
index 87bcc8a..5ddb5e2 100644
--- a/webserver/templates/ssl-certificate
+++ b/webserver/templates/ssl-certificate
@@ -1,6 +1,6 @@
-    ssl_certificate {{server.certificate|default("/var/lib/acme/live/" + server.server_name + "/fullchain")}};
-    ssl_trusted_certificate {{server.certificate|default("/var/lib/acme/live/" + server.server_name + "/fullchain")}};
-    ssl_certificate_key {{server.private_key|default("/var/lib/acme/live/" + server.server_name + "/privkey")}};
+    ssl_certificate {{server.certificate|default("/etc/ssl/acmebot/cert/" + server.server_name + ".pem")}};
+    ssl_trusted_certificate {{server.certificate|default("/etc/ssl/acmebot/cert/" + server.server_name + ".pem")}};
+    ssl_certificate_key {{server.private_key|default("/etc/ssl/acmebot/privkey/" + server.server_name + ".pem")}};
 
     {% set strength = server.cipher_strength|default(cipher_strength) %}
     ssl_protocols {{protocols[strength]}};
-- 
GitLab