AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible for SOC and SIEM: Automate Security Operations Complete Guide

By Luca Berton · Published 2024-01-01 · Category: installation

Complete guide to Ansible for Security Operations Centers (SOC) and SIEM integration. Automate incident response playbooks, log forwarding.

Security Operations Centers run on speed — detect, investigate, contain, remediate. Ansible automates every phase. Block malicious IPs in seconds, collect forensic data across hundreds of hosts simultaneously, push SIEM configurations consistently, and run compliance scans on demand. Here's how.

Why Ansible for Security Operations

Manual SOCAutomated with Ansible
SSH into each host to block IPBlock IP on all firewalls in 10 seconds
Manually collect logs for investigationGather forensic data from 500 hosts in parallel
Update SIEM agents one by onePush config to all agents simultaneously
Hours to contain an incidentMinutes from detection to containment
Inconsistent hardeningIdentical baseline across all systems

Incident Response Automation

Automated Threat Containment

---
- name: Contain compromised host
  hosts: "{{ compromised_host }}"
  become: true
  vars:
    incident_id: "{{ incident }}"
    quarantine_vlan: 999
  tasks:
    - name: Kill malicious processes
      ansible.builtin.shell: |
        for pid in $(ps aux | grep -i "{{ malicious_process }}" | grep -v grep | awk '{print $2}'); do
          kill -9 $pid
        done
      when: malicious_process is defined
      changed_when: true

    - name: Block outbound connections from compromised host
      ansible.builtin.iptables:
        chain: OUTPUT
        destination: "{{ item }}"
        jump: DROP
        comment: "INC-{{ incident_id }}: Block C2 server"
      loop: "{{ c2_servers | default([]) }}"

    - name: Disable compromised user accounts
      ansible.builtin.user:
        name: "{{ item }}"
        password_lock: true
        shell: /sbin/nologin
      loop: "{{ compromised_users | default([]) }}"

    - name: Collect forensic snapshot
      ansible.builtin.shell: |
        mkdir -p /tmp/forensics-{{ incident_id }}
        ps auxf > /tmp/forensics-{{ incident_id }}/processes.txt
        netstat -tulpn > /tmp/forensics-{{ incident_id }}/connections.txt
        last -50 > /tmp/forensics-{{ incident_id }}/logins.txt
        cat /etc/passwd > /tmp/forensics-{{ incident_id }}/passwd.txt
        find /tmp /var/tmp -mtime -1 -ls > /tmp/forensics-{{ incident_id }}/recent_tmp.txt
        journalctl --since "24 hours ago" > /tmp/forensics-{{ incident_id }}/journal.txt
      changed_when: true

    - name: Fetch forensic data
      ansible.builtin.fetch:
        src: "/tmp/forensics-{{ incident_id }}/"
        dest: "/evidence/{{ incident_id }}/{{ inventory_hostname }}/"
        flat: false

Block Indicators of Compromise (IOCs)

---
- name: Block IOCs across infrastructure
  hosts: all
  become: true
  vars:
    malicious_ips:
      - 198.51.100.23
      - 203.0.113.45
      - 192.0.2.100
    malicious_domains:
      - evil-c2.example.com
      - malware-drop.example.net
  tasks:
    - name: Block malicious IPs in iptables
      ansible.builtin.iptables:
        chain: "{{ item.0 }}"
        source: "{{ item.1 }}"
        jump: DROP
        comment: "IOC block - automated"
      loop: "{{ ['INPUT', 'OUTPUT'] | product(malicious_ips) | list }}"

    - name: Block domains in /etc/hosts
      ansible.builtin.lineinfile:
        path: /etc/hosts
        line: "127.0.0.1 {{ item }}"
        state: present
      loop: "{{ malicious_domains }}"

    - name: Update firewalld (RHEL/CentOS)
      ansible.posix.firewalld:
        rich_rule: "rule family='ipv4' source address='{{ item }}' drop"
        permanent: true
        immediate: true
        state: enabled
      loop: "{{ malicious_ips }}"
      when: ansible_facts['os_family'] == 'RedHat'

Fleet-Wide Forensic Collection

