Skip to content

cj667113/openstack_designate_certbot_renewal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

openstack_designate_certbot_renewal

Automate Let's Encrypt DNS-01 certificate renewal with:

  • certbot (manual DNS mode)
  • OpenStack Designate via Terraform for _acme-challenge TXT records
  • Optionally: Ansible to distribute renewed certificates to remote hosts

This repo is intentionally generic: no company-specific values. Everything is driven by variables or placeholders.


Directory Layout

.
├── terraform/
│   ├── _txt.tf
│   ├── provider.tf
│   ├── variables.tf
│   └── terraform.tfvars.example
├── hooks/
│   ├── create_txt.sh
│   ├── clean_txt.sh
│   └── ip_addr.sh
├── ansible/
│   ├── distribute_certs.yaml
│   └── inventory.yaml.example
└── cron/
    └── cron_example.txt

Requirements

On the host running certbot (the "control" host):

  • certbot
  • terraform
  • openstack terraform provider
  • ansible (only if you want distribution)
  • OpenStack Designate access (DNS zone already created)
  • SSH access from control host to target hosts where certs will be deployed (for Ansible mode)

1. Terraform: Designate TXT Record

Edit terraform/terraform.tfvars.example and copy it to terraform/terraform.tfvars:

zone_id     = "YOUR_DESIGNATE_ZONE_ID"

# For a wildcard covering *.example.com and example.com itself:
# base_domain = "example.com"
#
# For a single host like test.example.com:
# base_domain = "test.example.com"
base_domain = "example.com"

# Optional overrides
record_name = "_acme-challenge"
record_ttl  = 10

Configure OpenStack credentials either via OS_* environment variables or by uncommenting provider attributes in terraform/provider.tf.

You can test the record creation manually before integrating with certbot:

cd terraform
terraform init
terraform apply -auto-approve -var="challenge=test-value"
terraform destroy -auto-approve -var="challenge=test-value"

2. Certbot DNS Hooks

The hook scripts live in hooks/:

  • create_txt.sh – creates the TXT record for the current ACME challenge
  • clean_txt.sh – deletes the TXT record afterward
  • ip_addr.sh – small helper to output a JSON object with the IP of a given interface

By default, the scripts assume:

  • they’re installed under /opt/certbot_dns/hooks
  • the Terraform project is /opt/certbot_dns/terraform

You can override the Terraform directory with CERTBOT_DNS_TERRAFORM_DIR:

export CERTBOT_DNS_TERRAFORM_DIR=/some/other/path/terraform

ip_addr.sh uses the interface from CERTBOT_LOCAL_IFACE or falls back to eth0:

export CERTBOT_LOCAL_IFACE=enp3s0
./hooks/ip_addr.sh

Don’t forget to make the scripts executable:

chmod +x hooks/*.sh

3. Ansible: Distribute Certificates (Optional)

ansible/distribute_certs.yaml copies fullchain.pem and privkey.pem from the control host to each target host.

  1. Define your target hosts in ansible/inventory.yaml.example and copy to inventory.yaml:

    all:
      hosts:
        web1.example.com:
        web2.example.com:
  2. Run the playbook manually to test:

    ansible-playbook      -i ansible/inventory.yaml      ansible/distribute_certs.yaml      -u ubuntu      --private-key /path/to/ansible_private_key      -e "local_cert_dir=/opt/certificates"      -e "remote_cert_dir=/opt/certificates"
  • local_cert_dir is where the certbot-renewed certs live on the control host (default /opt/certificates).
  • remote_cert_dir is where you want them on the target hosts (also default /opt/certificates).

4. Usage Modes

You can use this project in two main ways.

Mode A: Full Flow (DNS + Distribution)

This is the "all-in" mode: certbot, Designate via Terraform, copy certs locally, then distribute via Ansible.

Example for a wildcard certificate (*.example.com):

CERTBOT_DNS_TERRAFORM_DIR=/opt/certbot_dns/terraform certbot certonly   --manual   --preferred-challenges dns   --manual-auth-hook /opt/certbot_dns/hooks/create_txt.sh   --manual-cleanup-hook /opt/certbot_dns/hooks/clean_txt.sh   --agree-tos   --email you@example.com   -d "*.example.com"   --force-renewal

After certbot succeeds, you might copy and distribute:

cp -f /etc/letsencrypt/live/example.com/*.pem /opt/certificates/

ansible-playbook   -i ansible/inventory.yaml   ansible/distribute_certs.yaml   -u ubuntu   --private-key /path/to/ansible_private_key   -e "local_cert_dir=/opt/certificates"   -e "remote_cert_dir=/opt/certificates"

The cron/cron_example.txt file includes a combined one-liner that chains all of this in a single cron job.

Mode B: DNS-Only (No Distribution)

This mode is useful when you:

  • Only care about getting the cert on the control host, or
  • Want to handle distribution separately (systemd reload scripts, custom tooling, etc.).

Example for a single host certificate (test.example.com):

CERTBOT_DNS_TERRAFORM_DIR=/opt/certbot_dns/terraform certbot certonly   --manual   --preferred-challenges dns   --manual-auth-hook /opt/certbot_dns/hooks/create_txt.sh   --manual-cleanup-hook /opt/certbot_dns/hooks/clean_txt.sh   --agree-tos   --email you@example.com   -d test.example.com   --force-renewal

In this case, certbot will store the certificate under:

/etc/letsencrypt/live/test.example.com/

You can then:

  • Symlink or copy those files into place for a local service, or
  • Run the Ansible playbook later, if you wish, with local_cert_dir pointing at the appropriate path.

5. Wiring It Together with Cron

See cron/cron_example.txt for sample cron lines for both modes.

A typical full-flow setup (run as root) looks like:

@daily certbot certonly   --manual   --preferred-challenges dns   --manual-auth-hook /opt/certbot_dns/hooks/create_txt.sh   --manual-cleanup-hook /opt/certbot_dns/hooks/clean_txt.sh   --agree-tos   --email you@example.com   -d "*.example.com"   --force-renewal   && cp -f /etc/letsencrypt/live/example.com/*.pem /opt/certificates/   && ansible-playbook        -i /opt/certbot_dns/ansible/inventory.yaml        /opt/certbot_dns/ansible/distribute_certs.yaml        -u ubuntu        --private-key /path/to/ansible_private_key        --ssh-common-args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'

And a DNS-only setup (no distribution) might be:

@daily CERTBOT_DNS_TERRAFORM_DIR=/opt/certbot_dns/terraform certbot certonly   --manual   --preferred-challenges dns   --manual-auth-hook /opt/certbot_dns/hooks/create_txt.sh   --manual-cleanup-hook /opt/certbot_dns/hooks/clean_txt.sh   --agree-tos   --email you@example.com   -d test.example.com   --force-renewal

Adjust paths, email, domains, and SSH user/key to your environment.


6. Notes & Tips

  • Start by running each piece manually (Terraform apply/destroy, hooks, Ansible) before relying on cron.
  • Use a staging ACME endpoint (e.g., Let’s Encrypt staging) while testing to avoid rate limits.
  • Add logging around your hooks and Ansible run if you want more visibility from cron.
  • If you don't use Ansible, you can replace the last part of the full-flow cron line with any script that restarts services or reloads load balancers, etc.

About

Certificate Renewal with Certbot + Designate + Terraform

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors