Initial commit

This commit is contained in:
Nick Janetakis 2018-09-29 11:19:18 -04:00
commit 0fb24730a1
9 changed files with 791 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.DS_Store
*/**.DS_Store
._*
.*.sw*
*~
.idea/
.vscode/
*.retry

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
---
services: "docker"
env:
- distro: "ubuntu1604"
- distro: "ubuntu1804"
- distro: "debian8"
- distro: "debian9"
script:
# Download test shim.
- wget -O ${PWD}/tests/test.sh https://gist.githubusercontent.com/nickjj/d12353b5b601e33cd62fda111359957a/raw
- chmod +x ${PWD}/tests/test.sh
# Run tests.
- ${PWD}/tests/test.sh

7
CHANGES.md Executable file
View File

@ -0,0 +1,7 @@
# Changelog
### v1.0.0
*Released: September 29th 2018*
- Initial release

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 Nick Janetakis nick.janetakis@gmail.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

397
README.md Normal file
View File

@ -0,0 +1,397 @@
## What is ansible-acme-sh? [![Build Status](https://secure.travis-ci.org/nickjj/ansible-acme-sh.png)](http://travis-ci.org/nickjj/ansible-acme-sh)
It is an [Ansible](http://www.ansible.com/home) role to:
- Install acme.sh to issue, renew or remove Let's Encrypt based SSL certificates
- Issue certificates for single, multiple or wildcard domains
- Configure multiple domains through 1 certificate or separate certificates
- Issue DNS based challenges using acme.sh's automated DNS API feature
- Run custom acme.sh commands if the presets are not enough for you
## Why would you want to use this role?
This role uses [acme.sh](https://github.com/Neilpang/acme.sh) which is a self
contained Bash script to handle all of the complexities of issuing and
automatically renewing your SSL certificates.
This role's goals are to be highly configurable but have enough sane defaults
so that you can get going by supplying nothing more than a list of domain names,
setting your DNS provider and supplying your DNS provider's API key.
It's also idempotent for every task because that's the only way I roll!
#### Why is DNS based challenges the only supported method?
Having challenges done through DNS means you can set up your certificates before
your web server or proxy is provisioned. It also means your web server doesn't
need to know anything about how the ACME challenge works. All you have to do is
reference the final certificates this role generates.
Another perk is if you're running a web server inside of Docker, you might not
have that up and running until after your server has been provisioned by Ansible.
For example, it's common to set up git based deploys to kick off an app deploy.
Also, it's nice using DNS challenges because DNS challenges are the only way to
issue wildcard certificates using Let's Encrypt. Focusing efforts onto 1 solution
that works with all certificate types seemed like the right move.
With that said, I probably won't be supporting other modes such as standalone,
webroot, nginx or Apache but nothing is set in stone.
## Supported platforms
- Ubuntu 16.04 LTS (Xenial)
- Ubuntu 18.04 LTS (Bionic)
- Debian 8 (Jessie)
- Debian 9 (Stretch)
## Role variables
```
# The user on the system that acme.sh will run as. Keep in mind this user
# needs to already exist, this role will not create it.
acme_sh_become_user: "root"
# The acme.sh repo to clone.
acme_sh_git_url: "https://github.com/Neilpang/acme.sh"
# The branch, tag or commit that will be cloned.
acme_sh_git_version: "master"
# By default if you were to clone this repo now and then 6 months from now you
# clonged it again, it will stick with the old master version from 6 months ago.
# If you want to pull the latest master version on every run, set this to True.
acme_sh_git_update: False
# Where will this repo get cloned to?
acme_sh_git_clone_dest: "/usr/local/src/acme.sh"
# When enabled, acme.me will upgrade itself to the latest version which is
# separate from updating the git repo. That's because acme.sh installs itself
# with an installer after cloning the source code.
#
# Enabling it could be good to get the latest release which may have bug fixes
# but keep in mind if you do this, you may get different results per run. I
# recommend occasionally setting this to True but keeping it disabled usually.
acme_sh_upgrade: False
# When enabled the cloned source code, installation path, log files and renewal
# cron jobs will be removed.
#
# Installed certificates will not be removed. If you want to remove the installed
# certificates there is another option for that which we'll cover later.
acme_sh_uninstall: False
# When creating an initial Let's Encrypt account, you can optionally supply an
# email address. By default this isn't set, but feel free to add your email
# address in if you want. If you do set it, you'll get emailed when your
# certificates are within 20 days of expiring.
#
# I highly recommend setting this because if all goes as planned you'll never
# get emailed unless acme.sh malfunctioned and failed to renew a certificate.
acme_sh_account_email: ""
# Certificates will be renewed through an acme.sh managed cron job. By default
# acme.sh uses 60 days for each renewal attempt, but I've chosen to go with 30
# by default to give 1 extra attempt in case something unexpected happens.
#
# Certificates that don't need to be renewed will be skipped by acme.sh, so
# it's all good. It's also worth mentioning this value cannot be > 60 days which
# is a limit enforced by acme.sh, this role does not double check the value.
acme_sh_renew_time_in_days: 30
# The base path where certificates will be copied into. If you're familiar with
# acme.sh, this is for the certificates generated with --install-cert.
#
# This is the final destination for your certificates and the user you've chosen
# will need write access to this path. This path will end up being having its
# owner:group set to the acme_sh_become_user's value.
acme_sh_copy_certs_to_path: "/etc/ssl/ansible"
# At the end of the run, an Ansible debug message will print out a list of
# domains that have valid SSL certificates along with their expiration dates.
# You can disable this by setting it to False.
acme_sh_list_domains: True
# When set to False, it will use the live Let's Encrypt servers, so please make
# sure everything works with staging True or you may find yourself rate limited.
#
# It is worth mentioning you'll need to force issue a new certificate when
# swiching between staging and live or vice versa.
acme_sh_default_staging: True
# When set to True, this will regenerate a new certificate even if your list of
# domains didn't change. It's also used to set a new DNS provider and API keys.
#
# Be careful with this because you may get rate limited if on the live server.
# Only consider using this to update your DNS provider. You should set it back
# to False when you're done.
acme_sh_default_force_issue: False
# When set to True, this will regenerate a new certificate for an existing list
# of certificates. This will not update your DNS provider or API keys.
#
# This could be useful to use if your certificates expired. You should set it
# back to False when you're done.
acme_sh_default_force_renew: False
# When set to True, this will provide more detailed information to STDOUT. This
# could be useful if you're testing the role in staging mode.
acme_sh_default_debug: False
# Which DNS provider should you use?
# A list of supported providers can be found at:
# https://github.com/Neilpang/acme.sh#7-automatic-dns-api-integration
# As for getting the name to use, you can find that at:
# https://github.com/Neilpang/acme.sh/tree/master/dnsapi
#
# It defaults to DigitalOcean. Make sure to include the dns_ part of the name,
# but leave off the .sh file extension.
acme_sh_default_dns_provider: "dns_dgon"
# What are your DNS provider's API key(s)?
# The key names to use can be found at:
# https://github.com/Neilpang/acme.sh/tree/master/dnsapi
#
# The API key can be created on your DNS provider's website. Some providers
# require 1 key, while others require 2+. Just add them as key / value pairs here
# without the "export ".
#
# For example if you were using DigitalOcean you would enter:
# acme_sh_default_dns_provider_api_keys:
# "DO_API_KEY": "THE_API_SECRET_TOKEN_FROM_THE_DO_DASHBOARD"
acme_sh_default_dns_provider_api_keys: {}
# How long should acme.sh sleep after attempting to set the TXT record to your
# DNS records? Some DNS providers do not update as fast as others.
#
# 120 is the default value from acme.sh itself but keep in mind if you use
# NameSilo, their DNS updates only propagate once per 15 minutes so you'll need
# to set this value to 900 or you run the risk of getting a DNS NXDOMAIN error.
#
# I recommend keeping it set to 120 or higher if your DNS provider requires it.
#
# Although as an aside, I used 10 when testing this role against DigitalOcean
# and it worked about 30 times in a row. Still, in production I would use 120
# just to be safe because this 2 minute delay will only affect you on the first
# Ansible run. After that it will be updated in the background through a cron job.
acme_sh_default_dns_sleep: 120
# When issuing new certificates, you can choose to add additional flags that
# are not present here by default. Supply them just as you would on the command
# line, such as "--help".
acme_sh_default_extra_flags_issue: ""
# When renewing certificates, you can choose to add additional flags that
# are not present here by default. Supply them just as you would on the command
# line, such as "--help".
acme_sh_default_extra_flags_renew: ""
# When installing certificates, you can choose to add additional flags that
# are not present here by default. Supply them just as you would on the command
# line, such as "--help".
#
# Installing is different than issuing and we'll cover that later.
acme_sh_default_extra_flags_install_cert: ""
# When a certificate is issued or renewed, acme.sh will attempt to run a command
# of your choosing. This could be to restart or reload your web server or proxy.
#
# Keep in mind the user you set in acme_sh_become_user needs access rights to
# sudo if you use sudo here, or if not, they need access rights to reload your
# web server / proxy.
#
# For a Docker example, check the example section of this README.
acme_sh_default_install_cert_reloadcmd: "sudo systemctl reload nginx"
# If you need more fine grain control than the reloadcmd you can hook into the
# life cycle of issuing or renewing a certificate. By default the following 3
# options do nothing unless you fill them out. They are not needed for everything
# to function as long as your reloadcmd works.
#
# When a certificate is issued or renewed, acme.sh will attempt to run a command
# before attempting to issue a certificate. This can only be applied while
# issuing a certificate but it will be saved and used for renewing as well.
#
# This will execute even if the certificate wasn't successfully issued / renewed.
acme_sh_default_issue_pre_hook: ""
# When a certificate is issued or renewed, acme.sh will attempt to run a command
# after attempting to issue a certificate. This can only be applied while
# issuing a certificate but it will be saved and used for renewing as well.
#
# This will execute even if the certificate wasn't successfully issued / renewed.
acme_sh_default_issue_post_hook: ""
# When a certificate is issued or renewed, acme.sh will attempt to run a command
# after a certificate is successfully renewed. This can only be applied while
# issuing a certificate but it will be saved and used for renewing as well.
#
# This will only execute if the certificate was successfully issued / renewed.
acme_sh_default_issue_renew_hook: ""
# When set to True, certificates will be removed and unset from being renewed
# instead of being created and set for renewal. This will not uninstall acme.sh.
acme_sh_default_remove: False
# This list contains a list of domains, along with key / value pairs to
# configure each set of domains individually.
#
# Here's an example with every available option documented, and a couple of real
# examples will also be included in the example section of this README:
acme_sh_domains:
# A list of 1 or more domains, you can use ["*.example.com" ,"example.com] for
# setting a wildcard + root domain certificate. Domains listed here will
# all belong to the same certificate. If you want separate certificate files
# then create a new "domains:" item in the list.
#
# The first domain in the list will end up being used as a base file name for
# the certificate name. In this case it would be "example.com.pem".
# - domains: ["example.com", "www.example.com]
# # Optionally override the default staging variable. This overall pattern lets
# # you situationally override the defaults listed above for each domain list.
# staging: False
# # Optionally force issue new certificates.
# force_issue: False
# # Optionally force renew certificates.
# force_renew: False
# # Optionally turn on debug mode.
# debug: True
# # Optionally override the default DNS provider.
# dns_provider: "dns_namesilo"
# # Optionally override the default DNS API keys.
# dns_provider_api_keys:
# "Namesilo_Key": "THE_API_SECRET_TOKEN_FROM_THE_NAMESILO_DASHBOARD"
# # Optionally override the default DNS sleep time.
# dns_sleep: 900
# # Optionally add extra flags to any of these 3 actions:
# extra_flags_issue: ""
# extra_flags_renew: ""
# extra_flags_install_cert: ""
# # Optionally set a different reload command.
# install_cert_reloadcmd: "whoami"
# # Optionally run commands during different points in the cert issue process:
# extra_issue_pre_hook: ""
# extra_issue_post_hook: ""
# extra_issue_renew_hook: ""
# # Optionally remove and disable the certificate.
# remove: True
# How long should the apt-cache last in seconds?
acme_sh_apt_cache_time: 86400
```
## Example usage
For the sake of this example let's assume you have a group called **app** and
you have a typical `site.yml` file.
To use this role edit your `site.yml` file to look something like this:
```
---
- name: Configure app server(s)
hosts: "app"
become: True
roles:
- { role: "nickjj.acme-sh", tags: ["acme-sh"] }
```
Here's a few examples. You can recreate this example on your end by opening or
creating `group_vars/app.yml` which is located relative to your `inventory`
directory and then making it look like this:
```
---
acme_sh_account_email: "you@example.com"
# An example where a DNS provider has 2 keys for API access:
acme_sh_default_dns_provider: "dns_cf"
acme_sh_default_dns_provider_api_keys:
"CF_Key": "THE_API_SECRET_TOKEN_FROM_THE_CLOUDFLARE_DASHBOARD"
"CF_Email: "you@example.com"
# Reloading nginx inside of a Docker container that is named "nginx".
# If you are running nginx in a Docker container then you'll also need to volume
# mount in your certificates, but I'm sure you knew that already!
acme_sh_default_install_cert_reloadcmd: "docker exec nginx nginx -s reload"
# --- Here's a few different acme_sh_domains examples --------------------------
# You would only need to supply one of these based on what you wanted to do!
# ------------------------------------------------------------------------------
# 1 certificate file for all of the domains.
acme_sh_domains:
- domains: ["example.com", "www.example.com", "admin.example.com"]
# Produces this on your server:
# /etc/ssl/ansible/example.com.key (the private key)
# /etc/ssl/ansible/example.com.pem (the full chain certificate)
# ------------------------------------------------------------------------------
# 2 certificate files using the same domains as above.
acme_sh_domains:
- domains: ["example.com", "www.example.com"]
- domains: ["admin.example.com"]
# Produces this on your server:
# /etc/ssl/ansible/example.com.key (the private key)
# /etc/ssl/ansible/example.com.pem (the full chain certificate)
# /etc/ssl/ansible/admin.example.com.key (the private key)
# /etc/ssl/ansible/admin.example.com.pem (the full chain certificate)
# ------------------------------------------------------------------------------
# 2 certificate files using the same example but the admin certificate will get
# removed and disabled.
acme_sh_domains:
- domains: ["example.com", "www.example.com"]
- domains: ["admin.example.com"]
remove: True
# Produces this on your server:
# /etc/ssl/ansible/example.com.key (the private key)
# /etc/ssl/ansible/example.com.pem (the full chain certificate)
# ------------------------------------------------------------------------------
# 2 certificate files using the same example but switching from staging to live
# on admin.example.com (but remember to remove force_issue after it runs once).
acme_sh_domains:
- domains: ["example.com", "www.example.com"]
- domains: ["admin.example.com"]
staging: False
force_issue: True
# ------------------------------------------------------------------------------
# 2 certificate files using the same example but forcing a renew on
# admin.example.com (let's say a catastrophic error happened and the cert expired).
acme_sh_domains:
- domains: ["example.com", "www.example.com"]
- domains: ["admin.example.com"]
force_renew: True
```
*If you're looking for an Ansible role to create users, then check out my
[user role](https://github.com/nickjj/ansible-user)*.
Now you would run `ansible-playbook -i inventory/hosts site.yml -t acme-sh`.
## Installation
`$ ansible-galaxy install nickjj.acme-sh`
## Ansible Galaxy
You can find it on the official
[Ansible Galaxy](https://galaxy.ansible.com/nickjj/acme-sh/) if you want to
rate it.
## License
MIT

46
defaults/main.yml Normal file
View File

@ -0,0 +1,46 @@
---
acme_sh_become_user: "root"
acme_sh_git_url: "https://github.com/Neilpang/acme.sh"
acme_sh_git_version: "master"
acme_sh_git_update: False
acme_sh_git_clone_dest: "/usr/local/src/acme.sh"
acme_sh_upgrade: False
acme_sh_uninstall: False
acme_sh_account_email: ""
acme_sh_renew_time_in_days: 30
acme_sh_copy_certs_to_path: "/etc/ssl/ansible"
acme_sh_list_domains: True
acme_sh_default_staging: True
acme_sh_default_force_issue: False
acme_sh_default_force_renew: False
acme_sh_default_debug: False
acme_sh_default_dns_provider: "dns_dgon"
acme_sh_default_dns_provider_api_keys: {}
acme_sh_default_dns_sleep: 120
acme_sh_default_extra_flags_issue: ""
acme_sh_default_extra_flags_renew: ""
acme_sh_default_extra_flags_install_cert: ""
acme_sh_default_install_cert_reloadcmd: "sudo service nginx reload"
acme_sh_default_issue_pre_hook: ""
acme_sh_default_issue_post_hook: ""
acme_sh_default_issue_renew_hook: ""
acme_sh_default_remove: False
acme_sh_domains: []
acme_sh_apt_cache_time: 86400

27
meta/main.yml Normal file
View File

@ -0,0 +1,27 @@
---
galaxy_info:
role_name: "acme-sh"
author: "Nick Janetakis"
description: "Install and auto-renew SSL certificates with Let's Encrypt using acme.sh."
license: "license (MIT)"
min_ansible_version: 2.5
platforms:
- name: "Ubuntu"
versions:
- "xenial"
- "bionic"
- name: "Debian"
versions:
- "jessie"
- "stretch"
galaxy_tags:
- "https"
- "networking"
- "security"
- "ssl"
- "system"
dependencies: []

233
tasks/main.yml Normal file
View File

@ -0,0 +1,233 @@
---
- name: Install dependencies
apt:
name: "{{ item }}"
update_cache: True
cache_valid_time: "{{ acme_sh_apt_cache_time }}"
loop: ["cron", "git", "wget"]
when: not acme_sh_uninstall
- name: Create git clone path
file:
path: "{{ acme_sh_git_clone_dest | dirname }}"
state: "directory"
owner: "{{ acme_sh_become_user }}"
group: "{{ acme_sh_become_user }}"
mode: "0755"
when: not acme_sh_uninstall
- name: Git clone https://github.com/Neilpang/acme.sh
git:
repo: "{{ acme_sh_git_url }}"
version: "{{ acme_sh_git_version }}"
dest: "{{ acme_sh_git_clone_dest }}"
update: "{{ acme_sh_git_update }}"
when: not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
- name: Install acme.sh
command: >-
./acme.sh --install --log
--days {{ acme_sh_renew_time_in_days }}
{{ "--accountemail " + acme_sh_account_email if acme_sh_account_email else "" }}
args:
chdir: "{{ acme_sh_git_clone_dest }}"
creates: "~/.acme.sh/acme.sh"
when: not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
- name: Determine if acme.sh is installed
stat:
path: "~/.acme.sh/acme.sh"
register: is_acme_sh_installed
become_user: "{{ acme_sh_become_user }}"
- name: Upgrade acme.sh
command: ./acme.sh --upgrade
args:
chdir: "~/.acme.sh"
when:
- acme_sh_upgrade
- is_acme_sh_installed.stat.exists
- not acme_sh_uninstall
register: upgrade_result
changed_when: upgrade_result.rc == 0 and "Upgrade success" in upgrade_result.stdout
become_user: "{{ acme_sh_become_user }}"
- name: Create certificate path
file:
path: "{{ acme_sh_copy_certs_to_path }}"
state: "directory"
owner: "{{ acme_sh_become_user }}"
group: "{{ acme_sh_become_user }}"
mode: "0755"
when: not acme_sh_uninstall
- name: Uninstall acme.sh and disable all certificate renewals
command: ./acme.sh --uninstall
args:
chdir: "~/.acme.sh"
when:
- acme_sh_uninstall
- is_acme_sh_installed.stat.exists
become_user: "{{ acme_sh_become_user }}"
- name: Remove acme.sh certificate(s) renewals from cron job
command: >-
./acme.sh --remove -d {{ item.domains | first }}
{{ "--debug" if item.debug | default(acme_sh_default_debug) else "" }}
args:
chdir: "~/.acme.sh"
removes: "~/.acme.sh/{{ item.domains | first }}"
loop: "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.remove is defined and item.remove
- not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
register: remove_result
- name: Remove acme.sh internal certificate files
file:
path: "~/.acme.sh/{{ item.domains | first }}"
state: "absent"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.remove is defined and item.remove
- not acme_sh_uninstall
loop: "{{ acme_sh_domains }}"
become_user: "{{ acme_sh_become_user }}"
- name: Remove acme.sh installed certificate files
file:
path: "{{ acme_sh_copy_certs_to_path }}/{{ item.domains | first }}*"
state: "absent"
loop: "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.remove is defined and item.remove
- not acme_sh_uninstall
- name: Remove acme.sh's cloned source code, installation path and log files
file:
path: "{{ item }}"
state: "absent"
loop:
- "{{ acme_sh_git_clone_dest }}"
- "~/.acme.sh"
when:
- acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
- name: Run custom acme.sh command
command: ./acme.sh {{ item.custom_command }}
args:
chdir: "~/.acme.sh"
environment: "{{ item.dns_provider_api_keys | default(acme_sh_default_dns_provider_api_keys) }}"
loop: "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.dns_provider | default(acme_sh_default_dns_provider)
- item.dns_provider_api_keys | default(acme_sh_default_dns_provider_api_keys)
- item.custom_command is defined and item.custom_command
- item.remove is undefined or not item.remove
- not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
- name: Issue acme.sh certificate(s) (this will sleep for dns_sleep seconds)
command: >-
./acme.sh --issue -d {{ item.domains | join(" -d ") }}
--dns {{ item.dns_provider | default(acme_sh_default_dns_provider) }}
--dnssleep {{ item.dns_sleep | default(acme_sh_default_dns_sleep) }}
{{ "--force" if item.force_issue | default(acme_sh_default_force_issue) else "" }}
{{ "--staging" if item.staging | default(acme_sh_default_staging) else "" }}
{{ "--debug" if item.debug | default(acme_sh_default_debug) else "" }}
{{ "--pre-hook " + '"' + item.issue_pre_hook | default(acme_sh_default_issue_pre_hook) + '"' if item.issue_pre_hook | default(acme_sh_default_issue_pre_hook) else "" }}
{{ "--post-hook " + '"' + item.issue_post_hook | default(acme_sh_default_issue_post_hook) + '"' if item.issue_post_hook | default(acme_sh_default_issue_post_hook) else "" }}
{{ "--renew-hook " + '"' + item.issue_renew_hook | default(acme_sh_default_issue_renew_hook) + '"' if item.issue_renew_hook | default(acme_sh_default_issue_renew_hook) else "" }}
{{ item.extra_flags_issue | default(acme_sh_default_extra_flags_issue) }}
args:
chdir: "~/.acme.sh"
environment: "{{ item.dns_provider_api_keys | default(acme_sh_default_dns_provider_api_keys) }}"
loop: "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.dns_provider | default(acme_sh_default_dns_provider)
- item.dns_provider_api_keys | default(acme_sh_default_dns_provider_api_keys)
- item.force_renew is undefined or not item.force_renew
- item.custom_command is undefined or not item.custom_command
- item.remove is undefined or not item.remove
- not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
register: issue_result
changed_when: issue_result.rc == 0 and "Cert success" in issue_result.stdout
failed_when: issue_result.rc != 0 and "Domains not changed" not in issue_result.stdout
- name: Force renew acme.sh certificate(s)
command: >-
./acme.sh --renew -d {{ item.domains | first }} --force
{{ "--debug" if item.debug | default(acme_sh_default_debug) else "" }}
{{ item.extra_flags_renew | default(acme_sh_default_extra_flags_renew) }}
args:
chdir: "~/.acme.sh"
loop: "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.force_issue is undefined or not item.force_issue
- item.force_renew is defined and item.force_renew
- item.remove is undefined or not item.remove
- not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
register: renew_result
failed_when: renew_result.rc != 0 and "Reload error for" not in renew_result.stderr
- name: Ensure installed certificates have correct user / group ownership
file:
path: "{{ acme_sh_copy_certs_to_path }}/{{ item.domains | first }}*"
group: "{{ acme_sh_become_user }}"
owner: "{{ acme_sh_become_user }}"
loop:
- "{{ acme_sh_domains }}"
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.custom_command is undefined or not item.custom_command
- item.remove is undefined or not item.remove
- not acme_sh_uninstall
- name: Install acme.sh certificate(s)
command: >-
./acme.sh --install-cert -d {{ item.domains | first }}
--key-file {{ acme_sh_copy_certs_to_path }}/{{ item.domains | first }}.key
--fullchain-file {{ acme_sh_copy_certs_to_path }}/{{ item.domains | first }}.pem
--reloadcmd "{{ item.install_cert_reloadcmd | default(acme_sh_default_install_cert_reloadcmd) }}"
{{ "--debug" if item.debug | default(acme_sh_default_debug) else "" }}
{{ item.extra_flags_install_cert | default(acme_sh_default_extra_flags_install_cert) }}
args:
chdir: "~/.acme.sh"
loop: "{{ acme_sh_domains }}"
loop_control:
index_var: domains_index
when:
- acme_sh_domains and item.domains is defined and item.domains
- item.custom_command is undefined or not item.custom_command
- item.remove is undefined or not item.remove
- not acme_sh_uninstall
become_user: "{{ acme_sh_become_user }}"
register: install_cert_result
changed_when: issue_result.results[domains_index].changed or renew_result.results[domains_index].changed
failed_when: install_cert_result.rc != 0 and "Reload error for" not in install_cert_result.stderr
- name: Register acme.sh certificate information
command: ./acme.sh --list
args:
chdir: "~/.acme.sh"
when: acme_sh_list_domains and not acme_sh_uninstall
changed_when: False
register: list_domains
become_user: "{{ acme_sh_become_user }}"
- name: List acme.sh certificate information
debug:
msg: "{{ list_domains.stdout_lines }}"
when: acme_sh_list_domains and not acme_sh_uninstall

34
tests/test.yml Normal file
View File

@ -0,0 +1,34 @@
---
- hosts: "all"
become: True
vars:
acme_sh_become_user: "test"
roles:
- "role_under_test"
pre_tasks:
- name: Add test user
user:
name: "{{ acme_sh_become_user }}"
shell: "/bin/bash"
post_tasks:
- name: Ensure acme.me was cloned
command: test -d /usr/local/src/acme.sh
register: result_cloned
changed_when: result_cloned.rc != 0
- name: Ensure acme.me was installed
command: ./acme.sh --version
args:
chdir: "~/.acme.sh"
register: result_installed
changed_when: result_installed.rc != 0
become_user: "{{ acme_sh_become_user }}"
- name: Ensure certificate installation path exists
command: test -d /etc/ssl/ansible
register: result_cert_installed_path
changed_when: result_cert_installed_path.rc != 0