Merge branch 'master' of ssh://git-ssh.notandy.de:2222/ansible/roles/certificates
This commit is contained in:
commit
5e931d8f41
9 changed files with 179 additions and 23 deletions
21
README.md
21
README.md
|
|
@ -74,14 +74,21 @@ backend_override: {}
|
||||||
# days of validity left on a certificate bevore it is renewed
|
# days of validity left on a certificate bevore it is renewed
|
||||||
remainingdays: 28
|
remainingdays: 28
|
||||||
|
|
||||||
# challange type to use, can be:
|
# challenge type to use, can be:
|
||||||
# 'dns-01': use the dns challange and a custom power dns backend
|
# 'dns-01': use the dns challenge and a custom powerdns backend
|
||||||
# 'dns-01-manual': use the dns challange and manualy set the dns record
|
# 'dns-01-manual': use the dns challenge and manualy set the dns record
|
||||||
# 'http-01: use the http challange and deploy the challanges to a webserver
|
# 'http-01: use the http challenge and deploy the challenges to a webserver
|
||||||
challange: dns-01
|
challenge: dns-01
|
||||||
|
|
||||||
# servers to deploy a challange to
|
# servers to deploy a challenge to
|
||||||
challangeserver: []
|
challengeserver: []
|
||||||
|
|
||||||
|
# Automaticly renew certificates using a cronjob
|
||||||
|
# Only supports the following cases:
|
||||||
|
# * 'dns-01' challenge with the custom powerdns backend
|
||||||
|
# This setting musst be set the first time the certificate is requested, it can not be enabled later without first deleting the certificates.
|
||||||
|
# Requires a working mail setup with some sort of sendmail binary to send warnings if a certificate can not be renewed.
|
||||||
|
autorenew: False
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Selfsigned
|
#### Selfsigned
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ certificates:
|
||||||
backends:
|
backends:
|
||||||
letsencrypt:
|
letsencrypt:
|
||||||
remainingdays: 28
|
remainingdays: 28
|
||||||
challange: dns-01
|
challenge: dns-01
|
||||||
challangeserver: []
|
challengeserver: []
|
||||||
|
autorenew: False
|
||||||
selfsigned:
|
selfsigned:
|
||||||
not_after: "+3650d"
|
not_after: "+3650d"
|
||||||
ownca:
|
ownca:
|
||||||
|
|
|
||||||
5
files/letsencrypt_deploy_challenge.sh
Executable file
5
files/letsencrypt_deploy_challenge.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
for i in $LETSENCRYPT_CHALLENGE_SERVERS; do
|
||||||
|
ssh -i /etc/letsencrypt/renewkey -o "StrictHostKeyChecking no" letsencrypt@$i $(< $LETSENCRYPT_TOKEN ) $1 $2
|
||||||
|
done
|
||||||
30
files/letsencrypt_renew.sh
Executable file
30
files/letsencrypt_renew.sh
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source $1
|
||||||
|
|
||||||
|
daysleft=$(/usr/local/bin/acme-primitives.py remaining_days "$LETSENCRYPT_CRT" || echo "0") 2>/dev/null
|
||||||
|
[ "$daysleft" -lt "$LETSENCRYPT_REMAININGDAYS" ] || exit 0
|
||||||
|
|
||||||
|
folder="$(mktemp -d)"
|
||||||
|
cd "$folder"
|
||||||
|
/usr/local/bin/acme-primitives.py get_cert --directory 'https://acme-v02.api.letsencrypt.org/directory' --acc /etc/ssl/letsencrypt_account.key --csr $LETSENCRYPT_CSR /usr/local/bin/letsencrypt_deploy_challenge.sh > chained.pem
|
||||||
|
|
||||||
|
cat chained.pem "$LETSENCRYPT_KEY" > full.pem
|
||||||
|
openssl x509 -in chained.pem > cert.pem
|
||||||
|
|
||||||
|
chown -R root:ssl-cert .
|
||||||
|
chmod 0644 chained.pem
|
||||||
|
chmod 0644 cert.pem
|
||||||
|
chmod 0640 full.pem
|
||||||
|
|
||||||
|
mv chained.pem "$LETSENCRYPT_CHAIN"
|
||||||
|
mv cert.pem "$LETSENCRYPT_CRT"
|
||||||
|
mv full.pem "$LETSENCRYPT_FULL"
|
||||||
|
|
||||||
|
cd
|
||||||
|
rm -r "$folder"
|
||||||
|
|
||||||
|
for i in $LETSENCRYPT_SERVICES; do
|
||||||
|
/bin/systemctl "$i" restart
|
||||||
|
done
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
- include_tasks: common_cert.yml
|
- include_tasks: common_cert.yml
|
||||||
|
|
||||||
- set_fact:
|
- set_fact:
|
||||||
external_challange_type: "{{ map_challange_type_letsencrypt[cert_backend.challange]|d(cert_backend.challange) }}"
|
external_challenge_type: "{{ map_challenge_type_letsencrypt[cert_backend.challenge]|d(cert_backend.challenge) }}"
|
||||||
|
|
||||||
- name: "get challange for {{ certname }}"
|
- name: "get challenge for {{ certname }}"
|
||||||
acme_certificate: &acmetask
|
acme_certificate: &acmetask
|
||||||
force: "{{ task_generate_csr is changed }}"
|
force: "{{ task_generate_csr is changed }}"
|
||||||
acme_version: 2
|
acme_version: 2
|
||||||
|
|
@ -14,43 +14,94 @@
|
||||||
dest: "{{ cert.certpath }}"
|
dest: "{{ cert.certpath }}"
|
||||||
fullchain_dest: "{{ cert.chainpath }}"
|
fullchain_dest: "{{ cert.chainpath }}"
|
||||||
remaining_days: "{{ cert_backend.remainingdays }}"
|
remaining_days: "{{ cert_backend.remainingdays }}"
|
||||||
challenge: "{{ external_challange_type }}"
|
challenge: "{{ external_challenge_type }}"
|
||||||
deactivate_authzs: yes
|
deactivate_authzs: yes
|
||||||
register: challenge
|
register: challenge
|
||||||
|
|
||||||
- name: "setup challenge server for {{ certname }} (dns challange)"
|
- name: "setup autorenew for {{ certname }} (dns challenge)"
|
||||||
|
when:
|
||||||
|
- cert_backend.autorenew
|
||||||
|
- cert_backend.challenge == "dns-01"
|
||||||
|
block:
|
||||||
|
- name: create token
|
||||||
|
copy:
|
||||||
|
dest: "/etc/letsencrypt/cert_{{ certname }}.token"
|
||||||
|
mode: 0640
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
content: "{{ lookup('password', '/dev/null length=128 chars=ascii_letters,digits,hexdigits') }}"
|
||||||
|
force: no
|
||||||
|
- name: slurp up token
|
||||||
|
slurp:
|
||||||
|
src: "/etc/letsencrypt/cert_{{ certname }}.token"
|
||||||
|
register: tokenfile
|
||||||
|
- name: add renew ssh key to backend server
|
||||||
|
delegate_to: "{{ item }}"
|
||||||
|
loop: "{{ cert_backend.challengeserver }}"
|
||||||
|
authorized_key:
|
||||||
|
user: letsencrypt
|
||||||
|
key: "{{ letsencrypt_renewkey.public_key }}"
|
||||||
|
- name: add server token to record whitelist on backend server
|
||||||
|
when:
|
||||||
|
- challenge is changed
|
||||||
|
delegate_to: "{{ item.0 }}"
|
||||||
|
loop: "{{ cert_backend.challengeserver|product(challenge.challenge_data.keys()|list)|list }}"
|
||||||
|
command:
|
||||||
|
argv:
|
||||||
|
- "/usr/local/bin/pdns.py"
|
||||||
|
- "add_token"
|
||||||
|
- "--"
|
||||||
|
- "{{ tokenfile.content | b64decode }}"
|
||||||
|
- "{{ challenge.challenge_data[item.1]['dns-01'].record }}"
|
||||||
|
- name: create cert renew config
|
||||||
|
template:
|
||||||
|
src: letsencrypt_renew_config.j2
|
||||||
|
dest: "/etc/letsencrypt/renew_{{ certname }}.config.sh"
|
||||||
|
mode: 0750
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
- name: setup renew cronjob
|
||||||
|
cron:
|
||||||
|
job: "/usr/local/bin/letsencrypt_renew.sh /etc/letsencrypt/renew_{{ certname }}.config.sh"
|
||||||
|
name: "letsencrypt: renew {{ certname }}"
|
||||||
|
hour: "{{ 23 | random(seed=inventory_hostname + certname + 'renew') }}"
|
||||||
|
minute: "{{ 59 | random(seed=inventory_hostname + certname + 'renew') }}"
|
||||||
|
|
||||||
|
- name: "setup challenge server for {{ certname }} (dns challenge)"
|
||||||
when:
|
when:
|
||||||
- challenge is changed
|
- challenge is changed
|
||||||
- cert_backend.challange == "dns-01"
|
- cert_backend.challenge == "dns-01"
|
||||||
delegate_to: "{{ item.0 }}"
|
delegate_to: "{{ item.0 }}"
|
||||||
loop: "{{ cert_backend.challangeserver|product(challenge.challenge_data.keys()|list)|list }}"
|
loop: "{{ cert_backend.challengeserver|product(challenge.challenge_data.keys()|list)|list }}"
|
||||||
command:
|
command:
|
||||||
argv:
|
argv:
|
||||||
- "/usr/local/bin/pdns.py"
|
- "/usr/local/bin/pdns.py"
|
||||||
|
- "add_challenge"
|
||||||
|
- "--"
|
||||||
- "{{ challenge.challenge_data[item.1]['dns-01'].record }}"
|
- "{{ challenge.challenge_data[item.1]['dns-01'].record }}"
|
||||||
- "{{ challenge.challenge_data[item.1]['dns-01'].resource_value }}"
|
- "{{ challenge.challenge_data[item.1]['dns-01'].resource_value }}"
|
||||||
|
|
||||||
- name: "setup challenge server for {{ certname }} (manual dns challange)"
|
- name: "setup challenge server for {{ certname }} (manual dns challenge)"
|
||||||
when:
|
when:
|
||||||
- challenge is changed
|
- challenge is changed
|
||||||
- cert_backend.challange == "dns-01-manual"
|
- cert_backend.challenge == "dns-01-manual"
|
||||||
loop: "{{ challenge.challenge_data_dns|d({})|dict2items }}"
|
loop: "{{ challenge.challenge_data_dns|d({})|dict2items }}"
|
||||||
debug:
|
debug:
|
||||||
msg: "add the following dns record: '{{ item.key }}.': { TXT: {{ item.value }} }"
|
msg: "add the following dns record: '{{ item.key }}.': { TXT: {{ item.value }} }"
|
||||||
|
|
||||||
- name: wait for challenges in dns (manual dns challange)
|
- name: wait for challenges in dns (manual dns challenge)
|
||||||
pause:
|
pause:
|
||||||
prompt: "When the relevant lines were added to dns and synced, press enter"
|
prompt: "When the relevant lines were added to dns and synced, press enter"
|
||||||
when:
|
when:
|
||||||
- challenge is changed
|
- challenge is changed
|
||||||
- cert_backend.challange == "dns-01-manual"
|
- cert_backend.challenge == "dns-01-manual"
|
||||||
|
|
||||||
- name: "setup challenge server for {{ certname }} (http challange)"
|
- name: "setup challenge server for {{ certname }} (http challenge)"
|
||||||
when:
|
when:
|
||||||
- challenge is changed
|
- challenge is changed
|
||||||
- cert_backend.challange == "http-01"
|
- cert_backend.challenge == "http-01"
|
||||||
delegate_to: "{{ item.0 }}"
|
delegate_to: "{{ item.0 }}"
|
||||||
loop: "{{ cert_backend.challangeserver|product(challenge.challenge_data.keys()|list)|list }}"
|
loop: "{{ cert_backend.challengeserver|product(challenge.challenge_data.keys()|list)|list }}"
|
||||||
copy:
|
copy:
|
||||||
dest: "/var/www/letsencrypt/{{ challenge.challenge_data[item.1]['http-01'].resource | basename }}"
|
dest: "/var/www/letsencrypt/{{ challenge.challenge_data[item.1]['http-01'].resource | basename }}"
|
||||||
content: "{{ challenge.challenge_data[item.1]['http-01'].resource_value }}"
|
content: "{{ challenge.challenge_data[item.1]['http-01'].resource_value }}"
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,52 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: 0600
|
mode: 0600
|
||||||
|
|
||||||
|
- name: register letsencrypt account
|
||||||
|
acme_account:
|
||||||
|
account_key_src: /etc/ssl/letsencrypt_account.key
|
||||||
|
state: present
|
||||||
|
terms_agreed: yes
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
|
||||||
|
- name: ensure config folders exist
|
||||||
|
file:
|
||||||
|
path: /etc/letsencrypt/
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: generate letsencrypt auto renew ssh key
|
||||||
|
register: letsencrypt_renewkey
|
||||||
|
openssh_keypair:
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
path: /etc/letsencrypt/renewkey
|
||||||
|
type: ed25519
|
||||||
|
comment: "letsencrypt-renew@{{ inventory_hostname }}"
|
||||||
|
|
||||||
|
- name: copy challenge deployment script
|
||||||
|
copy:
|
||||||
|
src: letsencrypt_deploy_challenge.sh
|
||||||
|
dest: /usr/local/bin/letsencrypt_deploy_challenge.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: copy letsencrypt renew skript
|
||||||
|
copy:
|
||||||
|
src: letsencrypt_renew.sh
|
||||||
|
dest: /usr/local/bin/letsencrypt_renew.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: copy acme primitives
|
||||||
|
get_url:
|
||||||
|
dest: /usr/local/bin/acme-primitives.py
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
url: "https://git.notandy.de/ansible/acme-primitives/-/raw/master/acme-primitives.py"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
pkg:
|
pkg:
|
||||||
- openssl
|
- openssl
|
||||||
- python3-cryptography
|
- python3-cryptography
|
||||||
|
- python3-acme
|
||||||
|
- python3-click
|
||||||
|
|
||||||
- name: add group ssl-cert
|
- name: add group ssl-cert
|
||||||
group:
|
group:
|
||||||
|
|
|
||||||
11
templates/letsencrypt_renew_config.j2
Normal file
11
templates/letsencrypt_renew_config.j2
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LETSENCRYPT_CHALLENGE_SERVERS="{{ cert_backend.challengeserver|join(' ') }}"
|
||||||
|
export LETSENCRYPT_CSR="{{ cert.csrpath }}"
|
||||||
|
export LETSENCRYPT_CRT="{{ cert.certpath }}"
|
||||||
|
export LETSENCRYPT_KEY="{{ cert.keypath }}"
|
||||||
|
export LETSENCRYPT_CHAIN="{{ cert.chainpath }}"
|
||||||
|
export LETSENCRYPT_FULL="{{ cert.fullpath }}"
|
||||||
|
export LETSENCRYPT_TOKEN="/etc/letsencrypt/cert_{{ certname }}.token"
|
||||||
|
export LETSENCRYPT_SERVICES="{{ cert.depending_services }}"
|
||||||
|
export LETSENCRYPT_REMAININGDAYS="{{ cert_backend.remainingdays }}"
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
map_challange_type_letsencrypt:
|
map_challenge_type_letsencrypt:
|
||||||
'dns-01-manual': 'dns-01'
|
'dns-01-manual': 'dns-01'
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue