|Patryk Cisek e6880ec2ed|
certbot-gandi Ansible Role
This role allows one to automate issuance of an wildcard Let's Encrypt X.509 certificate for a domain using gandi.
For example, if you own
example.com, this role will allow you to
automatically provision certificate for
Caveat: The certificate will be valid only for subdomains of
example.com!!! E.g. it will be valid for
yourcoolsubdomain.example.com, but it will not be valid for
I wrote this role to address specific use-case. I want to have an easy way to manage Let's Encrypt certificates for services that I self-host in my home network, but that are completely invisible outside my home. One way to achieve it is:
- I register a domain with gandi. E.g.
- At home I have my own DNS resolver. That could be for example something like pfSense, OPNSense, or even Pi-hole.
- On my private DNS resolver I add custom subdomains of
example.com. For example
- I use this Ansible role to generate Let's Encrypt certificate for
*.example.com, I hook it up to web-server (e.g. Nginx, Apache, whatever) that is hosting
mycoolservice.example.com is visible (resolvable) only from within
my home network. And the certificate that my private web-server presents is
valid on any device -- my computer, smartphone, tablet, TV, whatever -- without
any fiddling with accepting untrusted (e.g. self-signed, or signed by my own
custom CA) certificate.
- It creates
/srv/certbotdirectory. All activities except certbot logging will happen within subdirectories of
- It creates Python virtualenv in
/srv/certbot/venvand installs certbot with gandi plugin in it.
- It generates Bash scripts for issuing (
issue.sh) and renewing (
renew.sh) the certificate. They are placed in
/srv/certbot/example.com/workdir/directory (assuming your domain is
- Then it calls
issue.shto issue the certificate the very 1st time.
- It'll add a post-renew hook to certbot's config for reloading web server's configuration so that after renewing the certificate the web server reloads it.
- Adds a cron job to run
renew.shonce a day to check if the certificate needs renewing.
The generated certificate and corresponding key lands in
Pull in the role to your system
First off you have to add proper dependency to your project. Create -- if it
doesn't yet exist -- a file called
requirements.yaml. Then add the dependency
to it. If this role is the only one that your playbook is pulling in, then
requirements.yaml should look like this:
--- - src: git+https://codeberg.org/Prezu/certbot-gandi version: master name: certbot-gandi
Having that done, use
ansible-galaxy to pull the role in:
$ ansible-galaxy install -r requirements.yaml
This is a one-time thing. Once you pull the role it, it'll live in your
Using the role in a playbook
The role requires you to set up a couple of Ansible variables:
domain: This is the name of your domain. E.g.
gandi_api_token: The API token you generated on your gandi account page.
contact_email: Let's Encrypt requires you to provide a contact email address.
web_server_reload_command: A command that will be executed by certbot to reload your web server's configuration after renewing the certificate.
The simplest and least secure way
If you want to quickly test the role out, you could add the following section
roles in your playbook:
... roles: - role: certbot-gandi vars: domain: "example.com" contact_email: firstname.lastname@example.org gandi_api_token: 12345SLFDKSLFKJSD # Your generated API token web_server_reload_command: "systemctl reload nginx.service" # Assuming you're using Nginx
But you better not check that into your VCS!!!
Using ansible-vault to store the token
You should absolutely never check the bare API key to your version control
system. It's much better to use e.g.
ansible-vault to encrypt all security
sensitive variables. Ansible vault will maintain a file within your repository,
but the file will be encrypted.
Alright, so first you create the encrypted vault file:
$ mkdir vars $ ansible-vault create vars/secrets.yaml
You'll be asked to pick a password for your new file. Then, ansible-vault will automatically open an editor for you. You have to create the YAML with the sensitive variables. E.g.:
--- gandi_api_token: 12345SLFDKSLFKJSD # Your generated API token
Now when you save the file and quite the editor, take a look at the new file. It'll look similar to this:
$ cat vars/secrets.yaml $ANSIBLE_VAULT;1.1;AES256 38343062636539383830616436613162316536313465373236616566343034393937363665623466 3730613361363038613438376630393930373865343433660a636437396637663239363466363665 64386434663862666664323765373838346136326238316237383736373063393432333863373430 3364396133633933630a646434353937336233653430373166396139666539326239323463613132 39316163383364333836326639616339396333313534383663393737616363333336623033373833 38626430396264666365646366363530646462356637323533323962613866623561636363303339 36656335633535353565326339623463336265363663333661316562313730643234626265353938 30646631303330393464
So this is what you add to your VCS. So now in your runbook you'll need to point to the encrypted vars file:
... vars_files: - vars/secrets.yaml ... roles: - role: certbot-gandi vars: domain: "example.com" contact_email: email@example.com web_server_reload_command: "systemctl reload nginx.service" # Assuming you're using Nginx # That's it. gandi_api_token will be picked up from vars/secret.yaml instead of from here.
Now, from this point on, you'll need to pass a new parameter to
--ask-vault-pass. This will make ansible ask you
the Vault password each time you execute the runbook.