Compare commits

6 Commits

Author SHA1 Message Date
af72c10791 Update facts access for later Ansible versions 2025-11-29 15:04:07 +00:00
2908e643c7 Fix plugin deriving functions 2025-11-29 15:03:56 +00:00
e0b88c6dad Support any provided plugin via auto-installation 2025-07-19 11:29:56 +01:00
Andrew Williams
44174f00d9 Remove key_type option 2025-06-24 15:48:12 +01:00
Andrew Williams
f47c40b9c0 Add Route53 support 2025-06-24 15:48:02 +01:00
70ce48a0ef Merge pull request #1 from nikdoof/origin/main
Only provide keytype args if specified
2025-06-10 16:04:19 +01:00
8 changed files with 195 additions and 30 deletions

157
README.md
View File

@@ -1,2 +1,157 @@
# Ansible Certbot # Ansible Certbot Role
An Ansible role for installing Certbot and automatically requesting Let's Encrypt SSL certificates with support for multiple DNS providers and authentication methods.
## Description
This role automates the installation and configuration of Certbot, the official Let's Encrypt client. It supports multiple certificate acquisition methods including webroot validation and DNS challenges through various providers like DigitalOcean, GoDaddy, and AWS Route53.
## Features
- Installs Certbot and required plugins
- Supports multiple DNS providers for domain validation
- Automatic certificate renewal via systemd timer
- Certificate expansion for adding new domains
- Flexible plugin installation (package manager or PyPI)
- Automatic FQDN certificate generation option
## Requirements
- Ansible 2.9+
- Target systems: Linux distributions with systemd support
- For DNS challenges: appropriate DNS provider credentials
## Role Variables
### Required Variables
| Variable | Description | Default |
| --------------------- | -------------------------------------------- | ------------------------------ |
| `certbot_certs_email` | Email address for Let's Encrypt registration | `root@{{ ansible_inventory }}` |
### Certificate Configuration
| Variable | Description | Default |
| --------------------------- | ---------------------------------------- | ------- |
| `certbot_certs` | List of certificates to request | `[]` |
| `certbot_request_fqdn_cert` | Automatically request cert for host FQDN | `true` |
### Plugin Configuration
| Variable | Description | Default |
| -------------------------------- | -------------------------------------------------------- | -------------- |
| `certbot_plugins_source` | Plugin installation source (`package_manager` or `pypi`) | `pypi` |
| `certbot_plugins_package_prefix` | Prefix for plugin package names | `certbot-dns-` |
### DNS Provider Credentials
| Variable | Description | Default |
| ---------------------------- | ----------------------------------------- | ----------- |
| `certbot_digitalocean_token` | DigitalOcean API token for DNS challenges | `undefined` |
### System Configuration
| Variable | Description | Default |
| ----------------------- | --------------------------------- | --------------- |
| `certbot_packages` | Base certbot packages to install | `[certbot]` |
| `certbot_timer_service` | Systemd timer service for renewal | `certbot.timer` |
### Plugin Arguments
The `certbot_plugin_arguments` dictionary defines command-line arguments for different authentication methods:
```yaml
certbot_plugin_arguments:
digitalocean: --dns-digitalocean --dns-digitalocean-credentials /root/do_secrets.ini
godaddy: --authenticator dns-godaddy --dns-godaddy-credentials /root/gd_secrets.ini
route53: --dns-route53
default: "--webroot -w /var/www/acme-challenge"
```
## Usage Examples
### Basic Webroot Validation
```yaml
- hosts: webservers
roles:
- ansible-certbot
vars:
certbot_certs_email: admin@example.com
certbot_certs:
- hostname: example.com
sans:
- www.example.com
```
### DigitalOcean DNS Challenge
```yaml
- hosts: servers
roles:
- ansible-certbot
vars:
certbot_certs_email: admin@example.com
certbot_digitalocean_token: "your_do_token_here"
certbot_certs:
- hostname: example.com
plugin: digitalocean
sans:
- "*.example.com"
- www.example.com
```
### Multiple Certificates with Different Plugins
```yaml
- hosts: servers
roles:
- ansible-certbot
vars:
certbot_certs_email: admin@example.com
certbot_digitalocean_token: "your_do_token_here"
certbot_certs:
- hostname: api.example.com
plugin: digitalocean
- hostname: blog.example.com
plugin: default # Uses webroot
- hostname: shop.example.com
plugin: route53
extra_arguments: "--dns-route53-propagation-seconds 60"
```
### Custom Plugin Installation
```yaml
- hosts: servers
roles:
- ansible-certbot
vars:
certbot_plugins_source: package_manager
certbot_plugins_package_prefix: python3-certbot-dns-
certbot_certs:
- hostname: example.com
plugin: cloudflare
```
## Certificate Configuration Format
Each certificate in the `certbot_certs` list should follow this format:
```yaml
certbot_certs:
- hostname: primary.domain.com # Required: Primary domain name
plugin: digitalocean # Optional: Authentication plugin
sans: # Optional: Subject Alternative Names
- www.primary.domain.com
- alt.domain.com
extra_arguments: "--key-type rsa" # Optional: Additional certbot arguments
```
## Dependencies
- `community.crypto` collection (for certificate information parsing)
## License
MIT

