---
- name: Service Status Check and Conditional Disable
hosts: all
gather_facts: yes
become: yes
serial: 5
vars:
disable_auditd: false
disable_mlocate: false
disable_ntp_services: false
max_time_drift_seconds: 30
ntp_server_pool: "pool.ntp.org"
backup_configs: true
log_changes: true
tasks:
- name: Set time_reference from controller node
ansible.builtin.set_fact:
time_reference: "{{ ansible_date_time.iso8601 }}"
run_once: true
delegate_to: localhost
- name: Include service status check
ansible.builtin.include_tasks: service_status_check_complete.yml
- name: Include conditional service disable tasks
ansible.builtin.include_tasks: conditional_service_disable.yml
- name: Include time synchronization tasks
ansible.builtin.include_tasks: time_sync_correction.yml
when: node_result.ntp.ntp_synchronized == false or
(time_reference is defined and
((node_result.current_time | to_datetime('%Y-%m-%dT%H:%M:%SZ')) -
(time_reference | to_datetime('%Y-%m-%dT%H:%M:%SZ'))).total_seconds() | abs > max_time_drift_seconds)
- name: Include final verification
ansible.builtin.include_tasks: final_verification.yml
---
---
- name: Check if auditd disable is requested and service is active
ansible.builtin.set_fact:
should_disable_auditd: "{{ disable_auditd and node_result.auditd.service_exists and node_result.auditd.running }}"
- ansible.builtin.block:
- name: Create backup of auditd configuration
ansible.builtin.copy:
src: /etc/audit/auditd.conf
dest: /etc/audit/auditd.conf.backup.{{ ansible_date_time.epoch }}
remote_src: yes
backup: yes
when: backup_configs and node_result.auditd.service_exists
- name: Log auditd disable action
ansible.builtin.lineinfile:
path: /var/log/ansible_service_changes.log
create: yes
line: "{{ ansible_date_time.iso8601 }} - {{ inventory_hostname }} - Disabling auditd service (was {{ node_result.auditd.status }})"
when: log_changes
- name: Stop auditd service
ansible.builtin.systemd:
name: auditd
state: stopped
enabled: no
register: auditd_disable_result
- name: Mask auditd service to prevent accidental restart
ansible.builtin.systemd:
name: auditd
masked: yes
when: auditd_disable_result is succeeded
- name: Verify auditd is stopped
ansible.builtin.systemd:
name: auditd
register: auditd_final_status
- name: Display auditd disable result
ansible.builtin.debug:
msg: |
✅ AUDITD DISABLED SUCCESSFULLY on {{ inventory_hostname }}
- Previous Status: {{ node_result.auditd.status }}
- Current Status: {{ auditd_final_status.status.ActiveState }}
- Service Masked: Yes
{% if backup_configs %}
- Config Backup: /etc/audit/auditd.conf.backup.{{ ansible_date_time.epoch }}
{% endif %}
when: should_disable_auditd
- name: Skip auditd disable - not requested or not running
ansible.builtin.debug:
msg: |
⏭️ SKIPPING AUDITD DISABLE on {{ inventory_hostname }}
- Disable Requested: {{ disable_auditd }}
- Service Exists: {{ node_result.auditd.service_exists }}
- Currently Running: {{ node_result.auditd.running }}
- Current Status: {{ node_result.auditd.status }}
when: not should_disable_auditd
- name: Check if mlocate disable is requested and timer is active
ansible.builtin.set_fact:
should_disable_mlocate: "{{ disable_mlocate and node_result.mlocate.timer_exists and node_result.mlocate.timer_running }}"
- ansible.builtin.block:
- name: Log mlocate disable action
ansible.builtin.lineinfile:
path: /var/log/ansible_service_changes.log
create: yes
line: "{{ ansible_date_time.iso8601 }} - {{ inventory_hostname }} - Disabling mlocate timer (was {{ node_result.mlocate.timer_status }})"
when: log_changes
- name: Stop mlocate updatedb timer
ansible.builtin.systemd:
name: "{{ node_result.mlocate.timer_service }}"
state: stopped
enabled: no
register: mlocate_disable_result
- name: Mask mlocate timer to prevent accidental restart
ansible.builtin.systemd:
name: "{{ node_result.mlocate.timer_service }}"
masked: yes
when: mlocate_disable_result is succeeded
- name: Remove mlocate database if requested
ansible.builtin.file:
path: "{{ node_result.mlocate.db_path }}"
state: absent
when: mlocate_disable_result is succeeded and node_result.mlocate.db_exists
register: mlocate_db_removed
- name: Verify mlocate timer is stopped
ansible.builtin.systemd:
name: "{{ node_result.mlocate.timer_service }}"
register: mlocate_final_status
- name: Display mlocate disable result
ansible.builtin.debug:
msg: |
✅ MLOCATE DISABLED SUCCESSFULLY on {{ inventory_hostname }}
- Timer Service: {{ node_result.mlocate.timer_service }}
- Previous Status: {{ node_result.mlocate.timer_status }}
- Current Status: {{ mlocate_final_status.status.ActiveState }}
- Service Masked: Yes
{% if mlocate_db_removed is defined and mlocate_db_removed.changed %}
- Database Removed: {{ node_result.mlocate.db_path }}
{% endif %}
when: should_disable_mlocate
- name: Skip mlocate disable - not requested or not running
ansible.builtin.debug:
msg: |
⏭️ SKIPPING MLOCATE DISABLE on {{ inventory_hostname }}
- Disable Requested: {{ disable_mlocate }}
- Timer Exists: {{ node_result.mlocate.timer_exists }}
- Timer Running: {{ node_result.mlocate.timer_running }}
- Timer Status: {{ node_result.mlocate.timer_status }}
when: not should_disable_mlocate
- name: Check if NTP disable is requested and service is active
ansible.builtin.set_fact:
should_disable_ntp: "{{ disable_ntp_services and node_result.ntp.active_service != 'none' }}"
- ansible.builtin.block:
- name: Create backup of time service configurations
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
remote_src: yes
backup: yes
loop:
- { src: "/etc/chrony.conf", dest: "/etc/chrony.conf.backup.{{ ansible_date_time.epoch }}" }
- { src: "/etc/ntp.conf", dest: "/etc/ntp.conf.backup.{{ ansible_date_time.epoch }}" }
when: backup_configs
failed_when: false
- name: Log NTP disable action
ansible.builtin.lineinfile:
path: /var/log/ansible_service_changes.log
create: yes
line: "{{ ansible_date_time.iso8601 }} - {{ inventory_hostname }} - Disabling {{ node_result.ntp.active_service }} service"
when: log_changes
- name: Stop active NTP service
ansible.builtin.systemd:
name: "{{ node_result.ntp.active_service }}"
state: stopped
enabled: no
register: ntp_disable_result
- name: Mask NTP service to prevent accidental restart
ansible.builtin.systemd:
name: "{{ node_result.ntp.active_service }}"
masked: yes
when: ntp_disable_result is succeeded
- name: Verify NTP service is stopped
ansible.builtin.systemd:
name: "{{ node_result.ntp.active_service }}"
register: ntp_final_status
- name: Display NTP disable result
ansible.builtin.debug:
msg: |
✅ NTP SERVICE DISABLED SUCCESSFULLY on {{ inventory_hostname }}
- Service: {{ node_result.ntp.active_service }}
- Current Status: {{ ntp_final_status.status.ActiveState }}
- Service Masked: Yes
⚠️ WARNING: Time synchronization is now disabled!
when: should_disable_ntp
- name: Skip NTP disable - not requested or no active service
ansible.builtin.debug:
msg: |
⏭️ SKIPPING NTP DISABLE on {{ inventory_hostname }}
- Disable Requested: {{ disable_ntp_services }}
- Active Service: {{ node_result.ntp.active_service }}
when: not should_disable_ntp
- name: Create disable action summary
ansible.builtin.set_fact:
disable_summary:
hostname: "{{ inventory_hostname }}"
auditd_disabled: "{{ should_disable_auditd | default(false) }}"
mlocate_disabled: "{{ should_disable_mlocate | default(false) }}"
ntp_disabled: "{{ should_disable_ntp | default(false) }}"
timestamp: "{{ ansible_date_time.iso8601 }}"
actions_taken:
- "{{ 'auditd stopped and masked' if should_disable_auditd else 'auditd unchanged' }}"
- "{{ 'mlocate timer stopped and masked' if should_disable_mlocate else 'mlocate unchanged' }}"
- "{{ node_result.ntp.active_service + ' stopped and masked' if should_disable_ntp else 'NTP unchanged' }}"
- name: Display per-node disable summary
ansible.builtin.debug:
msg: |
================================================
🔧 SERVICE DISABLE SUMMARY - {{ inventory_hostname }}
================================================
Timestamp: {{ disable_summary.timestamp }}
📊 Actions Taken:
{% for action in disable_summary.actions_taken %}
- {{ action }}
{% endfor %}
📋 Current Service States:
{% if disable_summary.auditd_disabled %}
✅ auditd: DISABLED AND MASKED
{% else %}
⏭️ auditd: {{ node_result.auditd.status }} (unchanged)
{% endif %}
{% if disable_summary.mlocate_disabled %}
✅ mlocate: DISABLED AND MASKED
{% else %}
⏭️ mlocate: {{ node_result.mlocate.timer_status }} (unchanged)
{% endif %}
{% if disable_summary.ntp_disabled %}
⚠️ {{ node_result.ntp.active_service }}: DISABLED AND MASKED
{% else %}
⏭️ NTP: {{ node_result.ntp.active_service }} (unchanged)
{% endif %}
- name: Save disable action log
ansible.builtin.copy:
content: "{{ disable_summary | to_nice_json }}"
dest: "/tmp/disable_actions_{{ inventory_hostname }}.json"
delegate_to: localhost
---
---
- name: Calculate time drift from reference
ansible.builtin.set_fact:
time_drift_seconds: |
{% if time_reference is defined %}
{% set ref_time = time_reference | to_datetime('%Y-%m-%dT%H:%M:%SZ') %}
{% set node_time = node_result.current_time | to_datetime('%Y-%m-%dT%H:%M:%SZ') %}
{{ (node_time - ref_time).total_seconds() }}
{% else %}
0
{% endif %}
- name: Determine time correction strategy
ansible.builtin.set_fact:
time_correction_needed: "{{ (time_drift_seconds | float | abs) > max_time_drift_seconds }}"
drift_level: |
{% set drift = time_drift_seconds | float | abs %}
{% if drift > 300 %}
CRITICAL
{% elif drift > 60 %}
HIGH
{% elif drift > 30 %}
MODERATE
{% else %}
MINOR
{% endif %}
- name: Display time analysis
ansible.builtin.debug:
msg: |
🕐 TIME DRIFT ANALYSIS - {{ inventory_hostname }}
================================================
Current Time: {{ node_result.current_time }}
Reference Time: {{ time_reference | default('N/A') }}
Time Drift: {{ time_drift_seconds | float | round(2) }}s
Drift Level: {{ drift_level }}
Correction Needed: {{ time_correction_needed }}
NTP Synchronized: {{ node_result.ntp.ntp_synchronized }}
Active NTP Service: {{ node_result.ntp.active_service }}
- name: Fix NTP synchronization issues
ansible.builtin.block:
- name: Install chrony if no time service is available
ansible.builtin.package:
name: chrony
state: present
when: node_result.ntp.active_service == 'none'
register: chrony_installed
- name: Configure chrony with reliable NTP servers
ansible.builtin.template:
src: chrony.conf.j2
dest: /etc/chrony.conf
backup: yes
notify: restart chronyd
when: node_result.ntp.chronyd_exists or chrony_installed is defined
- name: Start and enable chronyd
ansible.builtin.systemd:
name: chronyd
state: started
enabled: yes
when: node_result.ntp.chronyd_exists or chrony_installed is defined
register: chronyd_started
- name: Force immediate time synchronization (gradual) using chronyc
ansible.builtin.command: chronyc bursts
when: time_correction_needed and drift_level in ['MINOR', 'MODERATE'] and (node_result.ntp.chronyd_exists or chrony_installed is defined)
register: gradual_sync_result
failed_when: false
- name: Force immediate time synchronization (step for critical drift)
ansible.builtin.block:
- name: Stop chronyd for manual time step
ansible.builtin.systemd:
name: chronyd
state: stopped
- name: Force time step with chronyd
ansible.builtin.command: chronyd -q 'server {{ ntp_server_pool }} iburst'
register: step_sync_result
- name: Start chronyd after manual sync
ansible.builtin.systemd:
name: chronyd
state: started
when: time_correction_needed and drift_level == 'CRITICAL' and (node_result.ntp.chronyd_exists or chrony_installed is defined)
- name: Wait for synchronization to stabilize using chronyc waitsync
ansible.builtin.command: chronyc waitsync 15
register: waitsync_result
until: waitsync_result.rc == 0
retries: 4
delay: 15
failed_when: false
when: (chronyd_started is changed or gradual_sync_result is defined or step_sync_result is defined) and (node_result.ntp.chronyd_exists or chrony_installed is defined)
- name: Verify time synchronization after correction with timedatectl
ansible.builtin.command: timedatectl status
register: time_verify_result
- name: Get updated chrony tracking status
ansible.builtin.command: chronyc tracking
register: chrony_tracking_updated
failed_when: false
when: node_result.ntp.chronyd_exists or chrony_installed is defined
- name: Display time correction results
ansible.builtin.debug:
msg: |
✅ TIME SYNCHRONIZATION CORRECTION COMPLETED
================================================
Previous Drift: {{ time_drift_seconds | float | round(2) }}s
Correction Method: {{ 'Step' if drift_level == 'CRITICAL' else 'Gradual' }}
Updated Status:
{{ time_verify_result.stdout }}
{% if chrony_tracking_updated.stdout is defined %}
Chrony Tracking:
{{ chrony_tracking_updated.stdout }}
{% endif %}
when: time_correction_needed or not node_result.ntp.ntp_synchronized
- name: Setup time synchronization monitoring
ansible.builtin.block:
- name: Create time sync monitoring script
ansible.builtin.copy:
content: |
#!/bin/bash
# Time synchronization monitoring script
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
LOG_FILE="/var/log/time_sync_monitor.log"
MAX_DRIFT={{ max_time_drift_seconds }}
NTP_POOL="{{ ntp_server_pool }}"
TIMEDATECTL_OUTPUT=$(timedatectl status)
NTP_SYNC=$(echo "$TIMEDATECTL_OUTPUT" | grep "NTP synchronized" | awk '{print $3}')
if [[ "$NTP_SYNC" != "yes" ]]; then
echo "$(date): WARNING - NTP not synchronized, attempting restart" >> $LOG_FILE
systemctl restart chronyd || echo "$(date): ERROR - Failed to restart chronyd" >> $LOG_FILE
fi
if command -v chronyc &> /dev/null; then
CHRONY_TRACKING=$(chronyc tracking)
OFFSET=$(echo "$CHRONY_TRACKING" | grep "Last offset" | awk '{print $4}')
if [[ -n "$OFFSET" && "$OFFSET" =~ ^[+-]?[0-9]*\.?[0-9]+$ ]]; then
if (( $(echo "$OFFSET > $MAX_DRIFT" | bc -l) )); then
echo "$(date): WARNING - Time offset too large: ${OFFSET}s, forcing burst sync" >> $LOG_FILE
chronyc bursts || echo "$(date): ERROR - Failed to perform chronyc bursts" >> $LOG_FILE
fi
fi
fi
dest: /usr/local/bin/time_sync_monitor.sh
mode: '0755'
- name: Create systemd timer for time sync monitoring
ansible.builtin.copy:
content: |
[Unit]
Description=Time Sync Monitor Timer
[Timer]
OnCalendar=*:0/15
Persistent=true
[Install]
WantedBy=timers.target
dest: /etc/systemd/system/time-sync-monitor.timer
- name: Create systemd service for time sync monitoring
ansible.builtin.copy:
content: |
[Unit]
Description=Time Sync Monitor Service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/time_sync_monitor.sh
User=root
dest: /etc/systemd/system/time-sync-monitor.service
- name: Enable and start time sync monitoring timer
ansible.builtin.systemd:
name: time-sync-monitor.timer
enabled: yes
state: started
daemon_reload: yes
when: time_correction_needed or not node_result.ntp.ntp_synchronized
- name: Generate time sync recommendations
ansible.builtin.set_fact:
time_recommendations: |
{% set drift = time_drift_seconds | float | abs %}
{% if drift > 300 %}
CRITICAL TIME DRIFT ({{ drift | round(2) }}s):
1. 즉시 수동 시간 동기화 수행
2. NTP 서버 연결 상태 확인
3. 방화벽 설정 점검 (UDP 123 포트)
4. 네트워크 연결성 확인
5. 시스템 클럭 하드웨어 점검 권장
{% elif drift > 60 %}
HIGH TIME DRIFT ({{ drift | round(2) }}s):
1. NTP 서비스 재시작 수행
2. 더 가까운 NTP 서버로 변경 고려
3. 정기적인 시간 동기화 모니터링 설정
{% elif drift > 30 %}
MODERATE TIME DRIFT ({{ drift | round(2) }}s):
1. NTP 동기화 강제 수행
2. 시간 동기화 빈도 증가
{% else %}
MINOR TIME DRIFT ({{ drift | round(2) }}s):
1. 정상 범위 내 차이
2. 정기 모니터링 유지
{% endif %}
- name: Display time sync recommendations
ansible.builtin.debug:
msg: |
================================================
🔧 TIME SYNCHRONIZATION RECOMMENDATIONS
================================================
Host: {{ inventory_hostname }}
{{ time_recommendations }}
추가 점검 사항:
- 네트워크 지연: ping {{ ntp_server_pool }}
- NTP 포트 확인: netstat -ulnp | grep :123
- 시스템 로그: journalctl -u chronyd -f
- 하드웨어 클럭: hwclock --show
when: time_correction_needed
---
---
- name: Re-check auditd status after changes
ansible.builtin.systemd:
name: auditd
register: auditd_final_check
failed_when: false
when: node_result.auditd.service_exists
- name: Re-check mlocate timer status after changes
ansible.builtin.systemd:
name: "{{ node_result.mlocate.timer_service }}"
register: mlocate_final_check
failed_when: false
when: node_result.mlocate.timer_exists
- name: Re-check NTP status after changes
ansible.builtin.command: timedatectl status
register: ntp_final_check
failed_when: false
- name: Get updated chrony tracking status
ansible.builtin.command: chronyc tracking
register: chrony_final_check
failed_when: false
when: node_result.ntp.chronyd_exists or (node_result.ntp.active_service == 'none' and 'chrony_installed' in hostvars[inventory_hostname] and hostvars[inventory_hostname].chrony_installed.changed)
- name: Get current time after changes
ansible.builtin.setup:
filter: ansible_date_time
register: final_time_info
- name: Analyze final service states
ansible.builtin.set_fact:
final_verification:
hostname: "{{ inventory_hostname }}"
timestamp: "{{ final_time_info.ansible_facts.ansible_date_time.iso8601 }}"
verification_status:
auditd:
requested_disable: "{{ disable_auditd | default(false) }}"
current_status: "{{ auditd_final_check.status.ActiveState if auditd_final_check.status is defined else 'N/A' }}"
is_masked: "{{ auditd_final_check.status.UnitFileState == 'masked' if auditd_final_check.status is defined else false }}"
disable_successful: "{{ (disable_auditd | default(false)) and (auditd_final_check.status.ActiveState == 'inactive' if auditd_final_check.status is defined else false) }}"
mlocate:
requested_disable: "{{ disable_mlocate | default(false) }}"
current_status: "{{ mlocate_final_check.status.ActiveState if mlocate_final_check.status is defined else 'N/A' }}"
is_masked: "{{ mlocate_final_check.status.UnitFileState == 'masked' if mlocate_final_check.status is defined else false }}"
disable_successful: "{{ (disable_mlocate | default(false)) and (mlocate_final_check.status.ActiveState == 'inactive' if mlocate_final_check.status is defined else false) }}"
ntp:
sync_status: "{{ 'synchronized' if 'NTP synchronized: yes' in ntp_final_check.stdout else 'not synchronized' }}"
current_time: "{{ final_time_info.ansible_facts.ansible_date_time.iso8601 }}"
chrony_tracking: "{{ chrony_final_check.stdout if chrony_final_check.stdout is defined else 'N/A' }}"
- name: Display final verification report
ansible.builtin.debug:
msg: |
================================================
📋 FINAL VERIFICATION REPORT
================================================
Host: {{ final_verification.hostname }}
Verification Time: {{ final_verification.timestamp }}
🔍 AUDITD VERIFICATION:
{% if final_verification.verification_status.auditd.requested_disable %}
- Disable Requested: ✅ YES
- Current Status: {{ final_verification.verification_status.auditd.current_status }}
- Service Masked: {{ '✅ YES' if final_verification.verification_status.auditd.is_masked else '❌ NO' }}
- Disable Success: {{ '✅ SUCCESS' if final_verification.verification_status.auditd.disable_successful else '❌ FAILED' }}
{% else %}
- Disable Requested: ⏭️ NO (Service Unchanged)
- Current Status: {{ final_verification.verification_status.auditd.current_status }}
{% endif %}
📍 MLOCATE VERIFICATION:
{% if final_verification.verification_status.mlocate.requested_disable %}
- Disable Requested: ✅ YES
- Current Status: {{ final_verification.verification_status.mlocate.current_status }}
- Service Masked: {{ '✅ YES' if final_verification.verification_status.mlocate.is_masked else '❌ NO' }}
- Disable Success: {{ '✅ SUCCESS' if final_verification.verification_status.mlocate.disable_successful else '❌ FAILED' }}
{% else %}
- Disable Requested: ⏭️ NO (Service Unchanged)
- Current Status: {{ final_verification.verification_status.mlocate.current_status }}
{% endif %}
🕐 NTP/TIME VERIFICATION:
- Current Time: {{ final_verification.verification_status.ntp.current_time }}
- Sync Status: {{ '✅ SYNCHRONIZED' if final_verification.verification_status.ntp.sync_status == 'synchronized' else '⚠️ NOT SYNCHRONIZED' }}
{% if final_verification.verification_status.ntp.chrony_tracking != 'N/A' %}
- Chrony Details:
{{ final_verification.verification_status.ntp.chrony_tracking | indent(4) }}
{% endif %}
- name: Save final verification report
ansible.builtin.copy:
content: "{{ final_verification | to_nice_json }}"
dest: "/tmp/final_verification_{{ inventory_hostname }}.json"
delegate_to: localhost
- name: Collect all verification reports
ansible.builtin.find:
paths: /tmp
patterns: "final_verification_*.json"
register: verification_files
delegate_to: localhost
run_once: true
- name: Read all verification files
ansible.builtin.slurp:
src: "{{ item.path }}"
register: verification_contents
loop: "{{ verification_files.files }}"
delegate_to: localhost
run_once: true
- name: Combine verification results
ansible.builtin.set_fact:
all_verifications: "{{ all_verifications | default([]) + [item.content | b64decode | from_json] }}"
loop: "{{ verification_contents.results }}"
delegate_to: localhost
run_once: true
- name: Calculate final statistics
ansible.builtin.set_fact:
final_stats:
total_nodes: "{{ all_verifications | length }}"
auditd:
disable_requested: "{{ all_verifications | selectattr('verification_status.auditd.requested_disable', 'equalto', true) | list | length }}"
disable_successful: "{{ all_verifications | selectattr('verification_status.auditd.disable_successful', 'equalto', true) | list | length }}"
disable_failed: "{{ all_verifications | selectattr('verification_status.auditd.requested_disable', 'equalto', true) | selectattr('verification_status.auditd.disable_successful', 'equalto', false) | list | length }}"
mlocate:
disable_requested: "{{ all_verifications | selectattr('verification_status.mlocate.requested_disable', 'equalto', true) | list | length }}"
disable_successful: "{{ all_verifications | selectattr('verification_status.mlocate.disable_successful', 'equalto', true) | list | length }}"
disable_failed: "{{ all_verifications | selectattr('verification_status.mlocate.requested_disable', 'equalto', true) | selectattr('verification_status.mlocate.disable_successful', 'equalto', false) | list | length }}"
ntp:
synchronized_nodes: "{{ all_verifications | selectattr('verification_status.ntp.sync_status', 'equalto', 'synchronized') | list | length }}"
unsynchronized_nodes: "{{ all_verifications | selectattr('verification_status.ntp.sync_status', 'equalto', 'not synchronized') | list | length }}"
delegate_to: localhost
run_once: true
- name: Get failed operations details
ansible.builtin.set_fact:
failed_operations:
auditd_failed_nodes: "{{ all_verifications | selectattr('verification_status.auditd.requested_disable', 'equalto', true) | selectattr('verification_status.auditd.disable_successful', 'equalto', false) | map(attribute='hostname') | list }}"
mlocate_failed_nodes: "{{ all_verifications | selectattr('verification_status.mlocate.requested_disable', 'equalto', true) | selectattr('verification_status.mlocate.disable_successful', 'equalto', false) | map(attribute='hostname') | list }}"
time_unsync_nodes: "{{ all_verifications | selectattr('verification_status.ntp.sync_status', 'equalto', 'not synchronized') | map(attribute='hostname') | list }}"
delegate_to: localhost
run_once: true
- name: Display cluster-wide final summary
ansible.builtin.debug:
msg: |
================================================
🎯 CLUSTER-WIDE FINAL SUMMARY
================================================
Total Nodes Processed: {{ final_stats.total_nodes }}
🔍 AUDITD DISABLE OPERATIONS:
├─ Disable Requested: {{ final_stats.auditd.disable_requested }} nodes
├─ Successfully Disabled: {{ final_stats.auditd.disable_successful }} nodes
├─ Failed Disables: {{ final_stats.auditd.disable_failed }} nodes
{% if failed_operations.auditd_failed_nodes | length > 0 %}
└─ Failed Nodes: {{ failed_operations.auditd_failed_nodes | join(', ') }}
{% else %}
└─ All Operations Successful ✅
{% endif %}
📍 MLOCATE DISABLE OPERATIONS:
├─ Disable Requested: {{ final_stats.mlocate.disable_requested }} nodes
├─ Successfully Disabled: {{ final_stats.mlocate.disable_successful }} nodes
├─ Failed Disables: {{ final_stats.mlocate.disable_failed }} nodes
{% if failed_operations.mlocate_failed_nodes | length > 0 %}
└─ Failed Nodes: {{ failed_operations.mlocate_failed_nodes | join(', ') }}
{% else %}
└─ All Operations Successful ✅
{% endif %}
🕐 TIME SYNCHRONIZATION STATUS:
├─ Synchronized Nodes: {{ final_stats.ntp.synchronized_nodes }} nodes
├─ Unsynchronized Nodes: {{ final_stats.ntp.unsynchronized_nodes }} nodes
{% if failed_operations.time_unsync_nodes | length > 0 %}
└─ Needs Attention: {{ failed_operations.time_unsync_nodes | join(', ') }}
{% else %}
└─ All Nodes Synchronized ✅
{% endif %}
delegate_to: localhost
run_once: true
- name: Generate comprehensive final report CSV
ansible.builtin.copy:
content: |
Hostname,Timestamp,auditd_Disable_Requested,auditd_Current_Status,auditd_Masked,auditd_Disable_Success,mlocate_Disable_Requested,mlocate_Current_Status,mlocate_Masked,mlocate_Disable_Success,NTP_Sync_Status,Current_Time,Overall_Status
{% for verification in all_verifications -%}
{% set auditd_ok = not verification.verification_status.auditd.requested_disable or verification.verification_status.auditd.disable_successful %}
{% set mlocate_ok = not verification.verification_status.mlocate.requested_disable or verification.verification_status.mlocate.disable_successful %}
{% set ntp_ok = verification.verification_status.ntp.sync_status == 'synchronized' %}
{{ verification.hostname }},{{ verification.timestamp }},{{ verification.verification_status.auditd.requested_disable }},{{ verification.verification_status.auditd.current_status }},{{ verification.verification_status.auditd.is_masked }},{{ verification.verification_status.auditd.disable_successful }},{{ verification.verification_status.mlocate.requested_disable }},{{ verification.verification_status.mlocate.current_status }},{{ verification.verification_status.mlocate.is_masked }},{{ verification.verification_status.mlocate.disable_successful }},{{ verification.verification_status.ntp.sync_status }},{{ verification.verification_status.ntp.current_time }},{{ 'SUCCESS' if auditd_ok and mlocate_ok and ntp_ok else 'PARTIAL' if (auditd_ok and mlocate_ok) or ntp_ok else 'FAILED' }}
{% endfor %}
dest: "./final_verification_report.csv"
delegate_to: localhost
run_once: true
- name: Clean up temporary verification files
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ verification_files.files }}"
delegate_to: localhost
run_once: true
- name: Display post-operation recommendations
ansible.builtin.debug:
msg: |
================================================
🔧 POST-OPERATION RECOMMENDATIONS
================================================
{% if final_stats.auditd.disable_failed > 0 %}
❌ AUDITD DISABLE FAILURES:
- Manual intervention required on: {{ failed_operations.auditd_failed_nodes | join(', ') }}
- Check service dependencies: systemctl list-dependencies auditd
- Force stop if needed: systemctl stop auditd --force
- Check for active audit processes: ps aux | grep audit
{% endif %}
{% if final_stats.mlocate.disable_failed > 0 %}
❌ MLOCATE DISABLE FAILURES:
- Manual intervention required on: {{ failed_operations.mlocate_failed_nodes | join(', ') }}
- Check running updatedb processes: ps aux | grep updatedb
- Kill if necessary: pkill -f updatedb
- Retry disable: systemctl stop mlocate-updatedb.timer
{% endif %}
{% if final_stats.ntp.unsynchronized_nodes > 0 %}
⚠️ TIME SYNCHRONIZATION ISSUES:
- Nodes needing attention: {{ failed_operations.time_unsync_nodes | join(', ') }}
Manual troubleshooting steps:
1. Check NTP service status:
systemctl status chronyd
2. Verify NTP server connectivity:
chronyc sources -v
ping {{ ntp_server_pool }}
3. Check firewall settings:
firewall-cmd --list-ports | grep 123
iptables -L | grep 123
4. Force time synchronization:
chrony -q 'server {{ ntp_server_pool }} iburst'
5. Check system logs:
journalctl -u chronyd --since="1 hour ago"
{% endif %}
📊 MONITORING SETUP:
{% if final_stats.auditd.disable_successful > 0 %}
- auditd monitoring disabled on {{ final_stats.auditd.disable_successful }} nodes
- Alternative security monitoring recommended
{% endif %}
{% if final_stats.mlocate.disable_successful > 0 %}
- locate database updates disabled on {{ final_stats.mlocate.disable_successful }} nodes
- Manual updatedb runs required for file indexing
{% endif %}
📄 Generated Reports:
- ./final_verification_report.csv (Complete operation results)
- /var/log/ansible_service_changes.log (Change audit trail on each node)
- Time sync monitoring active on nodes with corrections
🔄 ROLLBACK PROCEDURES:
If services need to be re-enabled:
For auditd:
sudo systemctl unmask auditd
sudo systemctl enable auditd
sudo systemctl start auditd
For mlocate:
sudo systemctl unmask mlocate-updatedb.timer
sudo systemctl enable mlocate-updatedb.timer
sudo systemctl start mlocate-updatedb.timer
sudo updatedb # Rebuild database
⚡ IMMEDIATE ACTIONS REQUIRED:
{% if final_stats.auditd.disable_failed > 0 or final_stats.mlocate.disable_failed > 0 %}
- Review failed operations and resolve manually
{% endif %}
{% if final_stats.ntp.unsynchronized_nodes > 0 %}
- Fix time synchronization on unsynchronized nodes
{% endif %}
{% if final_stats.auditd.disable_successful > 0 %}
- Implement alternative security monitoring if required
{% endif %}
delegate_to: localhost
run_once: true