letsencrypt acme.sh role.

This commit is contained in:
Andrea Dell'Amico 2018-08-20 19:19:56 +02:00
parent a5f0c611b7
commit dd2b1e1648
10 changed files with 334 additions and 0 deletions

View File

@ -0,0 +1,65 @@
---
letsencrypt_acme_sh_install: False
letsencrypt_acme_sh_git_install: True
letsencrypt_acme_sh_git_url: https://github.com/Neilpang/acme.sh.git
letsencrypt_acme_user: acme
letsencrypt_acme_sh_user: '{{ letsencrypt_acme_user }}'
letsencrypt_acme_user_home: /var/lib/acme
letsencrypt_acme_sh_user_home: '{{ letsencrypt_acme_user_home }}'
letsencrypt_acme_sh_base_data_dir: '{{ letsencrypt_acme_sh_user_home }}/acme_data'
letsencrypt_acme_sh_certificates_install_dir: '{{ ansible_fqdn }}'
letsencrypt_acme_sh_certificates_install_base_path: '{{ letsencrypt_acme_sh_user_home }}/live'
letsencrypt_acme_sh_certificates_install_path: '{{ letsencrypt_acme_sh_certificates_install_base_path }}/{{ letsencrypt_acme_sh_certificates_install_dir }}'
letsencrypt_acme_sh_log_dir: /var/log/acme
letsencrypt_acme_sh_install_cron: False
letsencrypt_acme_sh_log_enabled: True
letsencrypt_acme_sh_auto_upgrade: False
letsencrypt_acme_sh_install_options: '--install'
letsencrypt_acme_sh_test_request: False
letsencrypt_acme_sh_use_syslog: True
letsencrypt_acme_sh_syslog_level: 6
# We only support the PowerDNS API. Adding other ones should be straightforward
letsencrypt_acme_sh_use_dns_provider: False
letsencrypt_acme_sh_dns_provider_type: dns_pdns
letsencrypt_acme_sh_dns_api_url: 'http://localhost:8081'
letsencrypt_acme_sh_dns_api_provider_id: localhost
# Use a vault variable for this one
letsencrypt_acme_sh_dns_api_token: XXXXXXX
letsencrypt_acme_sh_command: acme.sh
# The data directory is created by the acme.sh install
letsencrypt_acme_sh_dirs:
- '{{ letsencrypt_acme_sh_user_home }}/bin'
- '{{ letsencrypt_acme_sh_base_data_dir }}/certs'
- '{{ letsencrypt_acme_sh_base_data_dir }}/logs'
# - '{{ letsencrypt_acme_sh_base_data_dir }}/data'
letsencrypt_acme_sh_dest_dir: '{{ ansible_fqdn }}'
letsencrypt_acme_sh_certs_dir: '{{ letsencrypt_acme_sh_base_data_dir }}/certs/{{ letsencrypt_acme_sh_dest_dir }}'
# The various services maintainers need to put the reconfigure/restart scripts there
letsencrypt_acme_sh_services_scripts_dir: /usr/lib/acme/hooks
letsencrypt_acme_sh_explicitly_install_certs: False
letsencrypt_acme_sh_use_ecc: True
letsencrypt_acme_sh_key_lenght: ec-384
letsencrypt_acme_sh_ocsp_must_staple: False
letsencrypt_acme_email: sysadmin@example.com
letsencrypt_acme_sh_email: '{{ letsencrypt_acme_email }}'
letsencrypt_acme_standalone_port: 4402
letsencrypt_acme_sh_standalone_port: '{{ letsencrypt_acme_standalone_port }}'
letsencrypt_acme_cron_day_of_month: '*'
letsencrypt_acme_cron_hour: '{{ range(1, 4) | random }}'
letsencrypt_acme_cron_minute: '{{ range(0, 59) | random }}'
# Use this when you want a single certificate. Even when multiple provider methods are needed
# The dns_provider and standalone options are mutually exclusive
letsencrypt_acme_sh_domains:
- ''
# - { domain: '{{ ansible_fqdn }}', dns_provider: '{{ letsencrypt_acme_sh_dns_provider_type }}', dns_alias_challenge: 'dns-challenge.example.org', standalone: True }
letsencrypt_acme_sh_domains_install:
- ''
# - { domain: '{{ ansible_fqdn }}', ecc: '{{ letsencrypt_acme_sh_use_ecc }}', cert_file: '{{ letsencrypt_acme_sh_certificates_install_path }}/cert', key_file: '{{ letsencrypt_acme_sh_certificates_install_path }}/privkey', fullchain_file: '{{ letsencrypt_acme_sh_certificates_install_path }}/fullchain', reloadcmd: 'letsencrypt_acme_sh_services_scripts_dir/hook_script' }

