How can I issue a Let's Encrypt certificate with Ansible when 'challenge_data' cannot be found? I am attempting to use the Ansible acme_certificate module to acquire a Let's Encrypt TLS certificate.

I have successfully generated the private keys, CSRs, etc, and then started the challenge using the following task:

- name: Start challenge
  acme_certificate:
    acme_version: 1
    account_key_src: /etc/letsencrypt/account/account.key
    challenge: http-01
    csr: /etc/letsencrypt/csrs/{{ item }}.csr
    dest: /etc/letsencrypt/certs/{{ item }}.crt
    fullchain_dest: /etc/letsencrypt/certs/fullchain_{{ item }}.crt
  with_items:
  - www.example.com
  register: acme_challenge


I then attempt to satisfy the http-01 challenge using:

- name: Implement challenge
  copy:
    content: "{{ acme_challenge['results']['challenge_data']['www.example.com']['http-01']['resource-value'] }}"
    dest: "/var/www/html/{{ acme_challenge['results']['challenge_data']['www.example.com']['http-01']['resource'] }}"
    owner: root
    group: root
    mode: u=rw,g=r,o=r


However, this results in the following error:

The error was: 'list object' has no attribute 'challenge_data'

I have tried accessing the acme_challenge variable in different ways, for example using {{ acme_challenge.challenge_data['www.example.com']['http-01']['resource'] }}, as well of various other combinations of square brackets and dots.

I've also copied the example of accessing the variable directly from the Ansible documentation, here and here, but that gives the same error.

After around 3 hours of trying I cannot read the challenge data at all. I've used a debug statement and I can confirm that it's all there properly, I just can't read the variable with this syntax.

Is this a known problem, or does anybody have a suggestion?
This was caused by the fact that I was starting the Let's Encrypt challenges using a with_items loop. From here:


  When using register with a loop, the data structure placed in the variable during the loop will contain a results attribute, that is a list of all responses from the module. For a more in-depth example of how this works, see the Loops section on using register with a loop.


The solution is to have a separate task for each Let's Encrypt challenge, rather than having them all in one.