Browse Source

Determine registered subdomains at deploy-time for LE

Mike Ashley 8 years ago
parent
commit
bc5bfa4b21
4 changed files with 11 additions and 26 deletions
  1. 2
    24
      roles/common/DESIGN.md
  2. 8
    0
      roles/common/files/gencert
  3. 1
    1
      roles/common/tasks/letsencrypt.yml
  4. 0
    1
      vars/defaults.yml

+ 2
- 24
roles/common/DESIGN.md View File

8
 
8
 
9
 The Let's Encrypt service uses DNS to look up domains being registered and then contact the client to verify. For this to work, DNS records must be configured before the playbook is run the first time.
9
 The Let's Encrypt service uses DNS to look up domains being registered and then contact the client to verify. For this to work, DNS records must be configured before the playbook is run the first time.
10
 
10
 
11
-A single certificate is created using Let's Encrypt with SANs used for the subdomains. The user must configure the list of subdomains to register in `vars/user.yml` unless they are installing all services, i.e., the default list of subdomains is everything.
11
+A single certificate is created using Let's Encrypt with SANs used for the subdomains.  At deploy-time, a script is used to query DNS for known subdomains, build a list of the subset that is registered, and use it when making the certificate request of Let's Encrypt.
12
 
12
 
13
-The role is designed to fail if a certificate cannot be generated for all subdomains listed.  This catches DNS configuration errors where a subdomain should have a record but does not.  Errors in the other direction (not all subdomains are listed in the SANs) can be addressed after detection by fixing the configuration and rerunning the role.
14
-
15
-Several packages need access to the private key. Not all are run as root. Examples include Prosody (XMPP) and ZNC (IRC bouncer). The approach in these cases is to copy the certificates and manage ownership and mode for them separately. This is to avoid stomping on directory ownership and modes in /etc/letsencrypt.
13
+Several packages need access to the private key. Not all are run as root. An example is Prosody (XMPP). Such users are added to the ssl-cert group, and /etc/letsencrypt is set up to allow keys to be read by ssl-cert.
16
 
14
 
17
 Certificates and private keys are backed up using tarsnap.
15
 Certificates and private keys are backed up using tarsnap.
18
 
16
 
24
 
22
 
25
 ### Alternative approaches
23
 ### Alternative approaches
26
 
24
 
27
-Two other approaches were considered.
28
-
29
-#### One certificate per domain
30
-
31
 Another way to generate certificates is to generate one certificate per domain and expect each module that uses a subdomain to generate its own certificate for the subdomain.
25
 Another way to generate certificates is to generate one certificate per domain and expect each module that uses a subdomain to generate its own certificate for the subdomain.
32
 
26
 
33
 This was prototyped. The common role included a parameterized task list that could be invoked by modules that needed to generate a key. The certificate renewal script run by cron could be modified to update all the certificates in the `live` directory.
27
 This was prototyped. The common role included a parameterized task list that could be invoked by modules that needed to generate a key. The certificate renewal script run by cron could be modified to update all the certificates in the `live` directory.
34
 
28
 
35
 This approach was rejected due to complexity. This would have been the first time modules needed to invoke a task list from another module. Managing multiple certificates is also more complicated.
29
 This approach was rejected due to complexity. This would have been the first time modules needed to invoke a task list from another module. Managing multiple certificates is also more complicated.
36
-
37
-#### Not requiring the user to list subdomains in vars/user.yml
38
-
39
-It would be desirable if the user did not have to list the subdomains used in `vars/user.yml`. This introduces an opportunity for the subdomain list to not match what is configured in DNS and the list of roles. Three pieces of information have to be coordinated instead of two.
40
-
41
-One approach to avoiding the subdomains variable looks like this.
42
-
43
-1. Install a wildcard certificate in the Lets Encrypt folder when the common role runs.  This would be sufficient for services to get off the ground as the playbook is executed.
44
-2. As modules run, they register subdomains they need in a variable.
45
-3. The last module run is a `letsencrypt` module that uses the registration variable to generate the real certificate with SANs and then bounce services using the same script cron will need to bounce services on certificate renewal.
46
-
47
-The whole thing becomes a bootstrapping process.
48
-
49
-This approach was not prototyped. It was rejected since the `letsencrypt` role would not be idempotent. Furthermore, in order to run at all, the entire playbook would need to be run.
50
-
51
-Asking the user to list subdomains in `vars/user.yml` is probably ok.  The user must preconfigure their DNS records before running the playbook so that Let's Encrypt can verify domains.  Therefore, the user is going to know what subdomains they are using before the first run of the playbook.

+ 8
- 0
roles/common/files/gencert View File

1
+#!/bin/bash
2
+d="$1"
3
+for i in www mail autoconfig read news cloud git; do
4
+  if (getent hosts $i.$1 > /dev/null); then
5
+    d="$d,$i.$1";
6
+  fi
7
+done
8
+/root/letsencrypt/letsencrypt-auto certonly -c /etc/letsencrypt/cli.conf --domains $d

+ 1
- 1
roles/common/tasks/letsencrypt.yml View File

31
   service: name=apache2 state=stopped
31
   service: name=apache2 state=stopped
32
 
32
 
33
 - name: Get an SSL certificate for {{ domain }} from Let's Encrypt
33
 - name: Get an SSL certificate for {{ domain }} from Let's Encrypt
34
-  command: /root/letsencrypt/letsencrypt-auto certonly -c /etc/letsencrypt/cli.conf --domains {{ domain }},{{ subdomains }}
34
+  script: gencert {{ domain }}
35
   args:
35
   args:
36
     creates: /etc/letsencrypt/live/{{ domain }}/privkey.pem
36
     creates: /etc/letsencrypt/live/{{ domain }}/privkey.pem
37
   when: ansible_ssh_user != "vagrant"
37
   when: ansible_ssh_user != "vagrant"

+ 0
- 1
vars/defaults.yml View File

14
 friendly_networks:
14
 friendly_networks:
15
   - ""
15
   - ""
16
 letsencrypt_server: "https://acme-v01.api.letsencrypt.org/directory"
16
 letsencrypt_server: "https://acme-v01.api.letsencrypt.org/directory"
17
-subdomains: "www.{{ domain }},mail.{{ domain }},autoconfig.{{ domain }},read.{{ domain }},news.{{ domain }},cloud.{{ domain }},git.{{ domain }}"
18
 
17
 
19
 # ssh
18
 # ssh
20
 kex_algorithms: "diffie-hellman-group-exchange-sha256"
19
 kex_algorithms: "diffie-hellman-group-exchange-sha256"

Loading…
Cancel
Save