Fix corner case when ansible_user: root

This commit is contained in:
Brian Lee 2023-06-16 20:07:35 -07:00
parent c8086b5d82
commit 74a305ef1e
6 changed files with 131 additions and 119 deletions

View File

@ -1,64 +1,4 @@
--- ---
# These tasks run in a loop for each domain so that we can check for existing certificates
# and only order new ones if they don't already exist.
- name: "Check for an existing certificate for {{ acme_domain.domain }}"
ansible.builtin.stat:
path: "{{ lego_path }}/certificates/{{ acme_domain.domain }}.crt"
register: lego_cert
delegate_to: localhost
tags: lego
- name: Instruct lego to register an account and order a new certificate if one doesn't already exist.
set_fact:
lego_command: "{{ 'renew' if lego_cert.stat.exists else 'run'}}"
delegate_to: localhost
tags: lego
- name: Order acme certificates without waiting for propogation of TXT record to all authoritative name servers.
ansible.builtin.command:
cmd: >
lego --path {{ lego_path }} --dns {{ acme_domain.provider }} --domains {{ acme_domain.domain }} --email {{ acme_email }} --dns.disable-cp --accept-tos {{ lego_command }}
register: lego_result
delegate_to: localhost
changed_when: False
ignore_errors: true
tags: lego
environment:
# EASYDNS_TOKEN: "{{ EASYDNS_TOKEN }}"
# EASYDNS_KEY: "{{ EASYDNS_KEY }}"
NAMECHEAP_API_USER: "{{ NAMECHEAP_API_USER }}"
NAMECHEAP_API_KEY: "{{ NAMECHEAP_API_KEY }}"
- name: Print lego output with dns.disable-cp
ansible.builtin.debug:
var: lego_result
delegate_to: localhost
tags: lego
# --dns.disable-cp: disables the need to wait the propagation of the TXT record to all authoritative name servers.
# I haven't yet figured out why it only works sporadically with or without this option.
- name: Retry the last command if necessary, but wait for propogation of TXT record to all authoritative name servers.
ansible.builtin.command:
cmd: >
lego --path {{ lego_path }} --dns {{ acme_domain.provider }} --domains {{ acme_domain.domain }} --email {{ acme_email }} --accept-tos {{ lego_command }}
when: lego_result.failed
register: lego_result
delegate_to: localhost
changed_when: False
tags: lego
environment:
# EASYDNS_TOKEN: "{{ EASYDNS_TOKEN }}"
# EASYDNS_KEY: "{{ EASYDNS_KEY }}"
NAMECHEAP_API_USER: "{{ NAMECHEAP_API_USER }}"
NAMECHEAP_API_KEY: "{{ NAMECHEAP_API_KEY }}"
- name: Print lego output without dns.disable-cp
ansible.builtin.debug:
var: lego_result
delegate_to: localhost
tags: lego
- name: "Copy certificate files for {{ acme_domain.domain }}." - name: "Copy certificate files for {{ acme_domain.domain }}."
ansible.builtin.copy: ansible.builtin.copy:
src: "{{ lego_path }}/certificates/{{ acme_domain.domain }}.{{ file_extension }}" src: "{{ lego_path }}/certificates/{{ acme_domain.domain }}.{{ file_extension }}"
@ -73,3 +13,47 @@
- issuer.crt - issuer.crt
loop_control: loop_control:
loop_var: file_extension loop_var: file_extension
- name: Configure nginx TLSv1.2 for {{ acme_domain.domain }}
ansible.builtin.import_role:
name: nginxinc.nginx_core.nginx_config
allow_duplicates: true
tags: nginx
vars:
nginx_config_http_template_enable: true
nginx_config_http_template:
- template_file: http/default.conf.j2
deployment_location: "/etc/nginx/acme_{{ acme_domain.domain }}.conf"
backup: false
config:
core:
server_name: "{{ acme_domain.domain }}"
ssl:
certificate: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.crt"
certificate_key: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.key"
trusted_certificate: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.issuer.crt"
ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
dhparam: "{{ nginx_config_dhparam }}"
ecdh_curve: X25519:secp521r1:secp384r1
prefer_server_ciphers: true
protocols:
- TLSv1.2
- TLSv1.3
session_cache:
shared:
name: "{{ acme_domain.domain }}"
size: 1M
session_tickets: false
session_timeout: 1d
ocsp: true
ocsp_cache:
name: cache
size: 64k
stapling: true
stapling_verify: true
ocsp_responder: http://r3.o.lencr.org
headers:
add_headers:
- name: Strict-Transport-Security
value: '"max-age=7776000"'
always: true

