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 SOC | Automated with Ansible | |-----------|----------------------| | SSH into each host to block IP | Block IP on all firewalls in 10 seconds | | Manually collect logs for investigation | Gather forensic data from 500 hosts in parallel | | Update SIEM agents one by one | Push config to all agents simultaneously | | Hours to contain an incident | Minutes from detection to containment | | Inconsistent hardening | Identical baseline across all systems |

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

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

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

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

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

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

See also: Ansible for AI Security: Protect Models, APIs & Data Pipelines (2026 Guide)

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.

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.

Related Articles

Ansible Vault Deep DiveAnsible for Linux System AdministrationAnsible Cloud AutomationAnsible Error Handling GuideManaging Compliance Drift with AnsibleInstalling and Enabling SELinux with Ansible on RHEL 8

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home