View File

@ -0,0 +1,17 @@
#!/bin/bash
if [ -f "/etc/default/acme_sh_request_env" ] ; then
. "/etc/default/acme_sh_request_env"
else
exit 1
fi
if [ -f "$ACME_SH_ENV_FILE" ] ; then
. "$ACME_SH_ENV_FILE"
else
exit 1
fi
$ACME_SH_BIN --cron --home "$ACME_SH_BINDIR" --config-home "$ACME_SH_CONFIG_HOME" > "$ACME_SH_CRON_LOG_FILE" 2>&1
exit $?

View File

@ -0,0 +1,21 @@
#!/bin/bash
if [ -f "/etc/default/acme_sh_request_env" ] ; then
. "/etc/default/acme_sh_request_env"
else
exit 1
fi
if [ -f "$ACME_SH_ENV_FILE" ] ; then
. "$ACME_SH_ENV_FILE"
else
exit 1
fi
su - acme -s /bin/bash -c '/usr/local/bin/acme-sh-cron-command'
if [ "$ACME_SH_INSTALL_CERTS" == "True" ] ; then
$ACME_SH_BIN $ACME_SH_INSTALL_CERT_REQUEST > "$ACME_SH_INSTALL_LOG_FILE" 2>&1
fi
exit $?

View File

@ -0,0 +1,12 @@
#!/bin/bash
if [ -f "/etc/default/acme_sh_request_env" ] ; then
. "/etc/default/acme_sh_request_env"
else
exit 1
fi
cd "$ACME_SH_HOME"
./acme.sh $ACME_SH_INSTALL_OPTS
exit $?

View File

@ -0,0 +1,22 @@
#!/bin/bash
if [ -f "/etc/default/acme_sh_request_env" ] ; then
. "/etc/default/acme_sh_request_env"
else
exit 1
fi
if [ -f "$ACME_SH_ENV_FILE" ] ; then
. "$ACME_SH_ENV_FILE"
else
exit 1
fi
if [ -d "$ACME_SH_HOME/keys/fakeselfsignedcert" -a -d "$ACME_SH_HOME/certs/fakeselfsignedcert" ] ; then
rm -fr "$ACME_SH_HOME/keys"
rm -fr "$ACME_SH_HOME/certs"
fi
$ACME_SH_BIN $ACME_SH_INSTALL_CERT_REQUEST > "$ACME_SH_INSTALL_LOG_FILE" 2>&1
exit $?

View File

@ -0,0 +1,23 @@
#!/bin/bash
if [ -f "/etc/default/acme_sh_request_env" ] ; then
. "/etc/default/acme_sh_request_env"
else
exit 1
fi
if [ -f "$ACME_SH_ENV_FILE" ] ; then
. "$ACME_SH_ENV_FILE"
else
exit 1
fi
RETVAL=
$ACME_SH_BIN $ACME_SH_ISSUE_CERT_REQUEST > "$ACME_SH_ISSUE_LOG_FILE" 2>&1
RETVAL=$?
if [ $RETVAL -ne 0 ] ; then
touch "$ACME_SH_CONFIG_HOME/ok_certificate_issued"
fi
exit $RETVAL

View File

@ -0,0 +1,7 @@
---
- name: Install the requested certificates
shell: /usr/local/bin/acme-sh-install-certs
when:
- letsencrypt_acme_sh_explicitly_install_certs
- acme_sh_certificate_issued is changed

View File