View File

@ -5,6 +5,7 @@
register: dhparams register: dhparams
delegate_to: localhost delegate_to: localhost
tags: dhparams tags: dhparams
become: false
- name: Use previously generated dhparams to reduce deployment time by several minutes. - name: Use previously generated dhparams to reduce deployment time by several minutes.
ansible.builtin.copy: ansible.builtin.copy:

60
tasks/lego.yml Normal file
View File

@ -0,0 +1,60 @@
---
# These tasks run in a loop for each domain so that we can check for existing certificates
# and only order new ones if they don't already exist.
- name: "Check for an existing certificate for {{ acme_domain.domain }}"
ansible.builtin.stat:
path: "{{ lego_path }}/certificates/{{ acme_domain.domain }}.crt"
register: lego_cert
delegate_to: localhost
tags: lego
- name: Instruct lego to register an account and order a new certificate if one doesn't already exist.
set_fact:
lego_command: "{{ 'renew' if lego_cert.stat.exists else 'run'}}"
delegate_to: localhost
tags: lego
- name: Order acme certificates without waiting for propogation of TXT record to all authoritative name servers.
ansible.builtin.command:
cmd: >
lego --path {{ lego_path }} --dns {{ acme_domain.provider }} --domains {{ acme_domain.domain }} --email {{ acme_email }} --dns.disable-cp --accept-tos {{ lego_command }}
register: lego_result
delegate_to: localhost
changed_when: False
ignore_errors: true
tags: lego
environment:
# EASYDNS_TOKEN: "{{ EASYDNS_TOKEN }}"
# EASYDNS_KEY: "{{ EASYDNS_KEY }}"
NAMECHEAP_API_USER: "{{ NAMECHEAP_API_USER }}"
NAMECHEAP_API_KEY: "{{ NAMECHEAP_API_KEY }}"
- name: Print lego output with dns.disable-cp
ansible.builtin.debug:
var: lego_result
delegate_to: localhost
tags: lego
# --dns.disable-cp: disables the need to wait the propagation of the TXT record to all authoritative name servers.
# I haven't yet figured out why it only works sporadically with or without this option.
- name: Retry the last command if necessary, but wait for propogation of TXT record to all authoritative name servers.
ansible.builtin.command:
cmd: >
lego --path {{ lego_path }} --dns {{ acme_domain.provider }} --domains {{ acme_domain.domain }} --email {{ acme_email }} --accept-tos {{ lego_command }}
when: lego_result.failed
register: lego_result
delegate_to: localhost
changed_when: False
tags: lego
environment:
# EASYDNS_TOKEN: "{{ EASYDNS_TOKEN }}"
# EASYDNS_KEY: "{{ EASYDNS_KEY }}"
NAMECHEAP_API_USER: "{{ NAMECHEAP_API_USER }}"
NAMECHEAP_API_KEY: "{{ NAMECHEAP_API_KEY }}"
- name: Print lego output without dns.disable-cp
ansible.builtin.debug:
var: lego_result
delegate_to: localhost
tags: lego

View File

