Browse Source

add sslletsencrypt and sslselfsigned roles for internal servers

Thomas Buck 2 years ago
parent
commit
37dd16fb67

+ 1
- 0
.gitignore View File

@@ -2,3 +2,4 @@
2 2
 secret
3 3
 *.pyc
4 4
 site.retry
5
+.directory

+ 7
- 0
README.md View File

@@ -84,6 +84,13 @@ Authorize your ssh key if you want passwordless ssh login (optional):
84 84
     nano /home/deploy/.ssh/authorized_keys
85 85
     chmod 400 /home/deploy/.ssh/authorized_keys
86 86
     chown deploy:deploy /home/deploy -R
87
+
88
+Or, in short:
89
+
90
+    ssh-copy-id -i ~/.ssh/id_ecdsa deploy@hostname
91
+
92
+Also, enable passwordless sudo for the deploy user:
93
+
87 94
     echo 'deploy ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/deploy
88 95
 
89 96
 Your new account will be automatically set up for passwordless `sudo`.

+ 1
- 0
roles/common/defaults/main.yml View File

@@ -1,6 +1,7 @@
1 1
 common_timezone: 'Etc/UTC'
2 2
 admin_email: "{{ main_user_name }}@{{ domain }}"
3 3
 main_user_shell: "/bin/bash"
4
+server_hostname: "{{ server_fqdn }}"
4 5
 friendly_networks:
5 6
   - ""
6 7
 

+ 1
- 3
roles/common/tasks/main.yml View File

@@ -1,7 +1,7 @@
1 1
 ---
2 2
 
3 3
 - name: Set hostname
4
-  hostname: name="{{ server_fqdn }}"
4
+  hostname: name="{{ server_hostname }}"
5 5
 
6 6
 - name: Replace /etc/hosts
7 7
   template: src=etc_hosts.j2 dest=/etc/hosts
@@ -83,8 +83,6 @@
83 83
 
84 84
 - include: users.yml tags=users
85 85
 - include: apache.yml tags=apache
86
-- include: ssl.yml tags=ssl
87
-- include: letsencrypt.yml tags=letsencrypt
88 86
 - include: ufw.yml tags=ufw
89 87
 - include: security.yml tags=security
90 88
 - include: ntp.yml tags=ntp

+ 0
- 1
roles/common/tasks/ufw.yml View File

@@ -24,7 +24,6 @@
24 24
   ufw: rule=allow port={{ item }} proto=tcp
25 25
   with_items:
26 26
     - http
27
-    - https
28 27
     - ssh
29 28
   tags: ufw
30 29
 

+ 18
- 0
roles/sslletsencrypt/DESIGN.md View File