---
- name: Collect forensic data across fleet
  hosts: all
  become: true
  gather_facts: true
  tasks:
    - name: Search for IOC file hashes
      ansible.builtin.find:
        paths:
          - /tmp
          - /var/tmp
          - /home
        recurse: true
        file_type: file
        size: "1k-10m"
      register: suspicious_files

    - name: Calculate hashes of suspicious files
      ansible.builtin.stat:
        path: "{{ item.path }}"
        checksum_algorithm: sha256
      register: file_hashes
      loop: "{{ suspicious_files.files[:100] }}"

    - name: Check for known malicious hashes
      ansible.builtin.set_fact:
        ioc_matches: >-
          {{ file_hashes.results
             | selectattr('stat.checksum', 'in', known_bad_hashes)
             | list }}
      vars:
        known_bad_hashes: "{{ lookup('file', 'ioc_hashes.txt').splitlines() }}"

    - name: Alert on IOC matches
      ansible.builtin.debug:
        msg: "🚨 IOC MATCH on {{ inventory_hostname }}: {{ item.stat.path }} ({{ item.stat.checksum }})"
      loop: "{{ ioc_matches }}"
      when: ioc_matches | length > 0

    - name: Check for unauthorized SSH keys
      ansible.builtin.find:
        paths: /home
        patterns: "authorized_keys"
        recurse: true
      register: ssh_keys

    - name: Collect SSH key contents
      ansible.builtin.slurp:
        src: "{{ item.path }}"
      register: key_contents
      loop: "{{ ssh_keys.files }}"

    - name: Check for unauthorized cron jobs
      ansible.builtin.command: find /var/spool/cron -type f
      register: cron_files
      changed_when: false

    - name: Collect cron contents
      ansible.builtin.slurp:
        src: "{{ item }}"
      register: cron_contents
      loop: "{{ cron_files.stdout_lines }}"
      when: cron_files.stdout_lines | length > 0

See also: Ansible for SIEM and SOC: Automate Security Operations, Incident Response, and Compliance

SIEM Integration

Splunk Forwarder Deployment

---
- name: Deploy Splunk Universal Forwarder
  hosts: all
  become: true
  vars:
    splunk_version: "9.3.0"
    splunk_server: splunk-indexer.example.com:9997
    splunk_deploy_server: splunk-deploy.example.com:8089
  tasks:
    - name: Download Splunk UF
      ansible.builtin.get_url:
        url: "https://download.splunk.com/products/universalforwarder/releases/{{ splunk_version }}/linux/splunkforwarder-{{ splunk_version }}-linux-amd64.deb"
        dest: /tmp/splunkforwarder.deb
        checksum: "sha256:{{ splunk_uf_checksum }}"

    - name: Install Splunk UF
      ansible.builtin.apt:
        deb: /tmp/splunkforwarder.deb
      when: ansible_facts['os_family'] == 'Debian'

    - name: Configure outputs
      ansible.builtin.template:
        src: splunk-outputs.conf.j2
        dest: /opt/splunkforwarder/etc/system/local/outputs.conf
        owner: splunk
        mode: '0600'
      notify: restart splunkforwarder

    - name: Configure inputs (log sources)
      ansible.builtin.template:
        src: splunk-inputs.conf.j2
        dest: /opt/splunkforwarder/etc/system/local/inputs.conf
        owner: splunk
        mode: '0600'
      notify: restart splunkforwarder

    - name: Enable and start Splunk UF
      ansible.builtin.service:
        name: SplunkForwarder
        state: started
        enabled: true

  handlers:
    - name: restart splunkforwarder
      ansible.builtin.service:
        name: SplunkForwarder
        state: restarted

Elasticsearch/ELK Stack Agents

---
- name: Deploy Filebeat for ELK
  hosts: all
  become: true
  vars:
    elastic_version: "8.15"
    elasticsearch_hosts:
      - "https://es01.example.com:9200"
      - "https://es02.example.com:9200"
  tasks:
    - name: Add Elastic repository
      ansible.builtin.apt_repository:
        repo: "deb https://artifacts.elastic.co/packages/{{ elastic_version }}/apt stable main"
        state: present
        filename: elastic

    - name: Install Filebeat
      ansible.builtin.apt:
        name: filebeat
        state: present

    - name: Configure Filebeat
      ansible.builtin.template:
        src: filebeat.yml.j2
        dest: /etc/filebeat/filebeat.yml
        mode: '0600'
      notify: restart filebeat

    - name: Enable modules
      ansible.builtin.command: >
        filebeat modules enable system auditd
      changed_when: true
      notify: restart filebeat

    - name: Start Filebeat
      ansible.builtin.service:
        name: filebeat
        state: started
        enabled: true

  handlers:
    - name: restart filebeat
      ansible.builtin.service:
        name: filebeat
        state: restarted

Wazuh Agent Deployment

---
- name: Deploy Wazuh SIEM agent
  hosts: all
  become: true
  vars:
    wazuh_manager: wazuh.example.com
    wazuh_version: "4.9"
  tasks:
    - name: Add Wazuh repository
      ansible.builtin.apt_repository:
        repo: "deb https://packages.wazuh.com/4.x/apt/ stable main"
        state: present
        filename: wazuh

    - name: Install Wazuh agent
      ansible.builtin.apt:
        name: wazuh-agent
        state: present
      environment:
        WAZUH_MANAGER: "{{ wazuh_manager }}"

    - name: Configure Wazuh agent
      ansible.builtin.template:
        src: ossec.conf.j2
        dest: /var/ossec/etc/ossec.conf
        mode: '0640'
      notify: restart wazuh-agent

    - name: Start Wazuh agent
      ansible.builtin.service:
        name: wazuh-agent
        state: started
        enabled: true

  handlers:
    - name: restart wazuh-agent
      ansible.builtin.service:
        name: wazuh-agent
        state: restarted

Compliance Scanning

CIS Benchmark Enforcement