@ -0,0 +1,90 @@
---
- block:
- name: Create the letsencrypt acme user
user: name={{ letsencrypt_acme_sh_user }} home={{ letsencrypt_acme_sh_user_home }} createhome=no shell=/usr/sbin/nologin system=yes
tags: [ 'letsencrypt', 'letsencrypt_user' ]
- name: Create the letsencrypt acme home, if it does not exist already. In a separate step because it could be already there.
file: dest={{ letsencrypt_acme_sh_user_home }} owner={{ letsencrypt_acme_sh_user }} group={{ letsencrypt_acme_sh_user }} state=directory recurse=yes
- name: Create a directory where to put the cron job and hooks logs
file: dest={{ letsencrypt_acme_sh_log_dir }} state=directory owner={{ letsencrypt_acme_sh_user }} group={{ letsencrypt_acme_sh_user }} mode=0750
- name: Install the acme.sh environment variables file
template: src=acme_sh_request_env.j2 dest=/etc/default/acme_sh_request_env owner=root group=root mode=0444
register: acme_sh_issue
- name: Install the script that initializes the acme.sh environment
copy: src=acme-sh-install dest=/usr/local/bin/acme-sh-install owner=root group=acme mode=0750
- name: Install a script that issues the certificates
copy: src=acme-sh-request-cert dest=/usr/local/bin/acme-sh-request-cert owner=root group=acme mode=0750
- name: Install a script that installs the issued certificates
copy: src=acme-sh-install-certs dest=/usr/local/bin/acme-sh-install-certs owner=root group=acme mode=0750
- name: Install the scripts that will be run as a cron job
copy: src={{ item }} dest=/usr/local/bin/{{ item }} owner=root group=acme mode=0750
with_items:
- acme-sh-cron-script
- acme-sh-cron-command
tags: [ 'letsencrypt', 'letsencrypt_cron', 'letsencrypt_acme_sh' ]
when: letsencrypt_acme_sh_install
tags: [ 'letsencrypt', 'letsencrypt_acme_sh' ]
- block:
- name: Download the acme.sh distribution
git: repo={{ letsencrypt_acme_sh_git_url }} dest={{ letsencrypt_acme_sh_user_home }} recursive=yes update=yes
- name: Create the letsencrypt acme.sh directory tree
file: dest={{ item }} state=directory mode=0755
with_items: '{{ letsencrypt_acme_sh_dirs }}'
- name: Run the installation command for acme.sh
shell: /usr/local/bin/acme-sh-install
args:
creates: '{{ letsencrypt_acme_sh_user_home }}/bin/acme.sh'
- name: Create the letsencrypt acme.sh configuration
template: src=account.conf.j2 dest={{ letsencrypt_acme_sh_base_data_dir }}/data/account.conf mode=0640
- name: Request the certificates
shell: /usr/local/bin/acme-sh-request-cert
args:
creates: '{{ letsencrypt_acme_sh_base_data_dir }}/data/ok_certificate_issued'
register: acme_sh_certificate_issued
when: acme_sh_issue is changed
notify: Install the requested certificates
- name: Install a daily cron job to renew the certificates when needed
cron: name="Letsencrypt certificate renewal" day={{ letsencrypt_acme_cron_day_of_month }} hour={{ letsencrypt_acme_cron_hour }} minute={{ letsencrypt_acme_cron_minute }} job="/usr/local/bin/acme-sh-cron-script > {{ letsencrypt_acme_sh_log_dir }}/acme-cron.log 2>&1"
tags: [ 'letsencrypt', 'letsencrypt_cron', 'letsencrypt_acme_sh' ]
become: True
become_user: '{{ letsencrypt_acme_sh_user }}'
when: letsencrypt_acme_sh_install
tags: [ 'letsencrypt', 'letsencrypt_acme_sh' ]
- block:
- name: Check if the 'live' path is a symling. It is, if acmetool was installed
stat: path={{ letsencrypt_acme_sh_certificates_install_path }}
register: is_symlink
- name: Remove the 'live' path if it was a symlink
file: dest={{ letsencrypt_acme_sh_certificates_install_path }} state=absent
when: is_symlink.stat.islnk is defined and is_symlink.stat.islnk
- name: Create the certificates installation directory
file: dest={{ letsencrypt_acme_sh_certificates_install_path }} state=directory owner=root group=root mode=0755
- name: Install the certificates
shell: /usr/local/bin/acme-sh-install-certs
when:
- letsencrypt_acme_sh_explicitly_install_certs
- acme_sh_certificate_issued is defined
- acme_sh_certificate_issued is changed
ignore_errors: True
when: letsencrypt_acme_sh_install
tags: [ 'letsencrypt', 'letsencrypt_acme_sh' ]

View File

@ -0,0 +1,21 @@
{% if letsencrypt_acme_sh_log_enabled %}
LOG_FILE="{{ letsencrypt_acme_sh_base_data_dir }}/logs"
LOG_LEVEL=1
{% endif %}
{% if letsencrypt_acme_sh_auto_upgrade %}
AUTO_UPGRADE="1"
{% endif %}
#NO_TIMESTAMP=1
CERT_HOME='{{ letsencrypt_acme_sh_base_data_dir }}/certs'
ACCOUNT_EMAIL='{{ letsencrypt_acme_sh_email }}'
{% if letsencrypt_acme_sh_use_dns_provider %}
{% if letsencrypt_acme_sh_dns_provider_type == 'dns_pdns' %}
PDNS_Url="{{ letsencrypt_acme_sh_dns_api_url }}"
PDNS_ServerId="{{ letsencrypt_acme_sh_dns_api_provider_id }}"
PDNS_Token="{{ letsencrypt_acme_sh_dns_api_token }}"
PDNS_Ttl=180
{% endif %}
{% endif %}

View File

