---
# Security hardening tasks for C2 server - Fixed AWS collection issues

- name: Check if system is updated
  apt:
    update_cache: yes
  register: apt_update_result
  until: apt_update_result is success
  retries: 5
  delay: 5

- name: Install security packages (non-UFW)
  apt:
    name:
      - fail2ban
      - unattended-upgrades
      - debsums
      - aide
      - rkhunter
      - logrotate
    state: present
  register: package_install
  until: package_install is success
  retries: 3
  delay: 5

# Provider and role detection - DRY principle
- name: Determine deployment configuration
  set_fact:
    is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
    is_c2_server: "{{ 'c2servers' in group_names }}"
    is_redirector: "{{ 'redirectors' in group_names }}"

# UFW Configuration Block - Non-AWS only
- name: UFW detection and installation block
  block:
    - name: Check if UFW is installed
      command: which ufw
      register: ufw_check
      failed_when: false
      changed_when: false

    - name: Install UFW if not present (non-AWS)
      apt:
        name: ufw
        state: present
        update_cache: yes
      register: ufw_install
      until: ufw_install is success
      retries: 3
      delay: 5
      when: ufw_check.rc != 0
  when: not is_aws_provider

- name: Configure UFW for non-AWS deployments
  block:
    - name: Configure UFW default policies
      community.general.ufw:
        state: enabled
        policy: deny
        direction: incoming
      ignore_errors: yes

    - name: Configure UFW for C2 server
      block:
        - name: Reset UFW to default deny
          community.general.ufw:
            state: enabled
            policy: deny
            direction: incoming

        - name: Allow SSH only from operator IP
          community.general.ufw:
            rule: allow
            port: "22"
            src: "{{ operator_ip }}"
            proto: tcp

        - name: Allow Havoc Teamserver only from operator IP
          community.general.ufw:
            rule: allow
            port: "{{ havoc_teamserver_port | default('40056') }}"
            src: "{{ operator_ip }}"
            proto: tcp

        - name: Allow traffic only from redirector
          community.general.ufw:
            rule: allow
            port: "{{ item }}"
            src: "{{ redirector_ip }}"
            proto: tcp
          loop:
            - "80"
            - "443"
            - "{{ havoc_http_port | default('8080') }}"
            - "{{ havoc_https_port | default('9443') }}"
            - "{{ havoc_payload_port | default('8443') }}"
            - "{{ gophish_admin_port }}"
            - "{{ gophish_phish_port | default('8081') }}"
            - "{{ tracker_port | default('5000') }}"
      when: is_c2_server

    - name: Configure UFW for redirector
      block:
        - name: Reset UFW to default deny
          community.general.ufw:
            state: enabled
            policy: deny
            direction: incoming

        - name: Allow SSH only from operator IP
          community.general.ufw:
            rule: allow
            port: "22"
            src: "{{ operator_ip }}"
            proto: tcp

        - name: Allow public services from anywhere
          community.general.ufw:
            rule: allow
            port: "{{ item }}"
            proto: tcp
          loop:
            - "80"
            - "443"
            - "{{ shell_handler_port | default('4488') }}"
      when: is_redirector
  when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)

# Iptables fallback configuration - Non-AWS only
- name: Configure basic iptables rules if UFW unavailable
  block:
    - name: Set up basic iptables rules for C2 server
      shell: |
        iptables -F
        iptables -P INPUT DROP
        iptables -P FORWARD DROP
        iptables -P OUTPUT ACCEPT
        # Allow established connections
        iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
        # Allow loopback
        iptables -A INPUT -i lo -j ACCEPT
        # Allow SSH from operator
        iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
        # Allow Havoc teamserver from operator
        iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
        # Allow traffic from redirector
        iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ havoc_payload_port | default(8443) }} -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ gophish_phish_port | default(8081) }} -s {{ redirector_ip }} -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ tracker_port | default(5000) }} -s {{ redirector_ip }} -j ACCEPT
      when: is_c2_server

    - name: Set up basic iptables rules for redirector
      shell: |
        iptables -F
        iptables -P INPUT DROP
        iptables -P FORWARD DROP
        iptables -P OUTPUT ACCEPT
        # Allow established connections
        iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
        # Allow loopback
        iptables -A INPUT -i lo -j ACCEPT
        # Allow SSH from operator
        iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
        # Allow public services
        iptables -A INPUT -p tcp --dport 80 -j ACCEPT
        iptables -A INPUT -p tcp --dport 443 -j ACCEPT
        iptables -A INPUT -p tcp --dport {{ shell_handler_port | default(4488) }} -j ACCEPT
      when: is_redirector

    - name: Save iptables rules
      shell: |
        iptables-save > /etc/iptables/rules.v4
      ignore_errors: yes
  when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))

