ansible-collections / community.crypto

The community.crypto collection for Ansible.
https://galaxy.ansible.com/ui/repo/published/community/crypto/
Other
97 stars 88 forks source link

ACME - Let's Encrypt - Unable to get renewal info #801

Closed lunix33 closed 6 days ago

lunix33 commented 6 days ago
SUMMARY

I've been trying to setup an ACME deployment pipeline using Ansible, but when trying to get the renewal information for a certificate, I've noticed the request is not properly formatted. The function in the ACME client taking care of formatting the URL doesn't add a slash between the directory URL and the certificate id (see: https://github.com/ansible-collections/community.crypto/blob/2d82f49adc1e8281721bedc80de7ed9f3d5d22a2/plugins/module_utils/acme/acme.py#L407). When looking at the ACME directory of Lets Encrypt, the URL doesn't end with a slash, and seems to be used as-is. This causes the request to error with a 404.

ISSUE TYPE
COMPONENT NAME
ANSIBLE VERSION
ansible [core 2.17.4]
  config file = /home/lunix/projects/Homelab/ansible.cfg
  configured module search path = ['/home/lunix/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/lunix/.pyenv/versions/3.12.2/lib/python3.12/site-packages/ansible
  ansible collection location = /home/lunix/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/lunix/.pyenv/versions/3.12.2/bin/ansible
  python version = 3.12.2 (main, Apr 10 2024, 01:11:49) [GCC 13.2.1 20230801] (/home/lunix/.pyenv/versions/3.12.2/bin/python3.12)
  jinja version = 3.1.4
  libyaml = True
COLLECTION VERSION
Collection       Version
---------------- -------
community.crypto 2.22.0
CONFIGURATION
CALLBACKS_ENABLED(/home/lunix/projects/Homelab/ansible.cfg) = ['ansible.posix.debug']
CONFIG_FILE() = /home/lunix/projects/Homelab/ansible.cfg
DEFAULT_HOST_LIST(/home/lunix/projects/Homelab/ansible.cfg) = ['/home/lunix/projects/Homelab/inventory']
DEFAULT_ROLES_PATH(/home/lunix/projects/Homelab/ansible.cfg) = ['/home/lunix/projects/Homelab/roles']
DEFAULT_STDOUT_CALLBACK(/home/lunix/projects/Homelab/ansible.cfg) = ansible.posix.debug
DEFAULT_VERBOSITY(/home/lunix/projects/Homelab/ansible.cfg) = 1
OS / ENVIRONMENT

LSB Version: n/a Distributor ID: Arch Description: Arch Linux Release: rolling Codename: n/a

STEPS TO REPRODUCE
- community.crypo.openssl_privatekey:
    path: "/account_key.pem"
- community.crypo.acme_account:
    account_key_src: /account_key.pem
    acme_directory: "https://acme-staging-v02.api.letsencrypt.org/directory"
    acme_version: 2
    terms_agreed: true
    contact: [ "mailto:my-email@somewhere.com" ]
- community.crypto.openssl_privatekey:
    path: "/privatekey.pem"
- community.crypto.openssl_csr:
    path: "/csr.pem"
    privatekey_path: "/privatekey.pem"
    subject_alt_name:
      - "DNS:my.domain.com"
- community.crypto.acme_certificate:
    [...]
    dest: /cert.pem
  register: challenge
[...]
- community.crypto.acme_certificate:
    [...]
    dest: /cert.pem
    data: "{{ challenge }}"
- community.crypto.acme_certificate_renewal_info:
    acme_directory: "https://acme-staging-v02.api.letsencrypt.org/directory"
    acme_version: 2
    certificate_path: "/cert.pem"
    remaining_days: 30
  register: renew_info
- debug:
    var: renew_info
EXPECTED RESULTS

I'd expect the command to be successful to know if the certificate is due for renewal

ACTUAL RESULTS

The command error with a 404 status when trying to reach the ACME directory

The full traceback is:
  File "/tmp/ansible_community.crypto.acme_certificate_renewal_info_payload__flx93fi/ansible_community.crypto.acme_certificate_renewal_info_payload.zip/ansible_collections/community/crypto/plugins/modules/acme_certificate_renewal_info.py", line 200, in main
    renewal_info = client.get_renewal_info(cert_id=cert_id)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ansible_community.crypto.acme_certificate_renewal_info_payload__flx93fi/ansible_community.crypto.acme_certificate_renewal_info_payload.zip/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py", line 409, in get_renewal_info
    data, info = self.get_request(url, parse_json_result=True, fail_on_error=True, get_only=True)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ansible_community.crypto.acme_certificate_renewal_info_payload__flx93fi/ansible_community.crypto.acme_certificate_renewal_info_payload.zip/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py", line 389, in get_request
    raise ACMEProtocolException(
fatal: [kraken]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "acme_directory": "https://acme-staging-v02.api.letsencrypt.org/directory",
            "acme_version": 2,
            "ari_algorithm": "standard",
            "certificate_content": null,
            "certificate_path": "/var/ssl/media.lunix.pro/cert.pem",
            "now": null,
            "remaining_days": 30,
            "remaining_percentage": null,
            "request_timeout": 10,
            "select_crypto_backend": "auto",
            "use_ari": true,
            "validate_certs": true
        }
    },
    "other": {
        "http_status": 404,
        "http_url": "https://acme-staging-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfoE8vX9q6d_GlCZNZcfCPMhflHx7Y.K3InqPeADAHkuiPWQLQ0OrNe"
    }
}

MSG:

ACME request failed for https://acme-staging-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfoE8vX9q6d_GlCZNZcfCPMhflHx7Y.K3InqPeADAHkuiPWQLQ0OrNe with HTTP status 404 Not Found. The raw error result: 404 page not found
felixfontein commented 6 days ago

Hmm, my guess is that this changed over time, since it did work when I first implemented it. The Pebble implementation still has a final slash in the renewalInfo URL. Edit: I just saw that it also removes the trailing /.

And indeed, here's the change in Boulder: https://github.com/letsencrypt/boulder/commit/d19f70407cd6c20acc15bf8af39115f7ce34cd94

felixfontein commented 6 days ago

802 should fix this.

lunix33 commented 6 days ago

Thanks for the quick fix. Can't wait to see the next release so I can test it out for myself.

felixfontein commented 6 days ago

I'll wait 1-2 more days for possible feedback on #799 (unrelated PR to this issue) and will create a new bugfix release once that's merged.