From 3ea3d94286aaeaca7b5293257ee9ad220fbaa6a9 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 7 Apr 2020 04:17:56 -0400 Subject: [PATCH] Simplified role for only work with Cloudflare. --- defaults/main.yml | 55 +++------- handlers/main.yml | 10 ++ tasks/main.yml | 252 ++++++++++------------------------------------ 3 files changed, 76 insertions(+), 241 deletions(-) create mode 100644 handlers/main.yml diff --git a/defaults/main.yml b/defaults/main.yml index 174a6de..0fb1ae1 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,46 +1,21 @@ --- - -acme_sh_become_user: "root" - -acme_sh_git_url: "https://github.com/Neilpang/acme.sh" +acme_sh_git_url: "https://github.com/acmesh-official/acme.sh.git" acme_sh_git_version: "master" -acme_sh_git_update: False -acme_sh_git_clone_dest: "/usr/local/src/acme.sh" +acme_sh_git_clone_dest: "/tmp/acme.sh" -acme_sh_upgrade: False -acme_sh_uninstall: False +acme_sh_copy_certs_to_path: "/tmp/ssl/ansible" -acme_sh_account_email: "" +acme_sh_domains: + - domain: acme.effenco.com + path: /tmp/ssl/certs + name: acme + remove: false + force_issue: false + staging: false + debug: false -acme_sh_renew_time_in_days: 30 +acme_cloudflare_token: xxxx +acme_cloudflare_account_id: xxxx +acme_cloudflare_zone_id: xxxx -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 +acme_sh_service: "" diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..5cc02bf --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,10 @@ +- name: reload services + service: + name: "{{ item.service | default(acme_sh_service) }}" + state: restarted + when: + - issue_result.results[domains_index].changed + - item.service is defined or acme_sh_service is not empty + loop: "{{ acme_sh_domains }}" + loop_control: + index_var: domains_index diff --git a/tasks/main.yml b/tasks/main.yml index e161884..cde4530 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,233 +1,83 @@ --- +- name: Update apt cache. + apt: + update_cache: true + when: ansible_os_family == 'Debian' - 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 + package: + name: + - git + - wget - 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 +- name: Git clone 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 }}" + update: true + changed_when: False - name: Create certificate path file: - path: "{{ acme_sh_copy_certs_to_path }}" + path: "{{ item.path | default(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 }}*" + path: "{{ item.path | default(acme_sh_copy_certs_to_path) }}/{{ item.domain }}*" 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 + - item.remove | default(false) + loop: "{{ acme_sh_domains }}" + +- name: Issue acme.sh certificate(s) + command: >- + ./acme.sh --issue -d {{ item.domain }} --dns dns_cf + {{ "--force" if item.force_issue | default(false) or item.force_renew | default(false) else "" }} + {{ "--staging" if item.staging | default(false) else "" }} + {{ "--debug" if item.debug | default(false) else "" }} + args: + chdir: "{{ acme_sh_git_clone_dest }}" + environment: + - "CF_Token": "{{ acme_cloudflare_token }}" + - "CF_Account_ID": "{{ acme_cloudflare_account_id }}" + - "CF_Zone_ID": "{{ acme_cloudflare_zone_id }}" + when: not item.remove | default(false) + loop: "{{ acme_sh_domains }}" + register: issue_result + changed_when: issue_result.rc == 0 and "Cert success" in issue_result.stdout and not item.force_renew | default(false) + failed_when: issue_result.rc != 0 and "Domains not changed" not in issue_result.stdout + +- name: Install acme.sh certificate(s) + command: >- + ./acme.sh --install-cert -d {{ item.domain }} + --key-file {{ item.path | default(acme_sh_copy_certs_to_path) }}/{{ item.domain }}.key + --fullchain-file {{ item.path | default(acme_sh_copy_certs_to_path) }}/{{ item.domain }}.pem + {{ "--debug" if item.debug | default(false) else "" }} + args: + chdir: "{{ acme_sh_git_clone_dest }}" + loop: "{{ acme_sh_domains }}" + loop_control: + index_var: domains_index + when: not item.remove | default(false) + register: install_cert_result + changed_when: issue_result.results[domains_index].changed + failed_when: install_cert_result.rc != 0 and "Reload error for" not in install_cert_result.stderr + notify: reload services - name: Remove acme.sh's cloned source code, installation path and log files file: path: "{{ item }}" state: "absent" + changed_when: False 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