Support any provided plugin via auto-installation

This commit is contained in:
2025-07-19 11:29:56 +01:00
parent 44174f00d9
commit e0b88c6dad
6 changed files with 186 additions and 27 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

@@ -12,10 +12,7 @@ certbot_plugin_arguments:
certbot_packages:
- certbot
certbot_extension_packages:
- python3-certbot-dns-digitalocean
- python3-certbot-dns-route53
certbot_extension_pypi_packages: []
certbot_plugins_source: pypi
certbot_plugins_package_prefix: certbot-dns-
certbot_timer_service: certbot.timer

View File

@@ -3,11 +3,14 @@
ansible.builtin.stat:
path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem"
register: cert_stat
check_mode: false
- name: Certbot - Get the SANs from the certificate file
community.crypto.x509_certificate_info:
path: "/etc/letsencrypt/live/{{ item.hostname }}/cert.pem"
register: cert_info
changed_when: false
check_mode: false
when: cert_stat.stat.exists
- name: Certbot - Calculate the SAN list
@@ -15,6 +18,6 @@
cert_sans: "{{ ['DNS:'] | product(item.sans | default([item.hostname])) | map('join') | list }}"
- 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 }}" # 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
when: not cert_stat.stat.exists or cert_sans | difference(cert_info.subject_alt_name) | list | length > 0

View File

@@ -4,23 +4,31 @@
name: "{{ certbot_packages }}"
state: present
- name: Certbot - Install certbot extensions (package manager)
ansible.builtin.package:
name: "{{ certbot_extension_packages }}"
state: present
when:
- certbot_extension_packages | length
- name: Certbot - Build plugin list
set_fact:
_certbot_plugins_used: "{{ certbot_certs | map(attribute='plugin') | list | unique | map('format', certbot_plugins_package_prefix + '%s') | list }}"
- name: Certbot - Install certbot extensions (pypi)
ansible.builtin.pip:
name: "{{ certbot_extension_pypi_packages }}"
state: present
when:
- certbot_extension_pypi_packages | length
- name: Certbot - Install extension packages
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
ansible.builtin.systemd:
name: "{{ certbot_timer_service }}"
state: started
enabled: true
when: certbot_timer_service
when: certbot_timer_service

View File

@@ -1,3 +1,6 @@
---
certbot_packages:
- 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