13 |
14 |
15 | {% if hostvars[linux_host]['services'] is defined %}
16 | {% for servicesname in hostvars[linux_host]['services']|sort %}
17 | {% set service = hostvars[linux_host]['services'][servicesname] %}
18 |
31 |
--------------------------------------------------------------------------------
/roles/build_report_google/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: Ensure Apache is installed
2 | ansible.builtin.yum:
3 | name: httpd
4 | state: present
5 |
6 | - name: Ensure Apache is started
7 | ansible.builtin.service:
8 | name: httpd
9 | state: started
10 |
11 | - name: Create HTML report if jinja include works
12 | ansible.builtin.template:
13 | src: report.j2
14 | dest: "{{ file_path }}/cloudgoogledetailed.html"
15 | owner: root
16 | group: root
17 | mode: '0644'
18 | when: not usesingletemplate
19 |
20 | - name: Create HTML report if jinja include doesn't work
21 | ansible.builtin.template:
22 | src: fullreport.j2
23 | dest: "{{ file_path }}/cloudgoogledetailed.html"
24 | owner: root
25 | group: root
26 | mode: '0644'
27 | when: usesingletemplate
28 |
29 | - name: Copy CSS over
30 | ansible.builtin.copy:
31 | src: "css"
32 | dest: "{{ file_path }}"
33 | directory_mode: true
34 | owner: root
35 | group: root
36 | mode: '0644'
37 |
38 | - name: Copy logos over
39 | ansible.builtin.copy:
40 | src: "{{ item }}"
41 | dest: "{{ file_path }}"
42 | directory_mode: true
43 | owner: root
44 | group: root
45 | mode: '0644'
46 | loop:
47 | - "webpage_logo.png"
48 | - "redhat-ansible-logo.svg"
49 | - "gcp.png"
50 |
51 | - name: Display link to inventory report
52 | ansible.builtin.debug:
53 | msg: "Please go to http://{{ ansible_host }}/cloudgoogledetailed.html"
54 |
--------------------------------------------------------------------------------
/roles/build_report_network/README.md:
--------------------------------------------------------------------------------
1 | build_report_network
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from network devices. Use in combination with facts modules for different Networking devices.
5 |
6 | Requirements
7 | ------------
8 |
9 | Must run on Apache server
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | N/A
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html report on any number of Linux hosts using any number of network devices
25 |
26 |
27 | ```
28 | ---
29 | - name: Build Networking Device Report
30 | hosts: all
31 | gather_facts: false
32 |
33 | tasks:
34 |
35 | - name: Grab Arista eos facts
36 | arista.eos.eos_facts:
37 | gather_subset: 'min'
38 | gather_network_resources: all
39 | register: eosfacts
40 |
41 | - name: Grab Cisco ios facts
42 | cisco.ios.ios_facts:
43 | gather_subset: 'min'
44 | gather_network_resources: all
45 | register: iosfacts
46 |
47 | - name: Grab vyos facts
48 | vyos.vyos.vyos_facts:
49 | gather_subset: 'min'
50 | gather_network_resources: all
51 | register: vyosfacts
52 |
53 | - name: Build the report
54 | ansible.builtin.include_role:
55 | name: shadowman.reports.build_report_network
56 | apply:
57 | delegate_to: report.shadowman.dev
58 | run_once: true
59 |
60 | ```
61 |
--------------------------------------------------------------------------------
/roles/build_report_windows/README.md:
--------------------------------------------------------------------------------
1 | build_report_windows
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from Windows services and packages modules. Utilize var "detailedreport=false" if you do not need packages or services information. Use in combination with win_scan_packages and win_scan_services modules included in the collection
5 |
6 |
7 | Requirements
8 | ------------
9 |
10 | Must run on Apache server
11 |
12 | Role Variables / Configuration
13 | --------------
14 |
15 | N/A
16 |
17 | Dependencies
18 | ------------
19 |
20 | N/A
21 |
22 | Example Playbook
23 | ----------------
24 |
25 | The role can be used to create an html report on any number of Linux hosts using any number of Windows servers about their services and packages installed. Added in a boolean var usesingletemplate if running into issues with jinja not adding in the package/services facts.
26 |
27 |
28 | ```
29 | ---
30 | - name: Create Windows Report
31 | hosts: all
32 | tasks:
33 |
34 | - name: "Scan packages (Windows)"
35 | shadowman.reports.win_scan_packages:
36 | when: ansible_os_family == "Windows"
37 |
38 | - name: "Scan services (Windows)"
39 | shadowman.reports.win_scan_services:
40 | when: ansible_os_family == "Windows"
41 |
42 | - name: Build the report
43 | ansible.builtin.include_role:
44 | name: shadowman.reports.build_report_windows
45 | apply:
46 | delegate_to: report.shadowman.dev
47 | run_once: true
48 |
49 | ```
50 |
--------------------------------------------------------------------------------
/roles/build_report_linux_patch/README.md:
--------------------------------------------------------------------------------
1 | build_report_linux_patch
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from RHEL patching. Could be expanded for patching other Linux distros but would require reviewing json output
5 |
6 | Requirements
7 | ------------
8 |
9 | Must run on Apache server
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | Must register yum results as patchingresult and dnf results as patchingresultdnf. Set var sendemailreport to false if not also sending the report via e-mail
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html report on any number of RHEL hosts using any number of RHEL servers about their patching results(yum and dnf)
25 |
26 |
27 | ```
28 | ---
29 | - name: Patch RHEL Servers
30 | hosts: all
31 |
32 | tasks:
33 |
34 | - name: upgrade all packages (yum)
35 | ansible.builtin.yum:
36 | name: '*'
37 | state: latest
38 | when: ansible_pkg_mgr == "yum"
39 | register: patchingresult
40 |
41 | - name: upgrade all packages (dnf)
42 | ansible.builtin.dnf:
43 | name: '*'
44 | state: latest
45 | when: ansible_pkg_mgr == "dnf"
46 | register: patchingresultdnf
47 |
48 | - name: Build the report
49 | ansible.builtin.include_role:
50 | name: shadowman.reports.build_report_linux_patch
51 | apply:
52 | delegate_to: report.shadowman.dev
53 | run_once: true
54 | ```
55 |
--------------------------------------------------------------------------------
/roles/build_report_patch/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: Ensure Apache is installed
2 | ansible.builtin.yum:
3 | name: httpd
4 | state: present
5 |
6 | - name: Ensure Apache is started
7 | ansible.builtin.service:
8 | name: httpd
9 | state: started
10 |
11 | - name: Create HTML report
12 | ansible.builtin.template:
13 | src: report.j2
14 | dest: "{{ file_path }}/patch.html"
15 | owner: root
16 | group: root
17 | mode: '0644'
18 | check_mode: false
19 |
20 | - name: Copy CSS over
21 | ansible.builtin.copy:
22 | src: "css"
23 | dest: "{{ file_path }}"
24 | directory_mode: true
25 | owner: root
26 | group: root
27 | mode: '0644'
28 | check_mode: false
29 |
30 | - name: Copy logo over
31 | ansible.builtin.copy:
32 | src: "webpage_logo.png"
33 | dest: "{{ file_path }}"
34 | directory_mode: true
35 | owner: root
36 | group: root
37 | mode: '0644'
38 | check_mode: false
39 |
40 | - name: Display link to Patch report
41 | ansible.builtin.debug:
42 | msg: "Please go to http://{{ ansible_host }}/patch.html"
43 |
44 | - name: Send Report via E-mail
45 | community.general.mail:
46 | host: "{{ EMAIL_HOST }}"
47 | username: "{{ EMAIL_USERNAME }}"
48 | password: "{{ EMAIL_PASSWORD }}"
49 | port: "{{ EMAIL_PORT }}"
50 | subject: "Patching Report"
51 | body: "{{ lookup('template', 'report.j2') }}"
52 | from: "{{ email_from }}"
53 | to: "{{ email_to }}"
54 | subtype: html
55 | delegate_to: localhost
56 | become: false
57 | check_mode: false
58 | when: sendemailreport
59 |
--------------------------------------------------------------------------------
/roles/build_report_network/templates/lacp.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
LACP
5 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['lacp'] is defined and hostvars[network_switch]['ansible_network_resources']['lacp'].keys()|length > 0 %}
7 |
8 |
9 |
10 |
System Priority
11 |
12 |
13 |
14 |
15 | {% if hostvars[network_switch]['ansible_network_resources']['lacp']['system'] is defined %}
16 |
21 | {% elif hostvars[network_switch]['ansible_network_resources']['lacp'] is defined and hostvars[network_switch]['ansible_network_resources']['lacp']|length == 0 %}
22 | LACP is not configured on this device
23 | {% else %}
24 | No LACP information available
25 | {% endif %}
26 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['bgp_address_family']['address_family'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_address_family']['address_family']|length > 0 %}
7 |
8 | {% for address_family in hostvars[network_switch]['ansible_network_resources']['bgp_address_family']['address_family'] %}
9 |
Address Family {{ address_family['afi'] }}
10 |
11 |
12 |
13 |
Network
14 |
Mask
15 |
16 |
17 |
18 |
19 | {% if address_family['networks'] is defined %}
20 | {% for bgp_network in address_family['networks'] %}
21 |
29 | {% endfor %}
30 |
31 | {% elif hostvars[network_switch]['ansible_network_resources']['bgp_address_family']['address_family'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_address_family']['address_family']|length == 0 %}
32 | no BGP address-family is not configured on this device
33 | {% else %}
34 | No BGP information available
35 | {% endif %}
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/roles/build_report_windows_patch/tasks/main.yml:
--------------------------------------------------------------------------------
1 | - name: Ensure Apache is installed
2 | ansible.builtin.yum:
3 | name: httpd
4 | state: present
5 |
6 | - name: Ensure Apache is started
7 | ansible.builtin.service:
8 | name: httpd
9 | state: started
10 |
11 | - name: Create HTML report
12 | ansible.builtin.template:
13 | src: report.j2
14 | dest: "{{ file_path }}/windowspatch.html"
15 | owner: root
16 | group: root
17 | mode: '0644'
18 | check_mode: false
19 |
20 | - name: Copy CSS over
21 | ansible.builtin.copy:
22 | src: "css"
23 | dest: "{{ file_path }}"
24 | directory_mode: true
25 | owner: root
26 | group: root
27 | mode: '0644'
28 | check_mode: false
29 |
30 | - name: Copy logo over
31 | ansible.builtin.copy:
32 | src: "webpage_logo.png"
33 | dest: "{{ file_path }}"
34 | directory_mode: true
35 | owner: root
36 | group: root
37 | mode: '0644'
38 | check_mode: false
39 |
40 | - name: Display link to Patch report
41 | ansible.builtin.debug:
42 | msg: "Please go to http://{{ ansible_host }}/windowspatch.html"
43 |
44 | - name: Send Report via E-mail
45 | community.general.mail:
46 | host: "{{ EMAIL_HOST }}"
47 | username: "{{ EMAIL_USERNAME }}"
48 | password: "{{ EMAIL_PASSWORD }}"
49 | port: "{{ EMAIL_PORT }}"
50 | subject: "Windows Patching Report"
51 | body: "{{ lookup('template', 'report.j2') }}"
52 | from: "{{ email_from }}"
53 | to: "{{ email_to }}"
54 | subtype: html
55 | delegate_to: localhost
56 | become: false
57 | check_mode: false
58 | when: sendemailreport
59 |
--------------------------------------------------------------------------------
/galaxy.yml:
--------------------------------------------------------------------------------
1 | ### REQUIRED
2 |
3 | # The namespace of the collection. This can be a company/brand/organization or product namespace under which all
4 | # content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with
5 | # underscores or numbers and cannot contain consecutive underscores
6 | namespace: shadowman
7 |
8 | # The name of the collection. Has the same character restrictions as 'namespace'
9 | name: reports
10 |
11 | dependencies:
12 | community.general: '>=1.0.0'
13 |
14 | # The version of the collection. Must be compatible with semantic versioning
15 | version: 1.9.1
16 |
17 | # The path to the Markdown (.md) readme file. This path is relative to the root of the collection
18 | readme: README.md
19 |
20 | license_file: LICENSE
21 |
22 | # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url)
23 | # @nicks:irc/im.site#channel'
24 | authors:
25 | - Alexander Dworjan
26 |
27 | repository: https://github.com/shadowman-lab/shadowman.reports
28 |
29 | ### OPTIONAL but strongly recommended
30 |
31 | # A short summary description of the collection
32 | description: Collection to create Linux and Windows server reports, Active Directory, Azure, GCP, AWS reports, patching report, tagging reports, and Networking reports including modules to pull server services and packages
33 |
34 | # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character
35 | # requirements as 'namespace' and 'name'
36 | tags: [reports, linux, windows, networking, cloud]
37 |
--------------------------------------------------------------------------------
/roles/build_report_ad_users/README.md:
--------------------------------------------------------------------------------
1 | build_report_ad_users
2 | ========
3 |
4 | Gathers users from an Active Directory Domain Controller and then on a Linux host installs Apache and creates a report based on current Active Directory Users
5 |
6 |
7 | Requirements
8 | ------------
9 |
10 | Must run on an Active Directory Domain Controller and then the report must be deployed onto an Apache server
11 |
12 | Role Variables / Configuration
13 | --------------
14 |
15 | N/A
16 |
17 | Dependencies
18 | ------------
19 |
20 | N/A
21 |
22 | Example Playbook
23 | ----------------
24 |
25 | The role can be used to create an html report on a Linux host by getting users from an Active Directory Domain Controller.
26 |
27 |
28 | ```
29 | ---
30 | - name: Build AD User Info Report
31 | hosts: all
32 |
33 | tasks:
34 |
35 | - name: Get AD user accounts with groups and lock status
36 | ansible.windows.win_shell: |
37 | Import-Module ActiveDirectory
38 | Get-ADUser -Filter * -Property GivenName, Surname, SamAccountName, MemberOf, LockedOut |
39 | Select-Object GivenName, Surname, SamAccountName, @{Name="Groups";Expression={(Get-ADUser -Identity $_.SamAccountName -Property MemberOf |
40 | Select-Object -ExpandProperty MemberOf | Get-ADGroup | Select-Object -ExpandProperty Name) -join ", "}}, LockedOut |
41 | ConvertTo-Json
42 | register: ad_users
43 |
44 | - name: Build the report
45 | ansible.builtin.include_role:
46 | name: shadowman.reports.build_report_ad_users
47 | apply:
48 | delegate_to: report.shadowman.dev
49 | run_once: true
50 | ```
51 |
--------------------------------------------------------------------------------
/roles/build_report_patch/README.md:
--------------------------------------------------------------------------------
1 | build_report_patch
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from Linux patching and Windows update job
5 |
6 | Requirements
7 | ------------
8 |
9 | Must run on Apache server on RHEL
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | Must register yum results as patchingresult and dnf results as patchingresultdnf. Set Windows patching results to patchresult variable. Set var sendemailreport to false if not also sending the report via e-mail
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html patching report on a Linux host using any number of Windows & RHEL servers
25 |
26 |
27 | ```
28 | ---
29 | - name: Windows patching playbook
30 | hosts: all
31 |
32 | tasks:
33 |
34 | - name: Install Windows Updates
35 | ansible.windows.win_updates:
36 | category_names: '*'
37 | reboot: yes
38 | register: patchresult
39 |
40 | - name: upgrade all packages (yum)
41 | ansible.builtin.yum:
42 | name: '*'
43 | state: latest
44 | when: ansible_pkg_mgr == "yum"
45 | register: patchingresult
46 |
47 | - name: upgrade all packages (dnf)
48 | ansible.builtin.dnf:
49 | name: '*'
50 | state: latest
51 | when: ansible_pkg_mgr == "dnf"
52 | register: patchingresultdnf
53 |
54 | - name: Build the report
55 | ansible.builtin.include_role:
56 | name: shadowman.reports.build_report_patch
57 | apply:
58 | delegate_to: report.shadowman.dev
59 | run_once: true
60 |
61 | ```
62 |
--------------------------------------------------------------------------------
/roles/build_report_linux/README.md:
--------------------------------------------------------------------------------
1 | build_report_linux
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from Linux services and packages modules. Utilize var "detailedreport=false" if you do not need packages or services information.
5 |
6 | Requirements
7 | ------------
8 |
9 | Must run on Apache server
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | N/A
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html report on any number of Linux hosts using any number of Linux servers about their services and packages installed. Added in a boolean var usesingletemplate if running into issues with jinja not adding in the package/services facts.
25 |
26 |
27 | ```
28 | ---
29 | - name: Create Linux Report
30 | hosts: all
31 | tasks:
32 |
33 | - name: Scan packages (Unix/Linux)
34 | ansible.builtin.package_facts:
35 | register: result
36 | when: ansible_os_family != "Windows"
37 |
38 | - name: Organize results for loopings
39 | ansible.builtin.set_fact:
40 | packagefacts: "{{ result.ansible_facts.packages | dict2items }}"
41 | cacheable: true
42 | when: ansible_os_family != "Windows"
43 |
44 | - name: Scan services (Unix/Linux)
45 | ansible.builtin.service_facts:
46 | when: ansible_os_family != "Windows"
47 |
48 | - name: Build the report
49 | ansible.builtin.include_role:
50 | name: shadowman.reports.build_report_linux
51 | apply:
52 | delegate_to: report.shadowman.dev
53 | run_once: true
54 | ```
55 |
--------------------------------------------------------------------------------
/roles/build_report_network/templates/vlans.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
VLANs
5 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['vlans'] is defined and hostvars[network_switch]['ansible_network_resources']['vlans']|length > 0 %}
7 |
8 |
9 |
10 |
vlan_id
11 |
Name
12 |
state
13 |
14 |
15 |
16 | {% for vlan in hostvars[network_switch]['ansible_network_resources']['vlans'] %}
17 |
18 |
{{vlan['vlan_id']| default("none")}}
19 |
{{vlan['name']|default("none")}}
20 |
{{vlan['state']|default("default")}}
21 |
22 | {% endfor %}
23 |
24 |
25 | {% elif hostvars[network_switch]['ansible_network_resources']['vlans'] is defined and hostvars[network_switch]['ansible_network_resources']['vlans']|length == 0 %}
26 | VLANs are not configured on this device
27 | {% else %}
28 | No VLAN information available
29 | {% endif %}
30 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['lldp_interfaces']|length > 0 %}
7 |
8 |
9 |
10 |
vlan_id
11 |
Name
12 |
state
13 |
14 |
15 |
16 | {% for interface in hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] %}
17 |
25 | {% elif hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'].keys()|length == 0 %}
26 | LLDP is not configured on this device
27 | {% else %}
28 | No LLDP information available
29 | {% endif %}
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/roles/build_report_google/README.md:
--------------------------------------------------------------------------------
1 | build_report_google
2 | ========
3 |
4 | Installs Apache and creates a report based on facts from Google.
5 |
6 | Requirements
7 | ------------
8 |
9 | Must deploy to Apache server
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | N/A
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html report on Google statistics onto an apache server.
25 |
26 |
27 | ```
28 | ---
29 | - name: Create Google Detailed Report
30 | hosts: localhost
31 | tasks:
32 |
33 | - name: Get list of all Zones
34 | ansible.builtin.shell: |
35 | gcloud compute zones list --uri \
36 | --account=${GCE_EMAIL} \
37 | --project=${GCP_PROJECT} \
38 | --credential-file-override=${GCE_CREDENTIALS_FILE_PATH} \
39 | | sed -e 's,.*/,,'
40 | register: all_zones
41 | changed_when: false
42 | environment:
43 | GCE_EMAIL: "{{ lookup('env', 'GCE_EMAIL') }}"
44 | GCP_PROJECT: "{{ lookup('env', 'GCP_PROJECT') }}"
45 | GCE_CREDENTIALS_FILE_PATH: "{{ lookup('env', 'GCE_CREDENTIALS_FILE_PATH') }}"
46 |
47 | - name: Get all virtual networks
48 | google.cloud.gcp_compute_network_info:
49 | auth_kind: serviceaccount
50 | register: gcp_networks
51 |
52 | - name: Retrieve VMs from your environment
53 | google.cloud.gcp_compute_instance_info:
54 | zone: "{{ item }}"
55 | project: "{{ gcp_project }}"
56 | auth_kind: serviceaccount
57 | loop: "{{ all_zones.stdout_lines }}"
58 | register: gcp_vms
59 |
60 | - name: Build the report
61 | ansible.builtin.include_role:
62 | name: shadowman.reports.build_report_google
63 | apply:
64 | delegate_to: report.shadowman.dev
65 | run_once: true
66 | ```
67 |
--------------------------------------------------------------------------------
/roles/build_report_certs/README.md:
--------------------------------------------------------------------------------
1 | build_report_certs
2 | ========
3 |
4 | Installs Apache and creates a report based on certificates on a specified port
5 |
6 | Requirements
7 | ------------
8 |
9 | Must run on Apache server
10 |
11 | Role Variables / Configuration
12 | --------------
13 |
14 | Must register facts for each host expire_days, issuer, expiration, expired, include_no_cert. Set var sendemailreport to false if not also sending the report via e-mail
15 |
16 | Dependencies
17 | ------------
18 |
19 | N/A
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | The role can be used to create an html report on any number of RHEL hosts using any number of servers about their certificate results
25 |
26 |
27 | ```
28 | ---
29 | - name: Check Certificates on port
30 | hosts: all
31 |
32 | tasks:
33 |
34 | - name: Block for cert Check
35 | block:
36 |
37 | - name: Get the cert from a port
38 | community.crypto.get_certificate:
39 | host: "{{ inventory_hostname }}"
40 | port: "{{ certificate_port }}"
41 | delegate_to: localhost
42 | register: cert
43 |
44 | - name: Set facts for report
45 | ansible.builtin.set_fact:
46 | expire_days: "{{ ((cert.not_after | to_datetime('%Y%m%d%H%M%SZ')) - (ansible_date_time.iso8601 | to_datetime('%Y-%m-%dT%H:%M:%SZ'))).days }}"
47 | issuer: "{{ cert.issuer }}"
48 | expiration: "{{ cert.not_after | to_datetime('%Y%m%d%H%M%SZ') }}"
49 | expired: "{{ cert.expired }}"
50 |
51 | rescue:
52 |
53 | - name: Display error
54 | ansible.builtin.debug:
55 | msg: "{{ cert.msg }}"
56 |
57 | - name: Build the report
58 | ansible.builtin.include_role:
59 | name: shadowman.reports.build_report_certs
60 | apply:
61 | delegate_to: report.shadowman.dev
62 | run_once: true
63 | ```
64 |
--------------------------------------------------------------------------------
/roles/build_report_network/templates/static.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Static Routes
5 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['static_routes'] is defined and hostvars[network_switch]['ansible_network_resources']['static_routes']|length > 0 %}
7 |
8 |
9 |
10 |
VRF
11 |
Address-Family
12 |
Route
13 |
Next-Hop
14 |
15 |
16 |
17 | {% for net_route in hostvars[network_switch]['ansible_network_resources']['static_routes'] %}
18 |
19 |
{{ net_route['vrf']|default("N/A") }}
20 | {% for address_family in net_route.address_families|default([]) %}
21 |
{{ address_family['afi']|default("N/A") }}
22 | {% for routes in address_family['routes'] %}
23 |
{{ routes['dest']|default("N/A") }}
24 |
25 |
26 |
Interface
27 |
Address
28 |
Global
29 |
30 | {% for next_hops in routes['next_hops'] %}
31 |
44 | {% elif hostvars[network_switch]['ansible_network_resources']['static_routes'] is defined and hostvars[network_switch]['ansible_network_resources']['static_routes']|length == 0 %}
45 | Static Routes are not configured on this device
46 | {% else %}
47 | No Static Route information available
48 | {% endif %}
49 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['bgp_global'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_global']|length > 0 %}
7 |
22 | {% if hostvars[network_switch]['ansible_network_resources']['bgp_global'][
23 | 'neighbor'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_global'][
24 | 'neighbor']|length > 0 %}
25 |
BGP Neighbors
26 |
27 |
28 |
29 |
Address
30 |
Remote AS
31 |
32 |
33 |
34 |
35 | {% for bgp_neighbor in hostvars[network_switch].ansible_network_resources.bgp_global.neighbor %}
36 |
43 | {% endif %}
44 | {% elif hostvars[network_switch]['ansible_network_resources']['bgp_global'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_global']|length == 0 %}
45 | BGP is not configured on this device
46 | {% else %}
47 | No BGP information available
48 | {% endif %}
49 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['ospfv2'] is defined and hostvars[network_switch]['ansible_network_resources']['ospfv2']|length > 0 %}
7 |
8 |
9 |
10 |
Process ID
11 |
Router ID
12 |
13 |
14 |
15 |
16 |
1
17 | {% if hostvars[network_switch]['ansible_network_resources']['ospfv2']['parameters'] is defined %}
18 |
19 | {% elif hostvars[network_switch]['ansible_network_resources']['ospfv2']['processes'] is defined %}
20 | {% for ospvf2info in hostvars[network_switch]['ansible_network_resources']['ospfv2']['processes'] %}
21 |
{{ ospvf2info['router_id'] | default('N/A') }}
22 | {% endfor %}
23 | {% endif %}
24 |
25 |
26 |
27 | {% elif hostvars[network_switch]['ansible_network_resources']['ospfv2'] is defined and hostvars[network_switch]['ansible_network_resources']['ospfv2']|length == 0 %}
28 | OSPF is not configured on this device
29 | {% else %}
30 | No OSPF information available
31 | {% endif %}
32 |
8 | {% if hostvars[network_switch]['ansible_network_resources']['interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['interfaces']|length > 0 %}
9 |
10 |
11 |
12 |
Interface Name
13 |
Description
14 |
Duplex
15 |
Enabled
16 |
MTU
17 |
Speed
18 |
19 |
20 |
21 | {% for interface in hostvars[network_switch]['ansible_network_resources']['interfaces'] %}
22 |
23 |
{{interface['name']| default("none")}}
24 |
{{interface['description']|default("none")}}
25 |
{{interface['duplex']|default("default")}}
26 |
{{interface['enabled']| default("N/A")}}
27 |
{{interface['mtu']|default("default")}}
28 |
{{interface['speed']|default("default")}}
29 |
30 | {% endfor %}
31 |
32 |
33 | {% elif hostvars[network_switch]['ansible_network_resources']['interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['interfaces']|length == 0 %}
34 | No interfaces configured on this device
35 | {% else %}
36 | No Interface information available
37 | {% endif %}
38 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l2_interfaces']|length > 0 %}
7 |
8 |
9 |
10 |
Name
11 |
Mode
12 |
Access VLAN
13 |
Trunk Native VLAN
14 |
Trunk Allowed VLANs
15 |
16 |
17 |
18 | {% for l2_interface in hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] %}
19 |
29 | {% elif hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l2_interfaces']|length == 0 %}
30 | L2 information is not configured on this device
31 | {% else %}
32 | No L2 information available
33 | {% endif %}
34 |
6 | {% if hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l3_interfaces']|length > 0 %}
7 |
8 |
9 |
10 |
Interface Name
11 |
IPv4
12 |
IPv6
13 |
14 |
15 |
16 | {% for interface in hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] %}
17 |
18 |
{{interface['name'] | default("none")}}
19 |
20 |
21 | {% if interface.ipv4 is defined %}
22 | {% for address in interface.ipv4 %}
23 | {% if address['address'] is defined %}
24 | {{address['address']}}
25 | {% else %}
26 | dhcp
27 | {% endif %}
28 | {% if address['secondary'] is defined %}
29 | secondary
30 | {% endif %}
31 | {% if loop.length > 1 and not loop.last %} {% endif %}
32 | {% endfor %}
33 | {% endif %}
34 |
35 |
36 |
37 |
38 | {% if interface.ipv6 is defined %}
39 | {% for v6address in interface.ipv6 %}
40 | {{v6address['address']}}
41 | {% if loop.length > 1 and not loop.last %} {% endif %}
42 | {% endfor %}
43 | {% endif %}
44 |
45 |
46 |
47 | {% endfor %}
48 |
49 |
50 | {% elif hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l3_interfaces']|length == 0 %}
51 | L3 information is not configured on this device
52 | {% else %}
53 | No L3 information available
54 | {% endif %}
55 |
81 |
82 |
--------------------------------------------------------------------------------
/plugins/modules/win_scan_packages.ps1:
--------------------------------------------------------------------------------
1 | #!powershell
2 | # This file is part of Ansible
3 | #
4 | # Ansible is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # Ansible is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with Ansible. If not, see .
16 |
17 | # WANT_JSON
18 | # POWERSHELL_COMMON
19 |
20 | $uninstall_native_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
21 | $uninstall_wow6432_path = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
22 |
23 | if ([System.IntPtr]::Size -eq 4) {
24 |
25 | # This is a 32-bit Windows system, so we only check for 32-bit programs, which will be
26 | # at the native registry location.
27 |
28 | [PSObject []]$packages = Get-ChildItem -Path $uninstall_native_path |
29 | Get-ItemProperty |
30 | Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
31 | @{Name="version"; Expression={$_."DisplayVersion"}},
32 | @{Name="publisher"; Expression={$_."Publisher"}},
33 | @{Name="arch"; Expression={ "Win32" }} |
34 | Where-Object { $_.name }
35 |
36 | } else {
37 |
38 | # This is a 64-bit Windows system, so we check for 64-bit programs in the native
39 | # registry location, and also for 32-bit programs under Wow6432Node.
40 |
41 | [PSObject []]$packages = Get-ChildItem -Path $uninstall_native_path |
42 | Get-ItemProperty |
43 | Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
44 | @{Name="version"; Expression={$_."DisplayVersion"}},
45 | @{Name="publisher"; Expression={$_."Publisher"}},
46 | @{Name="arch"; Expression={ "Win64" }} |
47 | Where-Object { $_.name }
48 |
49 | $packages += Get-ChildItem -Path $uninstall_wow6432_path |
50 | Get-ItemProperty |
51 | Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
52 | @{Name="version"; Expression={$_."DisplayVersion"}},
53 | @{Name="publisher"; Expression={$_."Publisher"}},
54 | @{Name="arch"; Expression={ "Win32" }} |
55 | Where-Object { $_.name }
56 |
57 | }
58 |
59 | $result = New-Object psobject @{
60 | ansible_facts = New-Object psobject @{
61 | packages = $packages
62 | }
63 | changed = $false
64 | }
65 |
66 | Exit-Json $result;
--------------------------------------------------------------------------------
/roles/build_report_azure/templates/report.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Detailed Cloud Automation Report
5 |
6 |
7 |
8 |
9 |
10 |
19 |
20 |
21 | {% include 'header.j2' %}
22 |
23 |
This region contains {{ region_specific_networks | length }} Virtual Network(s)
15 |
16 |
17 |
18 |
Virtual Network name
19 |
Address Prefixes
20 |
Subnets
21 |
Subnet Details
22 |
Network Interfaces
23 |
Network Interface Details
24 |
Virtual Machines
25 |
26 | {% set region_specific_nics = azure_vars.network_interfaces.networkinterfaces | selectattr('location', 'equalto', location.name) %}
27 | {% set nic_names = region_specific_nics | map(attribute='name') | list %}
28 | {% set filtered_vms = [] %}
29 | {% for vm in azure_vars.azure_vms.vms %}
30 | {% if nic_names | intersect(vm['network_interface_names']) %}
31 | {{- filtered_vms.append(vm) -}}
32 | {% endif %}
33 | {% endfor %}
34 |
35 | {% for virtual_network in region_specific_networks %}
36 | {% set virtual_network_specific_nics = region_specific_nics | selectattr('virtual_network.name', 'equalto', virtual_network.name) %}
37 |
38 |
{{ virtual_network.name | default("unknown") }}
39 |
{% for prefix in virtual_network.address_prefixes %}
{{ prefix }}
{% endfor %}
40 |
{{ virtual_network.subnets | length }}
41 |
{% for subnet in virtual_network.subnets %}
{{ subnet.name }}
{{ subnet.address_prefix }}
{% endfor %}
42 |
{{ virtual_network_specific_nics | length }}
43 |
{% for nic in virtual_network_specific_nics %}
{{ nic.name }}
{{ nic.mac_address }}
{% endfor %}
44 |
{{ filtered_vms | length }}
45 |
46 | {% endfor %}
47 |
48 |
49 |
50 |
51 | {% endfor %}
52 |
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Shadowman Reports Collection
2 |
3 | The Ansible Shadowman Reports collection includes a variety of Ansible content to help automate the creation of Linux, Windows, Cloud, Active Directory, and Networking reports.
4 |
5 |
6 | ## Ansible version compatibility
7 |
8 | This collection has been tested against following Ansible versions: **>=2.9.10**.
9 |
10 | Plugins and modules within a collection may be tested with only specific Ansible versions.
11 | A collection may contain metadata that identifies these versions.
12 | PEP440 is the schema used to describe the versions of Ansible.
13 |
14 |
15 | ## Tested with Ansible
16 |
17 | This collection has been tested against RHEL 7, 8, 9, Windows Server 2016, IOS, EOS, VyOS
18 |
19 |
20 | ## External requirements
21 |
22 |
23 | ## Included content
24 |
25 |
26 |
27 | ### Modules
28 | Name | Description
29 | --- | ---
30 | [shadowman.reports.win_scan_packages](https://github.com/shadowman-lab/shadowman.reports/blob/main/docs/shadowman.reports.win_scan_packages_module.rst)|Scans for all packages on a Windows server
31 | [shadowman.reports.win_scan_services](https://github.com/shadowman-lab/shadowman.reports/blob/main/docs/shadowman.reports.win_scan_services_module.rst)|Scans for all services on a Windows server
32 |
33 |
34 |
35 | ## Installing this collection
36 |
37 | You can install the Shadowman Reports collection with the Ansible Galaxy CLI:
38 |
39 | ansible-galaxy collection install shadowman.reports
40 |
41 | You can also include it in a `requirements.yml` file and install it with `ansible-galaxy collection install -r requirements.yml`, using the format:
42 |
43 | ```yaml
44 | ---
45 | collections:
46 | - name: shadowman.reports
47 | ```
48 | ## Using this collection
49 |
50 | ### Using Shadowman Reports Ansible Collection
51 |
52 | An example for using this collection to scan a Windows host for packages:
53 |
54 |
55 | ```yaml
56 | ---
57 | - name: Scan packages of all Windows hosts
58 | hosts: windows
59 |
60 | tasks:
61 |
62 | - name: "Scan packages (Windows)"
63 | shadowman.reports.win_scan_packages:
64 |
65 | ```
66 |
67 |
68 | ### Code of Conduct
69 | This collection follows the Ansible project's
70 | [Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html).
71 | Please read and familiarize yourself with this document.
72 |
73 | ## Roadmap
74 |
75 |
76 |
77 | ## More information
78 |
79 | - [Ansible Collection overview](https://github.com/ansible-collections/overview)
80 | - [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
81 | - [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
82 | - [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
83 |
84 | ## Licensing
85 |
86 | GNU General Public License v3.0 or later.
87 |
88 | See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text.
89 |
--------------------------------------------------------------------------------
/roles/build_report_windows_patch/templates/report.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Windows Patch Report
5 |
6 |
7 |
8 |
Ansible Windows Patching Report
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Hostname
25 |
Operating System
26 |
Required Updates
27 |
28 |
29 |
30 | {% for windows_host in ansible_play_hosts|sort %}
31 |
36 |
37 | {% if hostvars[windows_host].patchresult.updates is defined and hostvars[windows_host].patchresult.found_update_count|int > 0 %}
38 | {% for update in hostvars[windows_host].patchresult.updates %}
39 | {% set updatenum = hostvars[windows_host].patchresult.updates[update] %}
40 |
{{updatenum.title}}
41 | {% endfor %}
42 | {% else %}
43 |
Compliant
44 | {% endif %}
45 |
46 |
47 |
48 |
49 | {% endfor %}
50 |
51 |
52 |
Created with Ansible on {{hostvars[ansible_play_hosts[0]].ansible_date_time.iso8601}}
28 |
29 |
30 | {% if aws_info.results is defined %}
31 | {% for aws_regions in aws_info.results %}
32 | {% if aws_regions.instances is defined %}
33 | {% for aws_host in aws_regions.instances %}
34 |