An Ansible role that allows one to automate Let's Encrypt certificate issuance and update using [gandi](https://gandi.net)'s LiveDNS service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Patryk Cisek 02df4cbfc0 Added info on where the generated certificates land to the README. 3 months ago
meta Started the work on the role. Installing packages and creating user and corresponding venv. 3 months ago
tasks Abandoned certificator user. Using root instead with proper post-renew hook. 3 months ago
templates Replaced "source" with "." in {issue,renew}.sh scripts as they're not necessarily bash. 3 months ago
LICENSE Initial commit 3 months ago
README.md Added info on where the generated certificates land to the README. 3 months ago

README.md

certbot-gandi Ansible Role

This role allows one to automate issuance of an asterisk 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 *.example.com.

Caveat: The certificate will be valid only for subdomains of example.com!!! E.g. it will be valid for www.example.com, yourcoolsubdomain.example.com, but it will not be valid for example.com itself!

Why?

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:

  1. I register a domain with gandi. E.g. example.com
  2. At home I have my own DNS resolver. That could be for example something like pfSense, OPNSense, or even Pi-hole.
  3. On my private DNS resolver I add custom subdomains of example.com. For example mycoolservice.example.com.
  4. 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 locally.

This way 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.

How?

  1. It creates /srv/certbot directory. All activities except certbot logging will happen within subdirectories of /srv/certbot.
  2. It creates Python virtualenv in /srv/certbot/venv and installs certbot with gandi plugin in it.
  3. 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 example.com).
  4. Then it calls issue.sh to issue the certificate the very 1st time.
  5. 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.
  6. Adds a cron job to run renew.sh once a day to check if the certificate needs renewing.

The generated certificate and corresponding key lands in /srv/certbot/example.com/config/live/example.com/ directory.

Quick start

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:

---
roles:
  - src: https://codeberg.org/Prezu/certbot-gandi.git

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 ~/.ansible/roles subdirectory.

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. example.com.
  • 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 to your roles in your playbook:

...
roles:
  - role: certbot-gandi
    vars:
      domain: "example.com"
      contact_email: contact@example.com
      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: contact@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 ansible-playbook, namely --ask-vault-pass. This will make ansible ask you the Vault password each time you execute the runbook.