Mahesh Harripaul
Home Experience Blog Services Contact
← Back to blog
GitHub ActionsCI/CDRules as codeWazuh

CI/CD Pipeline: Managing Detection Rules as Code

June 8, 2026 · Mahesh Harripaul

<60s
Deploy time
3
GitHub secrets
4
Rule files

GitHub Actions · SCP + SSH · /var/ossec/etc/rules/

Every time a rule was updated, the process was: SSH into EC2, open nano, edit the XML, reload Wazuh. No version history. No rollback capability. No way to share cleanly with a team. The fix: treat rules like code. Store them in Git. Deploy automatically when changes are pushed.

Repository structure

wazuh-detection-rules/
├── .github/
│   └── workflows/
│       └── deploy.yml
├── rules/
│   ├── windows_authentication.xml
│   ├── windows_privilege.xml
│   ├── windows_attack_chain.xml
│   └── sysmon_detections.xml
└── README.md

One file per logical category. Each file is a complete XML group with all related rules inside it.

The GitHub Actions workflow

name: Deploy Wazuh Rules

on:
  push:
    branches:
      - main
    paths:
      - 'rules/**.xml'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Copy rules to Wazuh manager
        uses: appleboy/scp-action@v0.1.4
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USER }}
          key: ${{ secrets.EC2_SSH_KEY }}
          source: "rules/*.xml"
          target: "/tmp/wazuh-rules/"
          strip_components: 1

      - name: Deploy and reload
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USER }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            sudo cp /tmp/wazuh-rules/*.xml /var/ossec/etc/rules/
            sudo chown root:wazuh /var/ossec/etc/rules/*.xml
            sudo chmod 660 /var/ossec/etc/rules/*.xml
            sudo systemctl reload wazuh-manager

GitHub secrets

Three secrets stored in GitHub — never in code:

SecretValue
EC2_HOSTEC2 public IP — update this when EC2 restarts
EC2_USERubuntu
EC2_SSH_KEYContents of the .pem key file

The local_rules.xml placeholder problem

After migrating all rules to separate files, local_rules.xml was left empty. Wazuh requires at least one valid rule in every file it reads. An empty group fails validation.

<group name="local,">
  <rule id="199999" level="0">
    <match>placeholder</match>
    <description>Placeholder — all active rules are in separate files</description>
  </rule>
</group>

Verification after deployment

sudo grep -r "rule id" /var/ossec/etc/rules/ | grep "100"

This shows all custom rules (100000+) and which file they loaded from.

The result

Edit a rule in VS Code → commit → push → GitHub Actions deploys in under 60 seconds → Wazuh reloads → new rules are live. No SSH required. Full version history. The same workflow mature SOC teams use to manage detection rules at scale.

Previous: Installing SysmonNext: Gap Analysis All posts →