View File

@@ -6,14 +6,13 @@ certbot_request_fqdn_cert: true
certbot_plugin_arguments: certbot_plugin_arguments:
digitalocean: --dns-digitalocean --dns-digitalocean-credentials /root/do_secrets.ini digitalocean: --dns-digitalocean --dns-digitalocean-credentials /root/do_secrets.ini
godaddy: --authenticator dns-godaddy --dns-godaddy-credentials /root/gd_secrets.ini godaddy: --authenticator dns-godaddy --dns-godaddy-credentials /root/gd_secrets.ini
route53: --dns-route53
default: "--webroot -w /var/www/acme-challenge" default: "--webroot -w /var/www/acme-challenge"
certbot_packages: certbot_packages:
- certbot - certbot
certbot_extension_packages: certbot_plugins_source: pypi
- python3-certbot-dns-digitalocean certbot_plugins_package_prefix: certbot-dns-
certbot_extension_pypi_packages: []
certbot_timer_service: certbot.timer certbot_timer_service: certbot.timer

View File

@@ -3,11 +3,14 @@
ansible.builtin.stat: ansible.builtin.stat:
path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem" path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem"
register: cert_stat register: cert_stat
check_mode: false
- name: Certbot - Get the SANs from the certificate file - name: Certbot - Get the SANs from the certificate file
community.crypto.x509_certificate_info: community.crypto.x509_certificate_info:
path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem" path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem"
register: cert_info register: cert_info
changed_when: false
check_mode: false
when: cert_stat.stat.exists when: cert_stat.stat.exists
- name: Certbot - Calculate the SAN list - name: Certbot - Calculate the SAN list
@@ -15,6 +18,6 @@
cert_sans: "{{ ['DNS:'] | product(item.sans | default([item.hostname])) | map('join') | list }}" cert_sans: "{{ ['DNS:'] | product(item.sans | default([item.hostname])) | map('join') | list }}"
- name: Certbot - Request a certificate # noqa no-changed-when ignore-errors - name: Certbot - Request a certificate # noqa no-changed-when ignore-errors
ansible.builtin.command: "certbot certonly -n --expand --agree-tos {{ certbot_plugin_arguments[item.plugin | default('default')] }} -d '{{ item.hostname }}' {% for san in item.sans | default([]) %} -d '{{ san }}' {% endfor %} -m {{ certbot_certs_email }}{% if item.key_type %} --key-type {{ item.key_type }}{% endif %}" # noqa no-change-when ansible.builtin.command: "certbot certonly -n --expand --agree-tos {{ certbot_plugin_arguments[item.plugin | default('default')] | default('') }} -d '{{ item.hostname }}' {% for san in item.sans | default([]) %} -d '{{ san }}' {% endfor %} -m {{ certbot_certs_email }}{% if item.extra_arguments is defined %} {{ item.extra_arguments }}{% endif %}" # noqa no-change-when
ignore_errors: true ignore_errors: true
when: not cert_stat.stat.exists or cert_sans | difference(cert_info.subject_alt_name) | list | length > 0 when: not cert_stat.stat.exists or cert_sans | difference(cert_info.subject_alt_name) | list | length > 0

