1

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?

2 Answers 2

1

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.

1

For those searching, I found this post while experiencing the same issue. I was able to resolve this by adding the array index to my loop:

  copy:
    content: "{{ acme_challenge_your_domain['results'][ansible_loop.index0]['challenge_data'][item.hostname]['http-01']['resource_value'] }}"
    dest: "/var/www/{{ item.hostname }}/{{ acme_challenge_your_domain['results'][ansible_loop.index0]['challenge_data'][item.hostname]['http-01']['resource'] }}"
    owner: root
    group: root
    mode: u=rw,g=r,o=r
  loop: "{{ hosted_sites }}"
  loop_control:
    loop_var: item
    extended: yes

The specific changes here being converting with_items to a loop and adding the loop_control parameter extended. This allows for usage of ansible_loop.index0.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.