test0823a

Young-Kyoo Kim·2025년 8월 22일
# service_disable_playbook.yml
# 메인 플레이북: 서비스 상태 체크 후 조건부 비활성화 수행
---
- name: Service Status Check and Conditional Disable
  hosts: all
  gather_facts: yes
  become: yes
  serial: 5  # 5개 노드씩 순차 처리하여 안정성 확보
  
  vars:
    # 비활성화 대상 서비스 설정 (기본값: false로 안전하게 설정)
    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:
    # Phase 1: 현재 상태 체크 (기존 플레이북 재사용)
    - name: Include service status check
      include_tasks: service_status_check_complete.yml
      
    # Phase 2: 조건부 서비스 비활성화
    - name: Include conditional service disable tasks
      include_tasks: conditional_service_disable.yml
      
    # Phase 3: 시간 동기화 처리
    - name: Include time synchronization tasks
      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)
              
    # Phase 4: 최종 검증 및 보고
    - name: Include final verification
      include_tasks: final_verification.yml
      
      
      
# conditional_service_disable.yml
# 조건부 서비스 비활성화 태스크
---
# ========================================
# AUDITD 서비스 비활성화
# ========================================

- name: Check if auditd disable is requested and service is active
  set_fact:
    should_disable_auditd: "{{ disable_auditd and node_result.auditd.service_exists and node_result.auditd.running }}"

- block:
    - name: Create backup of auditd configuration
      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
      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
      systemd:
        name: auditd
        state: stopped
        enabled: no
      register: auditd_disable_result
      
    - name: Mask auditd service to prevent accidental restart
      systemd:
        name: auditd
        masked: yes
      when: auditd_disable_result is succeeded
      
    - name: Verify auditd is stopped
      systemd:
        name: auditd
      register: auditd_final_status
      
    - name: Display auditd disable result
      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
  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

# ========================================
# MLOCATE 서비스 비활성화
# ========================================

- name: Check if mlocate disable is requested and timer is active
  set_fact:
    should_disable_mlocate: "{{ disable_mlocate and node_result.mlocate.timer_exists and node_result.mlocate.timer_running }}"

- block:
    - name: Log mlocate disable action
      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
      systemd:
        name: "{{ node_result.mlocate.timer_service }}"
        state: stopped
        enabled: no
      register: mlocate_disable_result
      
    - name: Mask mlocate timer to prevent accidental restart
      systemd:
        name: "{{ node_result.mlocate.timer_service }}"
        masked: yes
      when: mlocate_disable_result is succeeded
      
    - name: Remove mlocate database if requested
      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
      systemd:
        name: "{{ node_result.mlocate.timer_service }}"
      register: mlocate_final_status
      
    - name: Display mlocate disable result
      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
  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

# ========================================
# NTP 서비스 비활성화 (선택적)
# ========================================

- name: Check if NTP disable is requested and service is active
  set_fact:
    should_disable_ntp: "{{ disable_ntp_services and node_result.ntp.active_service != 'none' }}"

- block:
    - name: Create backup of time service configurations
      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
      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
      systemd:
        name: "{{ node_result.ntp.active_service }}"
        state: stopped
        enabled: no
      register: ntp_disable_result
      
    - name: Mask NTP service to prevent accidental restart
      systemd:
        name: "{{ node_result.ntp.active_service }}"
        masked: yes
      when: ntp_disable_result is succeeded
      
    - name: Verify NTP service is stopped
      systemd:
        name: "{{ node_result.ntp.active_service }}"
      register: ntp_final_status
      
    - name: Display NTP disable result
      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
  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
  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
  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
  copy:
    content: "{{ disable_summary | to_nice_json }}"
    dest: "/tmp/disable_actions_{{ inventory_hostname }}.json"
  delegate_to: localhost
  
  
  
# time_sync_correction.yml
# 시간 동기화 문제 해결 태스크
---
# ========================================
# 시간 차이 분석 및 교정
# ========================================

- name: Calculate time drift from reference
  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
  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
  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 }}

# ========================================
# NTP 서비스 상태 확인 및 수정
# ========================================

