Git ve CI/CD ile Kod Olarak Algılama İşlem Hattı
2025 yılında sadece Güvenlik ekiplerinin %35'i kullanır Profesyonellerin %63'üne rağmen sistematik olarak Kod Olarak Algılama düzenli olarak sahiplenmek istediğinizi beyan edersiniz. Niyet ve uygulama arasındaki bu boşluk gerçek bir sorunu ortaya çıkarıyor: çoğu kuruluş bilmiyor gibi tüm döngüyü idare eden sağlam bir DaC boru hattı oluşturun Bir algılama kuralının, oluşturma aşamasından üretimde dağıtım aşamasına kadar olan ömrü.
Kod Olarak Algılama (DaC) mühendislik uygulamalarını uygular yazılımın güvenlik alanına aktarılması: sürüm kontrolü, kod incelemesi, test etme otomatikleştirilmiş, CI/CD ardışık düzeni ve kontrollü dağıtım. Sonuç bir Yeni bir saldırı tekniğinin keşfi arasındaki sürenin büyük ölçüde azaltılması ve kalite kurallarıyla etkili tespitin uygulanması Ölçülebilir ve zamanla geliştirilebilir.
Bu Makalede Neler Öğreneceksiniz?
- DaC deposunun yapısı: dizin düzeni, adlandırma kuralı, şema
- Git iş akışı: dallanma stratejisi, taahhüt kuralı, çekme isteği incelemesi
- GitHub Eylemleri ardışık düzeni: tüy bırakma, doğrulama, test etme, dönüştürme, dağıtma
- Sentetik günlüklerle otomatik test: pozitif ve negatif
- API aracılığıyla Splunk, Elastic ve Sentinel'e güvenli dağıtım
- Otomatik geri alma ve dağıtım sonrası olay yönetimi
- Kalite ölçümleri: kapsam, yanlış pozitif oranı, dağıtım sıklığı
- Tespit takibi için JIRA/GitHub Sorunları ile entegrasyon
çünkü Kod Olarak Algılama Temeldir
DaC'den önce SIEM'deki bir kuralı güncellemeye yönelik tipik süreç şuydu: web konsoluna erişin, kuralı bulun, manuel olarak düzenleyin, kaydedin, umarım hiçbir şeyi bozmaz. Önceki sürüm yok, test yok, hayır akran değerlendirmesi, değişikliklerin izlenebilirliği yok. Bir kural başladığında sabaha karşı 3'te binlerce yanlış pozitif üretmek, bunu anlamak imkansızdı kimin neyi, ne zaman yaptığını.
DaC bu kaotik süreci sistematik bir şeye dönüştürüyor:
- Her kural Git'te sürümlendirilmiş bir metin dosyasıdır
- Her değişiklik, zorunlu incelemeyle birlikte bir çekme talebinden geçer
- Birleştirmeden önce boru hattı sentetik kütükler üzerinde otomatik testler yürütür
- Dağıtım yalnızca tüm testler başarılı olursa gerçekleşir
- Sorun olması durumunda geri alma basit bir konudur
git revert
DaC Deposunun Yapısı
İyi yapılandırılmış bir DaC deposu, diğer her şeyin üzerine inşa edildiği temeldir. Bir kurumsal organizasyon için önerilen düzen aşağıda verilmiştir:
detection-as-code/
├── .github/
│ ├── workflows/
│ │ ├── pr-validation.yml # Validazione su ogni PR
│ │ ├── main-deploy.yml # Deploy su merge in main
│ │ └── nightly-test.yml # Test notturno su staging
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── CODEOWNERS
├── rules/
│ ├── windows/
│ │ ├── credential_access/
│ │ ├── lateral_movement/
│ │ └── persistence/
│ ├── linux/
│ ├── cloud/
│ │ ├── aws/
│ │ ├── azure/
│ │ └── gcp/
│ └── network/
├── tests/
│ ├── fixtures/
│ │ └── windows/
│ │ └── credential_access/
│ │ └── cred_mimikatz_lsass/
│ │ ├── positive/
│ │ └── negative/
│ └── unit/
│ └── test_sigma_rules.py
├── pipelines/
│ ├── splunk_enterprise.yml
│ └── elastic_ecs.yml
├── scripts/
│ ├── validate.py
│ ├── test_runner.py
│ ├── convert.py
│ └── deploy_splunk.py
└── Makefile
Adlandırma Kuralı ve Kurallar Şeması
A coherent and essential naming convention for the navigability of the repository yüzlerce kuralla. Önerilen dosya adı kuralı:
# Pattern: <tactic_prefix>_<technique_name>_<context>.yml
cred_mimikatz_lsass.yml # credential_access
lat_psexec_remote_execution.yml # lateral_movement
per_scheduled_task_creation.yml # persistence
def_timestomp_modification.yml # defense_evasion
exe_powershell_encoded.yml # execution
exf_dns_tunneling.yml # exfiltration
c2_http_beaconing.yml # command_and_control
DaC için Dallanma Stratejisi
# Flusso standard per nuove detection
git checkout -b detection/T1003-lsass-dump-via-procdump
# ... crea/modifica la regola e i test ...
git add rules/windows/credential_access/cred_lsass_procdump.yml
git add tests/fixtures/windows/process_creation/procdump_positive.json
git commit -m "feat(detection): T1003.001 LSASS dump via ProcDump
Adds detection for LSASS memory dump via legitimate ProcDump utility.
ATT&CK: T1003.001 - OS Credential Dumping: LSASS Memory
Severity: high
Test coverage: 3 positive, 2 negative fixtures"
git push origin detection/T1003-lsass-dump-via-procdump
# Flusso hotfix per detection urgenti (attacco in corso)
git checkout -b hotfix/active-incident-lateral-movement-mar2026
git commit -m "hotfix(detection): emergency rule for active APT lateral movement
Active incident response. Incident: INC-2026-0312"
GitHub Eylemleriyle CI/CD Ardışık Düzenini Tamamlayın
# .github/workflows/pr-validation.yml
name: Detection Rule Validation
on:
pull_request:
paths:
- 'rules/**/*.yml'
- 'tests/**'
jobs:
lint-yaml:
name: YAML Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run yamllint
uses: ibiqlik/action-yamllint@v3
with:
file_or_dir: rules/
config_data: |
extends: default
rules:
line-length:
max: 120
validate-schema:
name: Schema Validation
runs-on: ubuntu-latest
needs: lint-yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install pyyaml jsonschema sigma-cli
- name: Validate Sigma schemas
run: |
python scripts/validate.py ./rules \
--schema schemas/sigma_rule_schema.json
- name: Check UUID uniqueness
run: python scripts/check_uuid_uniqueness.py ./rules
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
needs: validate-schema
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install pytest pyyaml sigma-cli pySigma-backend-splunk
- name: Run detection tests
run: |
pytest tests/unit/ \
-v \
--tb=short \
--junit-xml=test-results.xml
convert-validate:
name: Conversion Test
runs-on: ubuntu-latest
needs: unit-tests
strategy:
matrix:
target: [splunk, elasticsearch, microsoft365defender]
steps:
- uses: actions/checkout@v4
- run: |
pip install sigma-cli \
pySigma-backend-splunk \
pySigma-backend-elasticsearch \
pySigma-backend-microsoft365defender
- name: Test conversion to ${{ matrix.target }}
run: |
sigma convert -t ${{ matrix.target }} rules/ \
2>&1 | tee conversion-${{ matrix.target }}.log
# .github/workflows/main-deploy.yml
name: Deploy Detection Rules to Production
on:
push:
branches: [main]
paths: ['rules/**/*.yml']
jobs:
deploy-splunk:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Identify changed rules
id: changed-rules
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'rules/**/*.yml')
echo "files=$CHANGED" >> $GITHUB_OUTPUT
- name: Convert changed rules
run: |
pip install sigma-cli pySigma-backend-splunk
echo "${{ steps.changed-rules.outputs.files }}" | while read rule; do
[ -f "$rule" ] && sigma convert -t splunk -p splunk_windows "$rule" \
>> converted.spl
done
- name: Deploy to Splunk via REST API
env:
SPLUNK_HOST: ${{ secrets.SPLUNK_HOST }}
SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }}
run: |
python scripts/deploy_splunk.py \
--rules-file converted.spl \
--host "$SPLUNK_HOST" \
--token "$SPLUNK_TOKEN" \
--dry-run false
- name: Notify on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'DEPLOY FAILURE: Detection rules deployment failed',
body: 'Run: ' + context.serverUrl + '/' +
context.repo.owner + '/' + context.repo.repo +
'/actions/runs/' + context.runId,
labels: ['incident', 'deployment-failure']
})
Algılama Kuralları için Test Çerçevesi
Test yapmak DaC'nin kalbidir. İşte tam Python test çerçevesi:
#!/usr/bin/env python3
"""Detection Rule Test Framework."""
import json
import yaml
import pytest
import subprocess
from pathlib import Path
from typing import NamedTuple
class TestCase(NamedTuple):
rule_path: Path
fixture_path: Path
should_match: bool
def load_test_cases() -> list[TestCase]:
"""Carica tutti i test case dalla struttura di directory."""
test_cases = []
rules_dir = Path("rules")
fixtures_dir = Path("tests/fixtures")
for rule_file in rules_dir.rglob("*.yml"):
rel_path = rule_file.relative_to(rules_dir)
fixture_dir = fixtures_dir / rel_path.parent / rule_file.stem
if fixture_dir.exists():
for pos_file in (fixture_dir / "positive").glob("*.json"):
test_cases.append(TestCase(rule_file, pos_file, True))
for neg_file in (fixture_dir / "negative").glob("*.json"):
test_cases.append(TestCase(rule_file, neg_file, False))
return test_cases
class TestDetectionRules:
"""Test suite per le detection rules."""
@pytest.mark.parametrize("test_case", load_test_cases())
def test_rule_against_fixture(self, test_case: TestCase):
rule_path, fixture_path, should_match = test_case
with open(fixture_path) as f:
log_event = json.load(f)
# Valuta la regola contro l'evento (implementazione omessa per brevita)
matched = evaluate_sigma_rule(rule_path, log_event)
if should_match:
assert matched, (
f"Rule {rule_path.name} SHOULD match {fixture_path.name} "
f"but did NOT match.\nEvent: {json.dumps(log_event, indent=2)}"
)
else:
assert not matched, (
f"Rule {rule_path.name} should NOT match {fixture_path.name} "
f"but DID match (false positive).\n"
f"Event: {json.dumps(log_event, indent=2)}"
)
def test_no_duplicate_ids(self):
"""Verifica che non ci siano UUID duplicati nel repository."""
seen_ids = {}
duplicates = []
for rule_file in Path("rules").rglob("*.yml"):
with open(rule_file) as f:
rule = yaml.safe_load(f)
rule_id = rule.get('id', '')
if rule_id in seen_ids:
duplicates.append(
f"{rule_file} duplicates ID of {seen_ids[rule_id]}"
)
else:
seen_ids[rule_id] = rule_file
assert not duplicates, "Duplicate IDs:\n" + "\n".join(duplicates)
def test_all_rules_have_tests(self):
"""Verifica che ogni regola abbia almeno un test positivo."""
rules_dir = Path("rules")
fixtures_dir = Path("tests/fixtures")
missing = []
for rule_file in rules_dir.rglob("*.yml"):
rel_path = rule_file.relative_to(rules_dir)
pos_dir = fixtures_dir / rel_path.parent / rule_file.stem / "positive"
if not pos_dir.exists() or not list(pos_dir.glob("*.json")):
missing.append(str(rule_file))
if missing:
pytest.fail(
"Rules missing positive test fixtures:\n" +
"\n".join(f" - {r}" for r in missing)
)
Test Fikstürleri: Sentetik Kütük Örnekleri
# tests/fixtures/windows/credential_access/
# cred_mimikatz_lsass/positive/mimikatz_direct.json
{
"EventID": 10,
"Channel": "Microsoft-Windows-Sysmon/Operational",
"SourceImage": "C:\\Users\\attacker\\Downloads\\mimikatz.exe",
"TargetImage": "C:\\Windows\\System32\\lsass.exe",
"GrantedAccess": "0x1010",
"UtcTime": "2026-03-09 14:30:00.123"
}
# cred_mimikatz_lsass/negative/windows_defender_scan.json
{
"EventID": 10,
"Channel": "Microsoft-Windows-Sysmon/Operational",
"SourceImage": "C:\\Program Files\\Windows Defender\\MsMpEng.exe",
"TargetImage": "C:\\Windows\\System32\\lsass.exe",
"GrantedAccess": "0x1000",
"UtcTime": "2026-03-09 14:31:00.456"
}
DaC kalite ölçümleri
| Metrik | Tanım | Hedef |
|---|---|---|
| Tespit Kapsamı | Kararlı kural kapsamındaki ATT&CK tekniklerinin yüzdesi | > %60 |
| Test Kapsamı | Pozitif ve negatif testlerle % kurallar | %100 |
| Yanlış Pozitif Oranı | FP Uyarıları / Haftalık Toplam Uyarılar | < %10 |
| Dağıtım Sıklığı | Haftalık yeni kurallarla birleştirme | > 3/hafta |
| Tespit Süresi (TTD) | Yayınlanan teknikten konuşlandırılan kurala kadar geçen süre | < 48 saat (yüksek önem derecesi) |
Kaçınılması Gereken Anti-Desenler
- Test etmeden dağıtın: acil durumda bile en az bir manuel duman testi
- Açıkça görülen sırlar: her zaman GitHub Secrets'ı kullanın, asla sabit kod kullanmayın
- Bildirimler olmadan işlem hattı: sessiz ve tehlikeli, başarısız bir dağıtım
- Sahibi olmayan kurallar: Her teknik alan için CODEOWNERS'ı kullanın
- Yalnızca pozitif testler: negatif fikstürler olmadan FP üretip üretmediğinizi bilemezsiniz
Sonuçlar
Kod Olarak Algılama yalnızca bir araç değişikliği değil, aynı zamanda bir zihniyet değişikliğidir: tespitler koddur ve bu nedenle test edilmeli, versiyonlandırılmalı, revize edilmelidir ve sistematik olarak konuşlandırın. Olgun bir DaC boru hattı, Tespit Süresini azaltır, kuralların kalitesini artırır ve algılama programını ölçeklendirmenize olanak tanır Personeli orantılı olarak artırmadan.
Serideki Sonraki Makale
Bir sonraki makalede nasıl entegre edileceğini göreceğiz. GÖNYE ATT&CK Kapsama boşluklarını otomatik olarak haritalamak ve önceliklendirmek için DaC iş akışında gerçek riske dayalı yeni tespitler.