@@ -0,0 +1,18 @@
1
+# Design Description for Common-SSL Role
2
+
3
+## Let's Encrypt Support
4
+
5
+[Let's Encrypt](https://letsencrypt.org) (LE) is an automated certificate authority that provides free SSL certificates that are trusted by all major browsers.  LE certificates are used by Sovereign instead of purchased certificates from authorities like RapidSSL in order to reduce the out-of-pocket cost of deploying Sovereign and avoid end-user problems with self-signed certificates.
6
+
7
+### Design approach
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.
10
+
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
+
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.
14
+
15
+Certificate renewal is done automatically using cron. The cron script must be aware of private key copies and update them as well. Services that depend on new keys must also be bounced. It is up to roles that rely on keys to modify the cron script (preferably using `lineinfile` or something similar) to accomplish this.
16
+
17
+If you changed something that requires new domains or subdomains to be considered when generating the certificates, do not just delete the files in /etc/letsencrypt/live!
18
+Instead, use /root/letsencrypt/letsencrypt-auto delete to remove the old certificates and then re-run the common role in this playbook.

+ 29
- 0
roles/sslletsencrypt/defaults/main.yml View File

@@ -0,0 +1,29 @@
1
+common_timezone: 'Etc/UTC'
2
+admin_email: "{{ main_user_name }}@{{ domain }}"
3
+main_user_shell: "/bin/bash"
4
+friendly_networks:
5
+  - ""
6
+
7
+# pass
8
+secret_root: '{{ inventory_dir | realpath }}'
9
+secret_name: 'secret'
10
+secret: '{{ secret_root + "/" + secret_name }}'
11
+
12
+db_admin_username: 'postgres'
13
+db_admin_password: "{{ lookup('password', secret + '/' + 'db_admin_password length=32') }}"
14
+
15
+# let's encrypt
16
+letsencrypt_server: "https://acme-v02.api.letsencrypt.org/directory"
17
+
18
+# ssh
19
+# Following https://infosec.mozilla.org/guidelines/openssh
20
+kex_algorithms: "curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256"
21
+ciphers: "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
22
+macs: "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com"
23
+
24
+# ntp
25
+ntp_servers:
26
+  - 0.pool.ntp.org
27
+  - 1.pool.ntp.org
28
+  - 2.pool.ntp.org
29
+  - 3.pool.ntp.org

roles/common/files/etc_cron-daily_letsencrypt-renew → roles/sslletsencrypt/files/etc_cron-daily_letsencrypt-renew View File


roles/common/files/letsencrypt-gencert → roles/sslletsencrypt/files/letsencrypt-gencert View File

@@ -17,7 +17,7 @@ for domain in "$@"; do
17 17
   fi
18 18
 
19 19
   # subdomains - www.foo.com mail.foo.com ...
20
-  for sub in www mail autoconfig stats news cloud git matrix status social comments iot; do
20
+  for sub in eddie www mail autoconfig stats news cloud git matrix status social comments iot; do
21 21
     # only add if the DNS entry for the subdomain does actually exist
22 22
     if (getent hosts $sub.$domain > /dev/null); then
23 23
       if [ -z "$d" ]; then

+ 5
- 0
roles/sslletsencrypt/handlers/main.yml View File

@@ -0,0 +1,5 @@
1
+---
2
+# Defines handlers applicable across all machines in the infrastructure.
3
+
4
+- name: restart apache
5
+  service: name=apache2 state=restarted

roles/common/tasks/letsencrypt.yml → roles/sslletsencrypt/tasks/letsencrypt.yml View File


+ 5
- 0
roles/sslletsencrypt/tasks/main.yml View File

@@ -0,0 +1,5 @@
1
+---
2
+
3
+- include: ssl.yml tags=ssl
4
+- include: letsencrypt.yml tags=letsencrypt
5
+- include: ufw.yml tags=ufw

roles/common/tasks/ssl.yml → roles/sslletsencrypt/tasks/ssl.yml View File


+ 7
- 0
roles/sslletsencrypt/tasks/ufw.yml View File

@@ -0,0 +1,7 @@
1
+---
2
+
3
+- name: Set firewall rules for SSL web traffic
4
+  ufw: rule=allow port={{ item }} proto=tcp
5
+  with_items:
6
+    - https
7
+  tags: ufw

roles/common/templates/etc_apache2_conf-available_ssl.conf.j2 → roles/sslletsencrypt/templates/etc_apache2_conf-available_ssl.conf.j2 View File


roles/common/templates/etc_letsencrypt_cli.conf.j2 → roles/sslletsencrypt/templates/etc_letsencrypt_cli.conf.j2 View File


+ 19
- 0
roles/sslselfsigned/defaults/main.yml View File

@@ -0,0 +1,19 @@
1
+common_timezone: 'Etc/UTC'
2
+admin_email: "{{ main_user_name }}@{{ domain }}"
3
+main_user_shell: "/bin/bash"
4
+friendly_networks:
5
+  - ""
6
+
7
+# pass
8
+secret_root: '{{ inventory_dir | realpath }}'
9
+secret_name: 'secret'
10
+secret: '{{ secret_root + "/" + secret_name }}'
11
+
12
+db_admin_username: 'postgres'
13
+db_admin_password: "{{ lookup('password', secret + '/' + 'db_admin_password length=32') }}"
14
+
15
+# ssh
16
+# Following https://infosec.mozilla.org/guidelines/openssh
17
+kex_algorithms: "curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256"
18
+ciphers: "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
19
+macs: "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com"

+ 5
- 0
roles/sslselfsigned/handlers/main.yml View File

@@ -0,0 +1,5 @@
1
+---
2
+# Defines handlers applicable across all machines in the infrastructure.
3
+
4
+- name: restart apache
5
+  service: name=apache2 state=restarted

+ 5
- 0
roles/sslselfsigned/tasks/main.yml View File

@@ -0,0 +1,5 @@
1
+---
2
+
3
+- include: ssl.yml tags=ssl
4
+- include: selfsigned.yml
5
+- include: ufw.yml tags=ufw

+ 42
- 0
roles/sslselfsigned/tasks/selfsigned.yml View File

@@ -0,0 +1,42 @@
1
+
2
+- name: Install Self Signed Cert stuff
3
+  apt:
4
+    name: "{{ packages }}"
5
+    state: present
6
+  vars:
7
+    packages:
8
+    - openssl
9
+  tags:
10
+    - dependencies
11
+
12
+- name: Add group name ssl-cert for SSL certificates
13
+  group:
14
+    name: ssl-cert
15
+    state: present
16
+
17
+- name: Create directory for certificates
18
+  file: state=directory path=/etc/letsencrypt group=root owner=root
19
+
20
+- name: Create live directory for certificates
21
+  file: state=directory path=/etc/letsencrypt/live/{{ domain }} group=ssl-cert owner=root
22
+
23
+- name: Add script for cert creation
24
+  template:
25
+    src=home_deploy_ssl-self-signed.sh.j2
26
+    dest=/home/deploy/ssl-self-signed.sh
27
+    owner=deploy
28
+    group=deploy
29
+    mode=755
30
+
31
+- name: Create self signed certificates
32
+  command:
33
+    cmd: /home/deploy/ssl-self-signed.sh
34
+  notify: restart apache
35
+
36
+- name: Modify permissions to allow ssl-cert group access to live
37
+  file: path=/etc/letsencrypt/live owner=root group=ssl-cert mode=0750 recurse=yes
38
+
39
+- name: Retrieve the self signing CA to remove warning in users browser
40
+  fetch: src=/etc/letsencrypt/live/fritz.box/chain.pem
41
+         dest="{{ secret }}/sovereign-self-signed-cert"
42
+         fail_on_missing=yes

+ 23
- 0
roles/sslselfsigned/tasks/ssl.yml View File

@@ -0,0 +1,23 @@
1
+- name: Create strong Diffie-Hellman group
2
+  command: openssl dhparam -out /etc/ssl/private/dhparam2048.pem 2048
3
+    creates=/etc/ssl/private/dhparam2048.pem
4
+
5
+- name: Enable Apache SSL module
6
+  command: a2enmod ssl creates=/etc/apache2/mods-enabled/ssl.load
7
+  notify: restart apache
8
+
9
+- name: Enable Apache SOCACHE_SHMCB module for the SSL stapling cache
10
+  command: a2enmod socache_shmcb
11
+    creates=/etc/apache2/mods-enabled/socache_shmcb.load
12
+  notify: restart apache
13
+
14
+- name: Add common Apache SSL config
15
+  template: src=etc_apache2_conf-available_ssl.conf.j2
16
+    dest=/etc/apache2/conf-available/ssl.conf
17
+    owner=root
18
+    group=root
19
+  notify: restart apache
20
+
21
+- name: Enable Apache SSL config
22
+  command: a2enconf ssl creates=/etc/apache2/conf-enabled/ssl.conf
23
+  notify: restart apache

+ 7
- 0
roles/sslselfsigned/tasks/ufw.yml View File

@@ -0,0 +1,7 @@
1
+---
2
+
3
+- name: Set firewall rules for SSL web traffic
4
+  ufw: rule=allow port={{ item }} proto=tcp
5
+  with_items:
6
+    - https
7
+  tags: ufw

+ 14
- 0
roles/sslselfsigned/templates/etc_apache2_conf-available_ssl.conf.j2 View File

@@ -0,0 +1,14 @@
1
+SSLProtocol ALL -SSLv2 -SSLv3
2
+SSLHonorCipherOrder On
3
+SSLCompression off
4
+SSLUseStapling On
5
+SSLStaplingCache shmcb:${APACHE_RUN_DIR}/stapling_cache(128000)
6
+SSLStaplingResponderTimeout 5
7
+SSLStaplingReturnResponderErrors off
8
+
9
+SSLCertificateKeyFile	/etc/letsencrypt/live/{{ domain }}/privkey.pem
10
+SSLCertificateFile	/etc/letsencrypt/live/{{ domain }}/fullchain.pem
11
+
12
+SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
13
+
14
+Header add Strict-Transport-Security "max-age=15768000; includeSubdomains"

+ 35
- 0
roles/sslselfsigned/templates/home_deploy_ssl-self-signed.sh.j2 View File

@@ -0,0 +1,35 @@
1
+#!/bin/bash
2
+
3
+echo generating CA key
4
+openssl genrsa -out /etc/letsencrypt/rootCA.key 4096
5
+
6
+echo generating CA certificate
7
+openssl req -x509 -new -nodes -sha256 -days 7300 \
8
+    -key /etc/letsencrypt/rootCA.key \
9
+    -subj "/C=DE/ST=BW/O={{ domain }}/CN={{ domain }}" \
10
+    -out /etc/letsencrypt/rootCA.crt
11
+
12
+echo generating server key
13
+openssl genrsa -out /etc/letsencrypt/{{ domain }}.key 2048
14
+
15
+echo generating signing request
16
+openssl req -new -sha256 \
17
+    -key /etc/letsencrypt/{{ domain }}.key \
18
+    -subj "/C=DE/ST=BW/O={{ domain }}/CN=*.{{ domain }}" \
19
+    -out /etc/letsencrypt/{{ domain }}.csr
20
+
21
+echo generating server certificate
22
+openssl x509 -req -CAcreateserial -days 7300 -sha256 \
23
+    -in /etc/letsencrypt/{{ domain }}.csr \
24
+    -CA /etc/letsencrypt/rootCA.crt \
25
+    -CAkey /etc/letsencrypt/rootCA.key \
26
+    -out /etc/letsencrypt/{{ domain }}.crt
27
+
28
+echo copy to proper locations
29
+cp /etc/letsencrypt/{{ domain }}.key /etc/letsencrypt/live/{{ domain }}/privkey.pem
30
+cp /etc/letsencrypt/rootCA.crt /etc/letsencrypt/live/{{ domain }}/chain.pem
31
+cp /etc/letsencrypt/{{ domain }}.crt /etc/letsencrypt/live/{{ domain }}/cert.pem
32
+
33
+echo generate full chain certificate
34
+cat /etc/letsencrypt/live/{{ domain }}/cert.pem > /etc/letsencrypt/live/{{ domain }}/fullchain.pem
35
+cat /etc/letsencrypt/live/{{ domain }}/chain.pem >> /etc/letsencrypt/live/{{ domain }}/fullchain.pem

+ 1
- 0
site.yml View File

@@ -9,6 +9,7 @@
9 9
   # This is what I'm using on my minimal web & mail server
10 10
   roles:
11 11
     - common
12
+    - sslletsencrypt
12 13
     - blog
13 14
     - mailserver
14 15
     - webmail

Loading…
Cancel
Save