Ansible NetApp ONTAP certificate report

This post will cover how to use Ansible to gather information from many NetApp ONTAP clusters using REST and generate a report of all server certificates.

Intro

NetApp ONTAP uses different types of certificates to secure communications and data, and if you have a large number of systems – tracking the expiry dates can become a bit of a challenge.

These certificates include:

  • Server certificates: These certificates are used to authenticate ONTAP servers to clients. They are installed on each cluster or SVM and are used to secure HTTPS connections.
  • Client certificates: These certificates are used to authenticate clients to ONTAP servers. They can be used to secure SSH connections, API access, and other types of client-server communication.
  • CA certificates: These certificates are used to sign other certificates. They are used to create a chain of trust that allows clients to verify the authenticity of server and client certificates.
  • CA-signed certificates: These certificates are created and signed by an enterprise certificate authority. They are often used in production for cluster or SVM certificates.
  • Self-signed certificates: These certificates are created and signed by the same entity. They are often used for testing or for small deployments where a CA is not necessary.

This post will focus on server certificates, both CA-issued and self-signed and detail a way to create and schedule an ONTAP certificate report using Jenkins/Ansible.

ONTAP Certificate Report

Normally a NetApp ONTAP cluster will have the following certificates: a cluster scope certificate which is most frequently used by the ONTAP System Manager and a svm scope self-signed certificate for each SVM (vserver). And depending on the number of clusters and SVMs, the total number of certificates can range from dozens to thousands of certificates.

The following report is one I have implemented for a number of customers and executed regularly by Jenkins. It uses the official NetApp ONTAP Collection collection netapp.ontap.

Variables

In our variables section we first define the list of our ONTAP clusters using ontap_clusters as well as the variables needed to send the ONTAP certificate report.

  vars:
    ontap_clusters:
      - cluster1_hostname
      - cluster2_hostname
    ontap_fields: [common_name, serial_number, ca, type, expiry_time, scope]
    certs: "{{ dict(certificate_info.results|json_query(certs_query)) }}"
    certs_query: '[].[item, ontap_info."security/certificates".records]'
    csv_file_path: /var/lib/jenkins/workspace/Infra-NetApp_certificates_report/netapp_certificate_details.csv
    sender: sender@domain.com
    recipient: recipient@domain.com
    mailrelay: fqdn_of_mailrelay
    template_vars:
      subject: NetApp Storage Certificate Report
      body: 'Attached is the list of certificates for all clusters (this includes both cluster and svm certificates). Please review and renew as needed.'
YAML

Additionally, the three lines for ontap_fields, certs and certs_query are used to organize the data but more on that later.

Tasks

There are three ansible tasks in our playbook.

run ONTAP gather facts for certificate info with specified fields

The first playbook uses the module netapp.ontap.na_ontap_rest_info which gathers various information about ONTAP configuration using REST APIs. In our case, the focus is on security/certificates and only certain fields are stored in the certificate_info variable: common_name, serial_number, ca, type, expiry_time, scope.

  - name: run ONTAP gather facts for certificate info with specified fields
    netapp.ontap.na_ontap_rest_info:
      hostname: "{{ item }}"
      username: "{{ lookup('env', 'ontap_admin_usr') }}"
      password: "{{ lookup('env', 'ontap_admin_pwd') }}"
      use_rest: always
      https: true
      validate_certs: false
      gather_subset:
        - security/certificates
      fields:
        - 'common_name'
        - 'serial_number'
        - 'ca'
        - 'type'
        - 'expiry_time'
        - 'scope'
      parameters:
        type: server
    loop: "{{ ontap_clusters }}"
    register: certificate_info
YAML

Unfortunately, the information required is rather lengthy (JSON) and not particularly easy to reason.

copy the results to CSV

For the purposes of this report, we will tidy up and export the results to CSV which we can later e-mail.

In the variable section above we had the following three lines. The first one simply defines the fields which will be our “CSV header”. The other two define what is known as a dictionary in abstract transformations:

    ontap_fields: [common_name, serial_number, ca, type, expiry_time, scope]
    certs: "{{ dict(certificate_info.results|json_query(certs_query)) }}"
    certs_query: '[].[item, ontap_info."security/certificates".records]'
YAML

Finally, in our task, we define the header using “{{ ontap_fields|join(‘,’) }}” and then create a line for each certificate:

  - name: copy the results to CSV
    copy:
      dest: "{{ csv_file_path }}"
      content: |
        {{ ontap_fields|join(',') }}
        {% for cluster,certs in certs.items() %}
        {% for cert in certs %}
        {{ ontap_fields|map('extract', cert)|join(',') }}
        {% endfor %}
        {% endfor %}
YAML
send the results by e-mail

The following is the simplest way to e-mail the contents of our report to the interested parties

  - name: send the results by e-mail
    mail:
      host: "{{ mailrelay }}"
      port: 25
      subject: "{{ template_vars.subject }}"
      body: "{{ template_vars.body }}"
      from: "{{ sender }}"
      to: "{{ recipient }}"
      attach:
      - "{{ csv_file_path }}"
    delegate_to: localhost
YAML
Full Playbook code
---
- name: NetApp Certificate Expiry Reporting
  hosts: localhost
  gather_facts: no
  collections:
    - netapp.ontap

  vars:
    ontap_clusters:
      - cluster1_hostname
      - cluster2_hostname
    ontap_fields: [common_name, serial_number, ca, type, expiry_time, scope]
    certs: "{{ dict(certificate_info.results|json_query(certs_query)) }}"
    certs_query: '[].[item, ontap_info."security/certificates".records]'
    csv_file_path: /var/lib/jenkins/workspace/Infra-NetApp_certificates_report/netapp_certificate_details.csv
    sender: sender@domain.com
    recipient: recipient@domain.com
    mailrelay: fqdn_of_mailrelay
    template_vars:
      subject: NetApp Storage Certificate Report
      body: 'Attached is the list of certificates for all clusters (this includes both cluster and svm certificates). Please review and renew as needed.'
    
  tasks:
  - name: run ONTAP gather facts for certificate info with specified fields
    netapp.ontap.na_ontap_rest_info:
      hostname: "{{ item }}"
      username: "{{ lookup('env', 'ontap_admin_usr') }}"
      password: "{{ lookup('env', 'ontap_admin_pwd') }}"
      use_rest: always
      https: true
      validate_certs: false
      gather_subset:
        - security/certificates
      fields:
        - 'common_name'
        - 'serial_number'
        - 'ca'
        - 'type'
        - 'expiry_time'
        - 'scope'
      parameters:
        type: server
    loop: "{{ ontap_clusters }}"
    register: certificate_info

  - name: copy the results to CSV
    copy:
      dest: "{{ csv_file_path }}"
      content: |
        {{ ontap_fields|join(',') }}
        {% for cluster,certs in certs.items() %}
        {% for cert in certs %}
        {{ ontap_fields|map('extract', cert)|join(',') }}
        {% endfor %}
        {% endfor %}
  
  - name: send the results by e-mail
    mail:
      host: "{{ mailrelay }}"
      port: 25
      subject: "{{ template_vars.subject }}"
      body: "{{ template_vars.body }}"
      from: "{{ sender }}"
      to: "{{ recipient }}"
      attach:
      - "{{ csv_file_path }}"
    delegate_to: localhost
YAML

NetApp_Certificates_Report.yml

Leave a Reply

Your email address will not be published. Required fields are marked *