4

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 Answer 1

8

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.

1
  • How would one email these results instead of just standard output? Commented Jun 3, 2021 at 16:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .