1

I am trying to figure out how to get a list of .crt files from one of our web servers and check the expiration date of these certification files (actually check if these certs are valid within a time range). What I have so far is the following .yml playbook code:

#
# simple playbook to check certificates expiration date

- name: find cerfication files & expiration dates
  hosts: 10.0.1.120
  gather_facts: false

  tasks:
    - name: Find cert files under /etc/pki/tls/certs
      find:
        paths: /etc/pki/tls/certs
        file_type: file
        patterns: "*.crt"
        recurse: yes
        excludes: "localhost.crt"
      register: find_result

    - name: check validity
      openssl_certificate_info:
        path: "{{ item.path }}"
        valid_at:
          point_1: "+1w"
          point_2: "+10w"
      register: result
      loop: "{{ find_result.files|flatten(levels=1) }}"

    #- name: validate
      #assert:
        #that:
          #- result.valid_at.point_1
          #- result.valid_at.point_2

    - debug: msg= "{{ result }}"

The result of the above debug msg is the following:

TASK [debug] ****************************************************************************
ok: [10.0.1.120] => {
    "msg": ""
}

I left the assert module with comments, so can also check the other output that I was trying to get by using the assert module and get a passed/failed message for each result (point_1 & point_2). If I give the .crt path hardcoded and with no loop, I get the exams that I am looking for, but when I try with the loop command, assert module is not running as expected and I am getting a dict object error, like the following one:

fatal: [10.0.1.120]: FAILED! => {"msg": "The conditional check 'result.valid_at.point_1' failed. The error was: error while evaluating conditional (result.valid_at.point_1): 'dict object' has no attribute 'valid_at'"}

Extra info regarding my ansible hosting server:

  • Server distro: CentOS-7
  • Ansible version: 2.8.1

So guys, any suggestions on how to get this loop run properly in order the get the passed/failed messages that I want for every .crt file that can be found under the /etc/pki/tls/certs path (except the localhost.crt)?

1

Ok... it took me a while to figure out why your debug result was inconsistent with my tests. You have an error there:

- debug: msg= "{{ result }}"

should be (notice the space that is gone)

- debug: msg="{{ result }}"

and even better be (do yourself a favor for future debugging hell, adopt full yaml syntax)

- debug:
    msg: "{{ result }}"

Now that's fixed, you will clearly see that result.someWhateverCertValue does not exist. Since you used a loop in your certificate info task, each individual module run is reported in a list: result.results[]

If you still want to use assert, you will have to loop again on each result:

- name: validate
  assert:
    that:
      - item.valid_at.point_1 | bool
      - item.valid_at.point_2 | bool
  loop: "{{ result.results }}"

The above should do the job: assert will run on each certificate info result and the playbook will exit with a fail if any of the checks does not meet the requirements.

The result might be a little hard to read though. I would do this slightly differently to maybe get a better output:

- name: find cerfication files & expiration dates
  hosts: my_host
  gather_facts: false

  tasks:
    - name: Find cert files under /etc/pki/tls/certs
      find:
        paths: /etc/pki/tls/certs
        file_type: file
        patterns: "*.crt"
        recurse: yes
        excludes: "localhost.crt"
      register: find_result

    - name: Check validity
      openssl_certificate_info:
        path: "{{ item.path }}"
        valid_at:
          point_1: "+1w"
          point_2: "+10w"
      register: cert_info
      loop: "{{ find_result.files }}"

    - name: Filter out valid certs
      set_fact:
        outdated_certs: "{{ cert_info | json_query('results[? !(valid_at.point_1) || !(valid_at.point_2)]') }}"

    - block:
        - name: Check that all certificates are valid
          assert:
            that:
              - outdated_certs | count == 0

      rescue:
        - name: Show info about outdated certs
          debug:
            msg: >-
              {{ { "Outdated Certs": outdated_certs | json_query("[].item.path") } }}

        - fail:
            msg: "Outdated certs found. See list above"

Last side note: I don't really get why you need two date checks. Since you consider that any fail in date makes the cert invalid, checking for the furthest one should be sufficient. I kept all tests in my examples so you know how to modify that if there is something I missed.

  • Yep, that did the trick. I can't believe that I have wasted so many hours just for an empty space. Thank you very much for your response and also for the playbook improvement. – blametheadmin Jul 10 at 10:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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