@ -0,0 +1,56 @@
#
# Globals
#
ACME_SH_HOME={{ letsencrypt_acme_sh_user_home }}
ACME_SH_BINDIR={{ letsencrypt_acme_sh_user_home }}/bin
ACME_SH_BIN="{{ letsencrypt_acme_sh_user_home }}/bin/acme.sh --config-home {{ letsencrypt_acme_sh_base_data_dir }}/data"
ACME_SH_CONFIG_HOME={{ letsencrypt_acme_sh_base_data_dir }}/data
ACME_SH_ENV_FILE=${ACME_SH_BINDIR}/acme.sh.env
ACME_SH_ISSUE_LOG_FILE={{ letsencrypt_acme_sh_base_data_dir }}/logs/cert_issue.log
ACME_SH_CRON_LOG_FILE={{ letsencrypt_acme_sh_base_data_dir }}/logs/cron.log
ACME_SH_INSTALL_LOG_FILE={{ letsencrypt_acme_sh_log_dir }}/cert_install.log
ACME_SH_INSTALL_CERTS={{ letsencrypt_acme_sh_explicitly_install_certs }}
#
# Install options
#
ACME_SH_INSTALL_OPTS="{{ letsencrypt_acme_sh_install_options }}"
{% if not letsencrypt_acme_sh_install_cron %}
ACME_SH_INSTALL_OPTS="$ACME_SH_INSTALL_OPTS --nocron"
{% endif %}
ACME_SH_INSTALL_OPTS="$ACME_SH_INSTALL_OPTS --home {{ letsencrypt_acme_sh_user_home }}/bin --config-home {{ letsencrypt_acme_sh_base_data_dir }}/data --certhome {{ letsencrypt_acme_sh_base_data_dir }}/certs --log {{ letsencrypt_acme_sh_base_data_dir }}/logs/acme.sh.log"
#
# Certificate issue options
#
ACME_SH_ISSUE_CERT_REQUEST="--issue -k {{ letsencrypt_acme_sh_key_lenght }} --log {{ letsencrypt_acme_sh_base_data_dir }}/logs/acme.sh.log"
{% if letsencrypt_acme_sh_ocsp_must_staple %}
ACME_SH_ISSUE_CERT_REQUEST="$ACME_SH_ISSUE_CERT_REQUEST --ocsp"
{% endif %}
{% if letsencrypt_acme_sh_use_syslog %}
ACME_SH_ISSUE_CERT_REQUEST="$ACME_SH_ISSUE_CERT_REQUEST --syslog {{ letsencrypt_acme_sh_syslog_level }}"
{% endif %}
{% if letsencrypt_acme_sh_test_request %}
ACME_SH_ISSUE_CERT_REQUEST="$ACME_SH_ISSUE_CERT_REQUEST --test"
{% endif %}
ACME_SH_ISSUE_CERT_DOMAINS="{% for dom in letsencrypt_acme_sh_domains %} -d {{ dom.domain }} {% if dom.dns_provider is defined %} --dns {{ dom.dns_provider }} {% if dom.dns_alias_challenge is defined %} --challenge-alias {{ dom.dns_alias_challenge }} {% endif %} {% endif %} {% if dom.standalone is defined %} --standalone --httpport {{ letsencrypt_acme_standalone_port }} {% endif %} {% endfor %}"
# The complete command line to issue a certificate
ACME_SH_ISSUE_CERT_REQUEST="$ACME_SH_ISSUE_CERT_REQUEST $ACME_SH_ISSUE_CERT_DOMAINS"
#
# Certificate install options
#
ACME_SH_INSTALL_CERT_REQUEST="--install-cert"
{% if letsencrypt_acme_sh_use_ecc %}
ACME_SH_INSTALL_CERT_REQUEST="$ACME_SH_INSTALL_CERT_REQUEST --ecc"
{% endif %}
{% if letsencrypt_acme_sh_use_syslog %}
ACME_SH_INSTALL_CERT_DOMAINS="$ACME_SH_INSTALL_CERT_DOMAINS --syslog {{ letsencrypt_acme_sh_syslog_level }}"
{% endif %}
ACME_SH_INSTALL_CERT_DOMAINS="{% for dom in letsencrypt_acme_sh_domains_install %} -d {{ dom.domain }} --cert-file {{ dom.cert_file }} --key-file {{ dom.key_file }} --fullchain-file {{ dom.fullchain_file }} --reloadcmd {{ dom.reloadcmd }} {% endfor %}"
# The complete command line to install a certificate. Run as root
ACME_SH_INSTALL_CERT_REQUEST="$ACME_SH_INSTALL_CERT_REQUEST $ACME_SH_INSTALL_CERT_DOMAINS"