# SSH Hardening - Universal application
- name: Harden SSH configuration
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    state: present
    backup: yes
  loop:
    - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
    - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
    - { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
    - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
    - { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
    - { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
    - { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
    - { regexp: '^#?Protocol', line: 'Protocol 2' }
    - { regexp: '^#?MaxStartups', line: 'MaxStartups 10:30:100' }
    - { regexp: '^#?LoginGraceTime', line: 'LoginGraceTime 60' }
  register: ssh_config_updated

# System resource limits configuration
- name: Configure system resource limits
  community.general.pam_limits:
    domain: "*"
    limit_type: "{{ item.limit_type }}"
    limit_item: "{{ item.limit_item }}"
    value: "{{ item.value }}"
  loop:
    - { limit_type: soft, limit_item: nofile, value: 65535 }
    - { limit_type: hard, limit_item: nofile, value: 65535 }
    - { limit_type: soft, limit_item: nproc, value: 4096 }
    - { limit_type: hard, limit_item: nproc, value: 4096 }

# Fail2ban configuration - Universal
- name: Set up fail2ban SSH jail
  copy:
    dest: /etc/fail2ban/jail.d/sshd.conf
    content: |
      [sshd]
      enabled = true
      port = ssh
      filter = sshd
      logpath = /var/log/auth.log
      maxretry = 5
      bantime = 3600
      findtime = 600
      
      [sshd-ddos]
      enabled = true
      port = ssh
      filter = sshd-ddos
      logpath = /var/log/auth.log
      maxretry = 2
      bantime = 7200
    mode: '0644'
  register: fail2ban_config_updated

# Automatic security updates
- name: Enable automatic security updates
  copy:
    dest: /etc/apt/apt.conf.d/20auto-upgrades
    content: |
      APT::Periodic::Update-Package-Lists "1";
      APT::Periodic::Unattended-Upgrade "1";
      APT::Periodic::AutocleanInterval "7";
      APT::Periodic::Download-Upgradeable-Packages "1";
    mode: '0644'

# Log cleaning functionality
- name: Create Tools directory if it doesn't exist
  file:
    path: /root/Tools
    state: directory
    mode: '0700'
  when: zero_logs | default(false) | bool

- name: Create log cleaning script if zero-logs is enabled
  copy:
    dest: /root/Tools/clean-logs.sh
    content: |
      #!/bin/bash
      # C2ingRed Log cleaning script for operational security
      echo "Starting log cleaning at $(date)" >> /tmp/clean-logs.log
      
      # Clear authentication logs
      echo "" > /var/log/auth.log
      echo "" > /var/log/auth.log.1
      
      # Clear system logs
      echo "" > /var/log/syslog
      echo "" > /var/log/syslog.1
      
      # Clear kernel logs
      echo "" > /var/log/kern.log
      echo "" > /var/log/kern.log.1
      
      # Clear application specific logs
      find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
      find /var/log -type f -name "*.log.*" -exec truncate -s 0 {} \;
      
      # Clear journal logs
      journalctl --vacuum-time=1s 2>/dev/null || true
      
      # Clear bash history for all users
      for user_home in /home/*; do
          if [ -d "$user_home" ]; then
              echo "" > "$user_home/.bash_history" 2>/dev/null || true
          fi
      done
      
      # Clear root bash history
      echo "" > /root/.bash_history 2>/dev/null || true
      history -c 2>/dev/null || true
      
      # Clear tmp files
      find /tmp -type f -mtime +1 -delete 2>/dev/null || true
      
      echo "Log cleaning completed at $(date)" >> /tmp/clean-logs.log
    mode: '0700'
  when: zero_logs | default(false) | bool

- name: Create cron job for log cleaning if enabled
  cron:
    name: "Clean operational logs"
    minute: "0"
    hour: "*/6"
    job: "/root/Tools/clean-logs.sh"
    user: root
  when: zero_logs | default(false) | bool

# Service restart handlers
- name: Restart SSH service if configuration changed
  service:
    name: ssh
    state: restarted
  when: ssh_config_updated.changed

- name: Check if fail2ban service exists
  stat:
    path: "/etc/init.d/fail2ban"
  register: fail2ban_service_stat

- name: Restart fail2ban service if installed and configuration changed
  service:
    name: fail2ban
    state: restarted
    enabled: yes
  when: fail2ban_service_stat.stat.exists and fail2ban_config_updated.changed

# AWS-specific security updates - NO MODULES REQUIRED
- name: Check if we're running on AWS provider
  set_fact:
    is_aws_provider: "{{ hostvars['localhost']['provider'] | default('') == 'aws' }}"

- name: AWS-specific security updates
  block:
    - name: Get redirector security group information
      block:
      - name: Check if infrastructure state file exists
        stat:
          path: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
        register: redirector_state_file
        delegate_to: localhost

      - name: Load redirector state if available
        include_vars:
          file: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
          name: redirector_state
        when: redirector_state_file.stat.exists
        delegate_to: localhost
      
    - name: Update redirector security group via raw AWS CLI
      delegate_to: localhost
      shell: |
        export AWS_ACCESS_KEY_ID="{{ hostvars['localhost']['aws_access_key'] }}"
        export AWS_SECRET_ACCESS_KEY="{{ hostvars['localhost']['aws_secret_key'] }}"
        export AWS_DEFAULT_REGION="{{ redirector_state.region | default(aws_region) }}"
        
        # Install AWS CLI if not present
        if ! command -v aws &> /dev/null; then
          curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
          unzip -q awscliv2.zip
          sudo ./aws/install --update
          rm -rf aws awscliv2.zip
        fi
        
        # Add security group rule (ignore if exists)
        aws ec2 authorize-security-group-ingress \
          --group-id {{ redirector_state.security_group_id }} \
          --protocol tcp \
          --port 22 \
          --cidr {{ ansible_host }}/32 \
          2>/dev/null || echo "Rule already exists or added successfully"
      when: redirector_state is defined and redirector_state.security_group_id is defined
      register: sg_update_result
      ignore_errors: yes

    - name: Display security group update result
      debug:
        msg: |
          AWS Security Group Update: {{ 'SUCCESS' if sg_update_result.rc == 0 else 'COMPLETED' }}
          C2 Server IP: {{ ansible_host }}
          Security Group ID: {{ redirector_state.security_group_id | default('NOT FOUND') }}

  when: is_aws_provider | bool

# Final security status report
- name: Generate security hardening report
  debug:
    msg: |
      C2ingRed Security Hardening Complete:
      =====================================
      Provider: {{ provider | default('unknown') }}
      Server Type: {{ 'C2 Server' if is_c2_server else 'Redirector' if is_redirector else 'Unknown' }}
      SSH Hardened: {{ 'YES' if ssh_config_updated.changed else 'ALREADY CONFIGURED' }}
      Fail2ban Configured: {{ 'YES' if fail2ban_config_updated.changed else 'ALREADY CONFIGURED' }}
      Firewall: {{ 'AWS Security Groups' if is_aws_provider else 'UFW/iptables' }}
      Log Cleaning: {{ 'ENABLED' if zero_logs | default(false) | bool else 'DISABLED' }}
      Auto Updates: ENABLED
      System Limits: CONFIGURED