@ -2,36 +2,35 @@
- name: Assert all secrets have been configured. - name: Assert all secrets have been configured.
ansible.builtin.assert: ansible.builtin.assert:
that: that:
# - EASYDNS_TOKEN != ''
# - EASYDNS_KEY != ''
- NAMECHEAP_API_USER != '' - NAMECHEAP_API_USER != ''
- NAMECHEAP_API_KEY != '' - NAMECHEAP_API_KEY != ''
fail_msg: "FAILED: Secrets have not been configured." fail_msg: "FAILED: Secrets have not been configured."
no_log: true no_log: true
- name: Set up the acme system user and group. - name: Set up the ACME system user and group.
import_tasks: setup-acme.yml import_tasks: setup-user.yml
become: true
- name: Add nginx user to the acme group. - name: Run lego looped task to order or renew certificates for all ACME domains.
ansible.builtin.user: include_tasks:
name: "{{ nginx_user }}" file: lego.yml
groups: "{{ acme_system_group }}" apply:
append: true become: false
when: acme_system_user != "root"
- name: Run lego looped task to order or renew certificates for all acme domains.
include_tasks: certificates.yml
loop: "{{ acme_domains }}" loop: "{{ acme_domains }}"
loop_control: loop_control:
loop_var: acme_domain loop_var: acme_domain
tags: lego tags: lego
- name: Loop through the domain list (again) to configure nginx for each ACME domain - name: Loop through the domain list (again) to copy certs and configure nginx for each ACME domain
include_tasks: nginx_conf.yml include_tasks:
file: certificates.yml
apply:
become: true
loop: "{{ acme_domains }}" loop: "{{ acme_domains }}"
loop_control: loop_control:
loop_var: acme_domain loop_var: acme_domain
tags: nginx tags: nginx
- import_tasks: dhparams.yml - import_tasks: dhparams.yml
become: true
tags: dhparams tags: dhparams

View File

@ -1,44 +0,0 @@
---
- name: Configure nginx TLSv1.2 for {{ acme_domain.domain }}
ansible.builtin.import_role:
name: nginxinc.nginx_core.nginx_config
allow_duplicates: true
tags: nginx
vars:
nginx_config_http_template_enable: true
nginx_config_http_template:
- template_file: http/default.conf.j2
deployment_location: "/etc/nginx/acme_{{ acme_domain.domain }}.conf"
backup: false
config:
core:
server_name: "{{ acme_domain.domain }}"
ssl:
certificate: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.crt"
certificate_key: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.key"
trusted_certificate: "{{ acme_path }}/certificates/{{ acme_domain.domain }}.issuer.crt"
ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
dhparam: "{{ nginx_config_dhparam }}"
ecdh_curve: X25519:secp521r1:secp384r1
prefer_server_ciphers: true
protocols:
- TLSv1.2
- TLSv1.3
session_cache:
shared:
name: "{{ acme_domain.domain }}"
size: 1M
session_tickets: false
session_timeout: 1d
ocsp: true
ocsp_cache:
name: cache
size: 64k
stapling: true
stapling_verify: true
ocsp_responder: http://r3.o.lencr.org
headers:
add_headers:
- name: Strict-Transport-Security
value: '"max-age=7776000"'
always: true

View File

@ -8,6 +8,7 @@
- /usr/sbin - /usr/sbin
patterns: nologin patterns: nologin
register: nologin_bin register: nologin_bin
become: true
- name: Create the acme group - name: Create the acme group
ansible.builtin.group: ansible.builtin.group:
@ -15,6 +16,7 @@
state: present state: present
system: true system: true
when: acme_system_group != "root" when: acme_system_group != "root"
become: true
- name: Create the acme system user - name: Create the acme system user
ansible.builtin.user: ansible.builtin.user:
@ -25,6 +27,7 @@
create_home: false create_home: false
home: "{{ acme_path }}" home: "{{ acme_path }}"
when: acme_system_user != "root" when: acme_system_user != "root"
become: true
- name: Ensure acme_path exists. - name: Ensure acme_path exists.
ansible.builtin.file: ansible.builtin.file:
@ -33,3 +36,12 @@
group: "{{ acme_system_group }}" group: "{{ acme_system_group }}"
state: directory state: directory
mode: '0750' mode: '0750'
become: true
- name: Add nginx user to the ACME group.
ansible.builtin.user:
name: "{{ nginx_user }}"
groups: "{{ acme_system_group }}"
append: true
when: acme_system_user != "root"
become: true