- name: Fix NTP synchronization issues
  block:
    - name: Install chrony if no time service is available
      package:
        name: chrony
        state: present
      when: node_result.ntp.active_service == 'none'
      register: chrony_installed
      
    - name: Configure chrony with reliable NTP servers
      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
      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)
      command: chrony -q 'server {{ ntp_server_pool }} iburst'
      when: time_correction_needed and drift_level in ['MINOR', 'MODERATE']
      register: gradual_sync_result
      failed_when: false
      
    - name: Force immediate time synchronization (step for critical drift)
      block:
        - name: Stop chronyd for manual time step
          systemd:
            name: chronyd
            state: stopped
            
        - name: Force time step with chronyd
          command: chronyd -q 'server {{ ntp_server_pool }} iburst'
          register: step_sync_result
          
        - name: Start chronyd after manual sync
          systemd:
            name: chronyd
            state: started
            
      when: time_correction_needed and drift_level == 'CRITICAL'
      
    - name: Wait for synchronization to stabilize
      wait_for:
        timeout: 30
      when: chronyd_started is changed or gradual_sync_result is defined or step_sync_result is defined
      
    - name: Verify time synchronization after correction
      command: timedatectl status
      register: time_verify_result
      
    - name: Get updated chrony status
      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
      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
  block:
    - name: Create time sync monitoring script
      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=30
          
          # Get current time sync status
          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" >> $LOG_FILE
              systemctl restart chronyd
          fi
          
          # Check chrony tracking if available
          if command -v chronyc &> /dev/null; then
              CHRONY_TRACKING=$(chronyc tracking)
              OFFSET=$(echo "$CHRONY_TRACKING" | grep "Last offset" | awk '{print $4}')
              
              if [[ $(echo "$OFFSET > $MAX_DRIFT" | bc -l) -eq 1 ]] 2>/dev/null; then
                  echo "$(date): WARNING - Time offset too large: ${OFFSET}s" >> $LOG_FILE
                  chrony -q 'server {{ ntp_server_pool }} iburst'
              fi
          fi
        dest: /usr/local/bin/time_sync_monitor.sh
        mode: '0755'
        
    - name: Create cron job for time sync monitoring
      cron:
        name: "Time synchronization monitoring"
        minute: "*/15"
        job: "/usr/local/bin/time_sync_monitor.sh"
        user: root
        
    - name: Create systemd timer for time sync monitoring (alternative)
      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
      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 time sync monitoring timer
      systemd:
        name: time-sync-monitor.timer
        enabled: yes
        state: started
        daemon_reload: yes
        
  when: time_correction_needed and node_result.ntp.ntp_synchronized

# ========================================
# 시간 동기화 권장사항
# ========================================

- name: Generate time sync recommendations
  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
  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
  
  
  
# final_verification.yml
# 최종 검증 및 보고서 생성
---
# ========================================
# 변경 후 서비스 상태 재검증
# ========================================

- name: Re-check auditd status after changes
  systemd:
    name: auditd
  register: auditd_final_check
  failed_when: false
  when: node_result.auditd.service_exists

- name: Re-check mlocate timer status after changes
  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
  command: timedatectl status
  register: ntp_final_check
  failed_when: false

- name: Get updated chrony status
  command: chronyc tracking
  register: chrony_final_check
  failed_when: false
  when: node_result.ntp.chronyd_exists

- name: Get current time after changes
  setup:
    filter: ansible_date_time
  register: final_time_info

# ========================================
# 최종 상태 분석
# ========================================

- name: Analyze final service states
  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
  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
  copy:
    content: "{{ final_verification | to_nice_json }}"
    dest: "/tmp/final_verification_{{ inventory_hostname }}.json"
  delegate_to: localhost

# ========================================
# 전체 클러스터 최종 요약 (run_once)
# ========================================

- name: Collect all verification reports
  find:
    paths: /tmp
    patterns: "final_verification_*.json"
  register: verification_files
  delegate_to: localhost
  run_once: true

- name: Read all verification files
  slurp:
    src: "{{ item.path }}"
  register: verification_contents
  loop: "{{ verification_files.files }}"
  delegate_to: localhost
  run_once: true

- name: Combine verification results
  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
  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
  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
  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
  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 -%}
      {{ 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 (not verification.verification_status.auditd.requested_disable or verification.verification_status.auditd.disable_successful) and (not verification.verification_status.mlocate.requested_disable or verification.verification_status.mlocate.disable_successful) else 'PARTIAL' }}
      {% endfor %}
    dest: "./final_verification_report.csv"
  delegate_to: localhost
  run_once: true