---
- name: CIS benchmark hardening
  hosts: all
  become: true
  tasks:
    - name: "CIS 1.1.1 - Disable cramfs"
      ansible.builtin.lineinfile:
        path: /etc/modprobe.d/cis.conf
        line: "install cramfs /bin/true"
        create: true
        mode: '0644'

    - name: "CIS 1.4.1 - Ensure permissions on bootloader config"
      ansible.builtin.file:
        path: /boot/grub2/grub.cfg
        owner: root
        group: root
        mode: '0600'
      when: ansible_facts['os_family'] == 'RedHat'

    - name: "CIS 5.2.1 - Ensure SSH protocol 2"
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?Protocol'
        line: 'Protocol 2'
      notify: restart sshd

    - name: "CIS 5.2.4 - Disable SSH root login"
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: restart sshd

    - name: "CIS 5.2.11 - Set SSH MaxAuthTries"
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?MaxAuthTries'
        line: 'MaxAuthTries 4'
      notify: restart sshd

    - name: "CIS 4.2.1 - Ensure auditd is installed"
      ansible.builtin.apt:
        name:
          - auditd
          - audispd-plugins
        state: present

    - name: "CIS 4.2.3 - Configure audit rules"
      ansible.builtin.template:
        src: audit-cis.rules.j2
        dest: /etc/audit/rules.d/cis.rules
        mode: '0640'
      notify: restart auditd

  handlers:
    - name: restart sshd
      ansible.builtin.service:
        name: sshd
        state: restarted

    - name: restart auditd
      ansible.builtin.service:
        name: auditd
        state: restarted

Vulnerability Scanning Integration

- name: Run OpenSCAP compliance scan
  hosts: all
  become: true
  tasks:
    - name: Install OpenSCAP
      ansible.builtin.dnf:
        name:
          - openscap-scanner
          - scap-security-guide
        state: present

    - name: Run CIS scan
      ansible.builtin.command: >
        oscap xccdf eval
        --profile xccdf_org.ssgproject.content_profile_cis
        --results /tmp/scan-results-{{ inventory_hostname }}.xml
        --report /tmp/scan-report-{{ inventory_hostname }}.html
        /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
      register: scan_result
      failed_when: false
      changed_when: false

    - name: Fetch scan reports
      ansible.builtin.fetch:
        src: "/tmp/scan-report-{{ inventory_hostname }}.html"
        dest: "reports/compliance/"
        flat: true

See also: Ansible splunk.es Collection: Automating Security Incident Response Workflows

Security Event Response Workflows

Automated Response to Failed Login Attempts

---
- name: Respond to brute force attacks
  hosts: all
  become: true
  tasks:
    - name: Get failed login attempts (last hour)
      ansible.builtin.shell: |
        journalctl -u sshd --since "1 hour ago" |
        grep "Failed password" |
        awk '{print $(NF-3)}' |
        sort | uniq -c | sort -rn |
        awk '$1 >= 10 {print $2}'
      register: brute_force_ips
      changed_when: false

    - name: Block brute force IPs
      ansible.builtin.iptables:
        chain: INPUT
        source: "{{ item }}"
        jump: DROP
        comment: "Auto-blocked: brute force {{ ansible_date_time.iso8601 }}"
      loop: "{{ brute_force_ips.stdout_lines }}"
      when: brute_force_ips.stdout_lines | length > 0

    - name: Report blocked IPs
      ansible.builtin.debug:
        msg: "Blocked {{ brute_force_ips.stdout_lines | length }} IPs for brute force on {{ inventory_hostname }}"
      when: brute_force_ips.stdout_lines | length > 0

FAQ

How does Ansible compare to SOAR platforms like Phantom or XSOAR?

SOAR platforms provide visual playbook builders, case management, and SIEM integration out of the box. Ansible is more flexible and cheaper — it automates the actual remediation actions that SOAR platforms trigger. Many organizations use both: SOAR for orchestration and case management, Ansible for execution.

Can Ansible replace a SIEM?

No. Ansible deploys and configures SIEM agents, collects forensic data, and executes remediation actions. But SIEMs (Splunk, ELK, QRadar) handle log aggregation, correlation, alerting, and investigation — capabilities Ansible doesn't provide.

How fast can Ansible respond to incidents?

With pre-built playbooks and AAP webhooks, Ansible can execute containment actions within 30-60 seconds of detection. The limiting factor is usually detection speed (SIEM alert latency), not execution speed.

Is it safe to automate incident response?

Start with low-risk automations (data collection, reporting) before automating containment actions (blocking IPs, disabling accounts). Always include manual approval gates for destructive actions in production environments.

See also: New Ansible Content Collections 2026: Cloud, Networking, Security, Observability, and Windows

Conclusion

Ansible bridges the gap between security detection and response. Deploy SIEM agents consistently, collect forensic data at scale, block IOCs across your entire infrastructure in seconds, and enforce compliance baselines automatically. Start with forensic collection and SIEM agent deployment — they're high-value, low-risk automation targets.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home