View File

@@ -4,23 +4,35 @@
name: "{{ certbot_packages }}" name: "{{ certbot_packages }}"
state: present state: present
- name: Certbot - Install certbot extensions (package manager) - name: Certbot - Build plugin list
ansible.builtin.package: set_fact:
name: "{{ certbot_extension_packages }}" _certbot_plugins_used: "{{ certbot_certs | map(attribute='plugin') | list | unique }}"
state: present
when:
- certbot_extension_packages | length
- name: Certbot - Install certbot extensions (pypi) - name: Certbot - Map plugin names to package names
ansible.builtin.pip: set_fact:
name: "{{ certbot_extension_pypi_packages }}" _certbot_plugins_used: "{{ [certbot_plugins_package_prefix] | product(_certbot_plugins_used) | map('join') | list }}"
state: present
when: - name: Certbot - Install extension packages
- certbot_extension_pypi_packages | length when:
- _certbot_plugins_used | length > 0
block:
- name: Certbot - Install certbot extensions (package manager)
ansible.builtin.package:
name: "{{ _certbot_plugins_used }}"
state: present
when:
- certbot_plugins_source == 'package_manager'
- name: Certbot - Install certbot extensions (pypi)
ansible.builtin.pip:
name: "{{ _certbot_plugins_used }}"
state: present
when:
- certbot_plugins_source == 'pypi'
- name: Certbot - Enable certbot renewal timer - name: Certbot - Enable certbot renewal timer
ansible.builtin.systemd: ansible.builtin.systemd:
name: "{{ certbot_timer_service }}" name: "{{ certbot_timer_service }}"
state: started state: started
enabled: true enabled: true
when: certbot_timer_service when: certbot_timer_service is defined

View File

@@ -2,8 +2,8 @@
- name: Certbot - Get OS specific vars - name: Certbot - Get OS specific vars
include_vars: "{{ item }}" include_vars: "{{ item }}"
with_first_found: with_first_found:
- "os/{{ ansible_os_family }}/{{ ansible_distribution_major_version }}.yaml" - "os/{{ ansible_facts['os_family'] }}/{{ ansible_facts['distribution_major_version'] }}.yaml"
- "os/{{ ansible_os_family }}.yaml" - "os/{{ ansible_facts['os_family'] }}.yaml"
- name: Certbot - Install Certbot - name: Certbot - Install Certbot
ansible.builtin.import_tasks: install.yaml ansible.builtin.import_tasks: install.yaml

View File

@@ -1,10 +1,10 @@
--- ---
- name: Certbot - Add host FQDN if not already listed in certs - name: Certbot - Add host FQDN if not already listed in certs
ansible.builtin.set_fact: ansible.builtin.set_fact:
certbot_certs: "{{ certbot_certs + [{'hostname': ansible_fqdn}] }}" certbot_certs: "{{ certbot_certs + [{'hostname': ansible_facts['fqdn']}] }}"
when: when:
- certbot_request_fqdn_cert - certbot_request_fqdn_cert
- certbot_certs | selectattr('hostname', 'equalto', ansible_fqdn) | list | length == 0 - certbot_certs | selectattr('hostname', 'equalto', ansible_facts['fqdn']) | list | length == 0
- name: Certbot - Request Certificate - name: Certbot - Request Certificate
ansible.builtin.include_tasks: cert.yaml ansible.builtin.include_tasks: cert.yaml

View File

@@ -1,3 +1,6 @@
--- ---
certbot_packages: certbot_packages:
- python3-certbot - python3-certbot
certbot_plugins_source: package_manager
certbot_plugins_package_prefix: python3-certbot-dns-

View File

@@ -1,7 +0,0 @@
---
certbot_extension_packages: []
certbot_extension_pypi_packages:
- certbot-dns-digitalocean
certbot_timer_service: certbot-renew.timer