- name: Clean up temporary verification files
  file:
    path: "{{ item.path }}"
    state: absent
  loop: "{{ verification_files.files }}"
  delegate_to: localhost
  run_once: true

# ========================================
# 권장 사후 조치
# ========================================

- name: Display post-operation recommendations
  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 pool.ntp.org
      
      3. Check firewall settings:
         firewall-cmd --list-ports | grep 123
         iptables -L | grep 123
      
      4. Force time synchronization:
         chrony -q 'server pool.ntp.org 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
  
  
```j2  
# Chrony configuration template
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
# Host: {{ inventory_hostname }}

# NTP Server Configuration
{% if ntp_server_pool is defined %}
pool {{ ntp_server_pool }} iburst
{% else %}
pool pool.ntp.org iburst
{% endif %}

# Additional reliable NTP servers
pool 0.pool.ntp.org iburst
pool 1.pool.ntp.org iburst
pool 2.pool.ntp.org iburst

# Local stratum 10 server for isolation
server 127.127.1.0 stratum 10

# Record the rate at which the system clock gains/losses time
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC)
rtcsync

# Enable hardware timestamping on all interfaces that support it
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock
minsources 2

# Allow NTP client access from local network
{% if ansible_default_ipv4.network is defined %}
allow {{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}
{% endif %}
allow 127.0.0.1

# Serve time even if not synchronized to a time source
local stratum 10

# Specify file containing keys for NTP authentication
keyfile /etc/chrony.keys

# Get TAI-UTC offset and leap seconds from the system tz database
leapsectz right/UTC

# Specify directory for log files
logdir /var/log/chrony

# Select which information is logged
#log measurements statistics tracking



```md
# Service Management Playbook 사용 가이드

## 개요
이 플레이북은 다중 서버 환경에서 auditd, mlocate, NTP 서비스의 상태를 체크하고 필요시 안전하게 비활성화하는 기능을 제공합니다.

## 파일 구조

.
├── service_disable_playbook.yml # 메인 플레이북
├── service_status_check_complete.yml # 서비스 상태 체크 (기존)
├── conditional_service_disable.yml # 조건부 서비스 비활성화
├── time_sync_correction.yml # 시간 동기화 교정
├── final_verification.yml # 최종 검증 및 보고
├── templates/chrony.conf.j2 # Chrony 설정 템플릿
└── README_Service_Management.md # 이 가이드


## 주요 기능

### 1. 서비스 상태 체크
- auditd 서비스 존재 여부 및 상태 확인
- mlocate/plocate 패키지 및 타이머 상태 확인
- NTP 서비스 (chronyd/ntpd/systemd-timesyncd) 상태 확인
- 시간 동기화 상태 및 노드 간 시간 차이 분석

### 2. 조건부 서비스 비활성화
- **auditd**: active 상태인 경우 안전하게 비활성화 및 마스킹
- **mlocate**: 타이머가 running 상태인 경우 비활성화 및 DB 제거 옵션
- **NTP**: 필요시 NTP 서비스 비활성화 (권장하지 않음)

### 3. 시간 동기화 교정
- 노드 간 시간 차이가 임계값을 초과하는 경우 자동 교정
- Chrony 서비스 설치 및 설정
- 시간 동기화 모니터링 설정

### 4. 안전 기능
- 설정 파일 자동 백업
- 변경 사항 로그 기록
- 순차 처리 (serial: 5)로 안정성 확보
- 서비스 마스킹으로 의도치 않은 재시작 방지

## 실행 방법

### 1. 상태 체크만 수행
```bash
ansible-playbook -i inventory service_disable_playbook.yml \
    -e "disable_auditd=false" \
    -e "disable_mlocate=false" \
    -e "disable_ntp_services=false"

2. auditd만 비활성화

ansible-playbook -i inventory service_disable_playbook.yml \
    -e "disable_auditd=true" \
    -e "disable_mlocate=false" \
    -e "disable_ntp_services=false"

3. auditd와 mlocate 모두 비활성화

ansible-playbook -i inventory service_disable_playbook.yml \
    -e "disable_auditd=true" \
    -e "disable_mlocate=true" \
    -e "disable_ntp_services=false"

4. 시간 동기화 교정 포함 실행

ansible-playbook -i inventory service_disable_playbook.yml \
    -e "disable_auditd=true" \
    -e "disable_mlocate=true" \
    -e "max_time_drift_seconds=30" \
    -e "ntp_server_pool=kr.pool.ntp.org"

5. 특정 노드만 대상으로 실행

ansible-playbook -i inventory service_disable_playbook.yml \
    -l "webserver*" \
    -e "disable_auditd=true"

주요 변수 설정

필수 변수

변수명기본값설명
disable_auditdfalseauditd 서비스 비활성화 여부
disable_mlocatefalsemlocate 서비스 비활성화 여부
disable_ntp_servicesfalseNTP 서비스 비활성화 여부 (권장하지 않음)

선택적 변수

변수명기본값설명
max_time_drift_seconds30시간 차이 임계값 (초)
ntp_server_poolpool.ntp.org기본 NTP 서버 풀
backup_configstrue설정 파일 백업 여부
log_changestrue변경 사항 로깅 여부

시간 동기화 문제 해결 가이드

시간 차이 수준별 대응

  • MINOR (5-30초): 자동 점진적 동기화
  • MODERATE (30-60초): 강제 동기화 수행
  • HIGH (60-300초): NTP 서비스 재시작 + 강제 동기화
  • CRITICAL (300초+): 수동 시간 설정 + 시스템 점검 권장

수동 시간 동기화

# 시간 동기화 상태 확인
timedatectl status

# Chrony 소스 확인
chronyc sources -v

# 강제 시간 동기화
chrony -q 'server kr.pool.ntp.org iburst'

# Chrony 서비스 재시작
systemctl restart chronyd

시간 동기화 문제 해결

  1. 네트워크 연결 확인

    ping kr.pool.ntp.org
    telnet kr.pool.ntp.org 123
  2. 방화벽 설정 확인

    firewall-cmd --list-ports | grep 123
    iptables -L | grep 123
  3. 하드웨어 클럭 확인

    hwclock --show
    hwclock --hctosys  # 하드웨어 클럭을 시스템 클럭으로

생성되는 보고서

1. clear_service_status.csv

전체 서비스 상태 요약 보고서

2. time_sync_detailed_report.csv

시간 동기화 상세 분석 보고서

3. final_verification_report.csv

작업 완료 후 최종 검증 보고서

4. 로그 파일

  • /var/log/ansible_service_changes.log: 각 노드의 변경 사항 기록
  • /var/log/time_sync_monitor.log: 시간 동기화 모니터링 로그

롤백 절차

auditd 서비스 복원

sudo systemctl unmask auditd
sudo systemctl enable auditd
sudo systemctl start auditd

# 백업된 설정 복원 (필요시)
sudo cp /etc/audit/auditd.conf.backup.* /etc/audit/auditd.conf

mlocate 서비스 복원

sudo systemctl unmask mlocate-updatedb.timer
sudo systemctl enable mlocate-updatedb.timer
sudo systemctl start mlocate-updatedb.timer

# 데이터베이스 즉시 업데이트
sudo updatedb

주의사항

⚠️ 중요한 고려사항

  1. auditd 비활성화: 보안 감사 기능이 중단되므로 대안 모니터링 필요
  2. mlocate 비활성화: locate 명령어 사용 불가, 파일 검색 속도 저하
  3. NTP 비활성화: 시간 동기화 중단으로 로그 분석 등에 영향

🔒 보안 권장사항

  • auditd 비활성화 시 SIEM 등 대안 보안 모니터링 도구 사용
  • 정기적인 보안 로그 검토 체계 유지
  • 시스템 변경사항에 대한 별도 감사 절차 수립

📊 모니터링

  • 비활성화 후 시스템 성능 변화 모니터링
  • 로그 파일 정기 검토
  • 시간 동기화 상태 지속적 확인

트러블슈팅

일반적인 문제

  1. 권한 부족: become: yes 및 sudo 권한 확인
  2. 서비스 의존성: systemctl list-dependencies 로 확인
  3. 실행 중인 프로세스: ps aux | grep service_name 로 확인

연락처

시스템 관리팀 또는 Ansible 관리자에게 문의

0개의 댓글