Übersicht
In diesem Leitfaden wird die End-to-End-Bereitstellung des Elastic Stack (Elasticsearch und Kibana) auf einem freigegebenen Cluster von Google Distributed Cloud (GDC) mit Air Gap beschrieben. Außerdem wird gezeigt, wie Sie ihn in einen LLM-Dienst (Large Language Model) einbinden, um die generativen KI-Funktionen von Elastic zu bewerten.
Für die Bereitstellung wird der offizielle Elastic Cloud on Kubernetes (ECK)-Operator verwendet, der im GDC mit Air Gap Marketplace verfügbar ist. Der Operator wird in einem Projekt-Namespace auf einem freigegebenen Kubernetes-Cluster installiert und automatisiert die Bereitstellung und das Lebenszyklusmanagement von Elasticsearch- und Kibana-Ressourcen. Nach der Bereitstellung stellt Kibana eine Verbindung zu einem LLM-Inferenzendpunkt her (z. B. verwaltetes Gemini auf GDC oder ein selbstverwalteter OpenAI-kompatibler Dienst wie Ollama oder vLLM). Diese Integration unterstützt die generativen KI-Funktionen von Elastic, einschließlich des Elastic AI Agent, benutzerdefinierter Agenten, die mit Agent Builder erstellt wurden, und Attack Discovery.
Dieser Leitfaden wurde für Elastic v9.4.0, den Elastic Kubernetes Operator v3.4.0 und GDC v1.16.2 geschrieben. Einige Anleitungen können sich geringfügig unterscheiden, wenn Sie andere Versionen verwenden.
Architektur
Die Architektur besteht aus einer Elastic Stack-Bereitstellung, die vom ECK-Operator in einem Projekt-Namespace auf einem freigegebenen GDC-Nutzercluster verwaltet wird. Kibana kommuniziert über das interne GDC-Netzwerk mit einem LLM-Inferenzendpunkt.

Zu den wichtigsten Komponenten dieser Architektur gehören:
- Gemeinsam genutzter GDC-Cluster: Ein auf Organisationsebene gemeinsam genutzter Kubernetes-Cluster, der mit mehreren Projekten verbunden ist und GDC Marketplace-Softwarepakete und Anwendungsworkloads hostet.
- GDC-Projekt: Der Projekt-Namespace im freigegebenen Cluster, der den ECK-Operator, den Elasticsearch-Cluster, die Kibana-Instanz und die zugehörigen Kubernetes-Secrets und NetworkPolicies isoliert.
- Elastic Cloud on Kubernetes (ECK)-Operator: Der Operator wird vom GDC Marketplace im Projekt-Namespace installiert und verwaltet die benutzerdefinierten Ressourcen
ElasticsearchundKibana. Außerdem gleicht er die Elastic-Lizenz ab, die für generative KI-Funktionen und externe LLM-Connectors erforderlich ist. - Elasticsearch: Speichert und indexiert Betriebs- und Sicherheitsdaten und führt Such- und ES|QL-Abfragen aus, die von den KI-Funktionen und -Agents von Kibana generiert werden.
- Kibana: Hostet die generativen KI-Funktionen von Elastic, einschließlich des Elastic AI Agent (für die Protokolluntersuchung in natürlicher Sprache und die ES|QL-Generierung), des Agent Builder (zum Erstellen benutzerdefinierter Konversations-Agenten und Tools über Elasticsearch-Daten) und Attack Discovery (für die Korrelation von Sicherheitswarnungen und die Analyse von Angriffsketten). Kibana verwaltet auch die LLM-Aktions-Connectors, die die mehrstufigen Toolaufrufe zwischen dem Nutzer, Elasticsearch und dem LLM-Dienst orchestrieren.
- LLM-Dienst: Ein verwalteter LLM-Dienst (z. B. Gemini on GDC) oder ein selbstverwalteter Inferenzserver (z. B. Ollama oder vLLM), der Kibana über das interne GDC-Netzwerk Chatvervollständigungs- und Toolaufruffunktionen bereitstellt.
Hinweis
Prüfen Sie, ob Ihre GDC-Umgebung die folgenden Voraussetzungen und Annahmen erfüllt, bevor Sie mit der Bereitstellung beginnen:
- Gemeinsam genutzter Kubernetes-Cluster und GDC-Projekt: Sie haben Zugriff auf einen vorhandenen gemeinsam genutzten GDC-Cluster und ein GDC-Projekt, das mit diesem Cluster verknüpft ist. Das Projekt dient als Namespace-Container für alle Kubernetes-Ressourcen, die in dieser Anleitung bereitgestellt werden. Achten Sie darauf, dass der Cluster über genügend Rechen- und nichtflüchtige Speicherressourcen verfügt, um die ECK-Operator-, Elasticsearch- und Kibana-Arbeitslasten zu hosten.
- LLM-Dienst: Sie haben Netzwerkzugriff auf einen LLM-Dienst, entweder den verwalteten Gemini-Dienst (falls in Ihrer GDC-Umgebung verfügbar) oder einen selbstverwalteten OpenAI-kompatiblen LLM-Dienst (z. B.
gemma4:31b, der über Ollama oder vLLM in einem GPU-Projekt bereitgestellt wird). Die Bereitstellung der LLM-Infrastruktur selbst wird in diesem Leitfaden nicht behandelt. Die spezifischen Modell- und API-Anforderungen werden jedoch unter Anforderungen für den LLM-Dienst ausführlich beschrieben. Rufen Sie die Elastic-Version ab, die in Ihrer GDC-Umgebung enthalten ist:
export ELASTIC_VERSION=$(curl -sk "https://harbor.${ORG}.${ZONE}.${GDCH_DOMAIN}/api/v2.0/projects/library/repositories/elasticsearch%252Felasticsearch/artifacts" | jq -r '[.[].tags[]?.name] | sort_by(split(".") | map(tonumber)) | last')Konfigurieren Sie Umgebungsvariablen, auf die in diesem Leitfaden verwiesen wird. Ändern Sie diese Werte nach Bedarf, um sie an Ihre spezifische Umgebung anzupassen:
# GDC environment configuration export PROJECT_ID="your-project-id" export CLUSTER_NAME="your-shared-cluster-name" export ZONE="your-zone-name" export USER_NAME="your-gdc-user-email" # Marketplace package and Elastic Stack configuration export MARKETPLACE_SERVICE_NAME="elastic" # LLM service configuration export LLM_CONNECTOR_NAME="your-llm-connector-name" export LLM_API_URL="http://your-llm-service-host:11434/v1/chat/completions" export LLM_MODEL_NAME="your-llm-model-name" export LLM_API_KEY="your-llm-api-key"Konfigurieren Sie
gdcloud:gdcloud config set project ${PROJECT_ID} gdcloud config set core/zone ${ZONE}Fordern Sie die erforderlichen IAM-Rollen auf Projektebene für Ihren Nutzer im GDC-Zielprojekt (
${PROJECT_ID}) an oder binden Sie sie. Gemäß der Dokumentation zum GDC Marketplace-Lebenszyklus und den GDC-Netzwerkanforderungen sind mindestens die folgenden Projektrollen erforderlich:- Namespace-Administrator (
namespace-admin): Vollständiger Administratorzugriff zum Erstellen und Verwalten von Kubernetes-Arbeitslasten, Secrets, Diensten und benutzerdefinierten Ressourcen im Projekt-Namespace auf dem freigegebenen Cluster. - Projektbetrachter (
project-viewer): Lesezugriff zum Aufrufen des vorhandenen Projekts und seiner Ressourcen in der GDC-Konsole und der Befehlszeile. - Marketplace-Bearbeiter (
marketplace-editor): Berechtigung zum Installieren, Aktualisieren und Deinstallieren von GDC Marketplace-Softwarepaketen im Projekt. - Project NetworkPolicy Admin (
project-networkpolicy-admin): Berechtigung zum Konfigurieren globalerProjectNetworkPolicy-Regeln, die projektübergreifenden und externen Traffic zu den LoadBalancer-Diensten von Kibana und Elasticsearch zulassen.
Bitten Sie Ihren IAM-Admin der Organisation oder IAM-Projektadministrator, diese Rollen zuzuweisen, oder führen Sie die folgenden Befehle aus, wenn Sie IAM-Administratorberechtigungen haben:
gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=namespace-admin gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=project-viewer gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=marketplace-editor gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=project-networkpolicy-admin- Namespace-Administrator (
Rufen Sie die kubeconfig-Datei für den freigegebenen Cluster ab und konfigurieren Sie einen
ku-Shell-Alias fürkubectl:KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \ get-credentials ${CLUSTER_NAME} \ --zone ${ZONE} alias ku="kubectl --kubeconfig=kubeconfig-${CLUSTER_NAME}.yaml"
Elastic Marketplace-Paket installieren
In diesem Abschnitt installieren Sie den ECK-Operator (Elastic Cloud on Kubernetes) aus dem GDC mit Air Gap-Marketplace in Ihrem Projekt-Namespace. Folgen Sie dazu dem GDC Marketplace-Lebenszyklusleitfaden.
Über die gdcloud-Befehlszeile (oder die GDC-Konsole) installieren
Listen Sie die verfügbaren Marketplace-Softwarepakete auf, um den Dienstnamen und die verfügbare Version zu bestätigen:
gdcloud marketplace services listDie Ausgabe sollte in etwa so aussehen:
SERVICE LATEST VERSION confluent <CONFLUENT_VERSION> dataproc <DATAPROC_VERSION> elastic <ECK_OPERATOR_VERSION> mariadb <MARIADB_VERSION> mattermost <MATTERMOST_VERSION> mongodb <MONGODB_VERSION> neo4j <NEO4J_VERSION> redis <REDIS_VERSION> starboard <STARBOARD_VERSION> starburst <STARBURST_VERSION> tes <TES_VERSION> vault <VAULT_VERSION>Installieren Sie das Elastic Marketplace-Paket auf Ihrem freigegebenen Zielcluster:
gdcloud marketplace services install ${MARKETPLACE_SERVICE_NAME} \ --cluster=${CLUSTER_NAME} \ --zone=${ZONE} \ --project ${PROJECT_ID}*(Alternativ können Sie in der GDC-Konsole Ihr Projekt
${PROJECT_ID}auswählen, zu Marketplace gehen, den Eintrag Elastic Cloud on Kubernetes auswählen, auf Installieren klicken, den Cluster${CLUSTER_NAME}auswählen und auf Installieren klicken.)*Prüfen Sie, ob das StatefulSet
elastic-operatorund der Pod in Ihrem Projekt-Namespace (${PROJECT_ID}) ausgeführt werden:ku get statefulset,pods -n ${PROJECT_ID}Die Ausgabe sollte in etwa so aussehen:
NAME READY AGE statefulset.apps/elastic-operator 1/1 3m NAME READY STATUS RESTARTS AGE pod/elastic-operator-0 1/1 Running 0 3m
Elastic Stack bereitstellen
Elastic Stack-Manifest erstellen
Das GDC Marketplace-Paket stellt den ECK-Operator bereit, der so vorkonfiguriert ist, dass er Elasticsearch- und Kibana-Container-Images aus der lokalen Harbor-Registry mit Air Gap abruft.
Erstellen Sie elastic-stack.yaml, um einen Elasticsearch-Cluster mit einem Knoten, eine Kibana-UI-Instanz, LoadBalancer-HTTP-Dienste und eine allow-all NetworkPolicy in Ihrem Projekt-Namespace (${PROJECT_ID}) bereitzustellen. Das Manifest enthält auch eine Lizenz Secret, die vom ECK-Operator abgeglichen wird. Diese ist hier als 30-tägige Enterprise-Testversion (eck-trial-license) konfiguriert, falls Sie noch keine eigene Enterprise-Lizenz haben:
cat <<EOF > elastic-stack.yaml
apiVersion: v1
kind: Secret
metadata:
name: eck-trial-license
namespace: ${PROJECT_ID}
labels:
license.k8s.elastic.co/type: enterprise_trial
annotations:
elastic.co/eula: accepted
---
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elastic-cluster
namespace: ${PROJECT_ID}
spec:
version: ${ELASTIC_VERSION}
http:
service:
spec:
type: LoadBalancer
nodeSets:
- name: default
count: 1
config:
# Disable mmap to avoid requiring privileged host sysctl modifications
node.store.allow_mmap: false
podTemplate:
spec:
initContainers:
- name: sysctl
securityContext:
privileged: false
allowPrivilegeEscalation: false
runAsNonRoot: true
capabilities:
drop:
- ALL
command: ["sh", "-c", "true"]
containers:
- name: elasticsearch
resources:
requests:
memory: 2Gi
cpu: 500m
limits:
memory: 4Gi
cpu: 2
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: kibana-ui
namespace: ${PROJECT_ID}
spec:
version: ${ELASTIC_VERSION}
count: 1
elasticsearchRef:
name: elastic-cluster
http:
service:
spec:
type: LoadBalancer
podTemplate:
spec:
containers:
- name: kibana
resources:
requests:
memory: 1Gi
cpu: 200m
limits:
memory: 2Gi
cpu: 1
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
namespace: ${PROJECT_ID}
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 0.0.0.0/0
EOF
Deployment anwenden und prüfen
Wenden Sie das Manifest an:
ku apply -f elastic-stack.yaml
Wenden Sie eine globale ProjectNetworkPolicy an, damit GDC-Firewallregeln eingehenden Traffic zu den LoadBalancer-IP-Adressen sowie projektübergreifenden Traffic (z. B. Kommunikation mit dem LLM-Dienst) zulassen:
kubectl --kubeconfig=kubeconfig-global.yaml apply -f - <<EOF
apiVersion: networking.global.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
namespace: ${PROJECT_ID}
name: allow-inbound-traffic-from-external
spec:
policyType: Ingress
subject:
subjectType: UserWorkload
ingress:
- from:
- ipBlock:
cidr: 0.0.0.0/0
---
apiVersion: networking.global.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
namespace: ${PROJECT_ID}
name: allow-inbound-traffic-from-all-projects
spec:
policyType: Ingress
subject:
subjectType: UserWorkload
ingress:
- from:
- projects: {}
EOF
Überwachen Sie die Pods, Dienste und benutzerdefinierten Ressourcen, bis sowohl Elasticsearch als auch Kibana den Status Running und Ready erreichen und LoadBalancer-IP-Adressen auf ${CLUSTER_NAME} erhalten:
ku get pods,svc,elasticsearch,kibana -n ${PROJECT_ID}
Sobald die Ressourcen bereit sind, sollte die Ausgabe in etwa so aussehen:
NAME READY STATUS RESTARTS AGE
pod/elastic-cluster-es-default-0 1/1 Running 0 3m
pod/elastic-operator-0 1/1 Running 0 15m
pod/kibana-ui-kb-869844478d-59ptw 1/1 Running 0 3m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/elastic-cluster-es-default ClusterIP None <none> 9200/TCP 11m
service/elastic-cluster-es-http LoadBalancer 10.101.18.181 <ELASTIC_EXTERNAL_IP> 9200:32159/TCP 11m
service/elastic-cluster-es-internal-http ClusterIP 10.101.18.81 <none> 9200/TCP 11m
service/elastic-cluster-es-transport ClusterIP None <none> 9300/TCP 11m
service/g-svc-g-fre-elastic-cluster-es-http-shared-clus-extern-56d5eb67 ClusterIP None <none> 9200/TCP 11m
service/g-svc-g-fre-kibana-ui-kb-http-shared-cluster-0b-extern-75a78b1f ClusterIP None <none> 5601/TCP 11m
service/kibana-ui-kb-http LoadBalancer 10.101.19.86 <KIBANA_EXTERNAL_IP> 5601:32735/TCP 11m
NAME HEALTH NODES VERSION PHASE AGE
elasticsearch.elasticsearch.k8s.elastic.co/elastic-cluster green 1 <ELASTIC_VERSION> Ready 3m
NAME HEALTH NODES VERSION AGE
kibana.kibana.k8s.elastic.co/kibana-ui green 1 <ELASTIC_VERSION> 3m
Exportieren Sie die externen LoadBalancer-IP-Adressen, die Elasticsearch und Kibana zugewiesen sind, zur Verwendung in den folgenden Schritten:
export ELASTICSEARCH_IP=$(ku get svc elastic-cluster-es-http \
-n ${PROJECT_ID} \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export KIBANA_IP=$(ku get svc kibana-ui-kb-http \
-n ${PROJECT_ID} \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Kibana External URL: https://${KIBANA_IP}:5601"
echo "Elasticsearch External URL: https://${ELASTICSEARCH_IP}:9200"
Anmeldedaten abrufen und auf die Kibana-Benutzeroberfläche zugreifen
elastic-Superuser-Passwort abrufen
ECK generiert automatisch ein Kubernetes-Secret (elastic-cluster-es-elastic-user), das das Standard-Superuser-Passwort elastic enthält. Rufen Sie sie ab und decodieren Sie sie mit:
export ELASTIC_PASSWORD=$(ku get secret elastic-cluster-es-elastic-user \
-n ${PROJECT_ID} \
-o jsonpath='{.data.elastic}' | base64 -d)
echo "${ELASTIC_PASSWORD}"
Verbindung prüfen und anmelden
Prüfen Sie, ob Elasticsearch von Ihrer Workstation aus über HTTPS erreichbar ist:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" "https://${ELASTICSEARCH_IP}:9200"Öffnen Sie
https://${KIBANA_IP}:5601in Ihrem Browser, akzeptieren Sie die Warnung zum selbst signierten Zertifikat und melden Sie sich mit folgenden Anmeldedaten an:- Nutzername:
elastic - Passwort:
<output from ELASTIC_PASSWORD above>
- Nutzername:
Elastic-Lizenz prüfen
Für die generativen KI-Funktionen von Elastic (einschließlich Elastic AI Agent, Agent Builder und Attack Discovery) und externe LLM-Connectors ist eine Enterprise-Lizenz (oder eine aktive 30-tägige Enterprise-Testlizenz) erforderlich.
Wenn ein Elasticsearch-Cluster vom ECK-Operator verwaltet wird, gleicht der license-controller von ECK die Clusterlizenz kontinuierlich mit Kubernetes-Secrets im Operator-Namespace (${PROJECT_ID}) ab. Wenn Sie noch keine Enterprise-Lizenz für die Produktion haben, weist das in elastic-stack.yaml (license.k8s.elastic.co/type:
enterprise_trial) enthaltene Secret eck-trial-license ECK an, automatisch eine 30-tägige Enterprise-Testlizenz bereitzustellen und zu verwalten. (Hinweis: Wenn Sie einen Testzeitraum manuell über POST
/_license/start_trial ohne ein ECK-Lizenz-Secret starten, wird der Cluster im nächsten Abgleichszyklus von ECK auf basic zurückgesetzt.)
So prüfen Sie die aktive Lizenz über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
"https://${ELASTICSEARCH_IP}:9200/_license" | jq .
*(Alternativ können Sie in Kibana das Navigationsmenü öffnen und zu Management > Dev Tools gehen und dann auf dem Tab „Console“ GET /_license ausführen.)*
Die Ausgabe sollte in etwa so aussehen und "status": "active" und "type": "enterprise" (oder "type": "trial", wenn Sie die Testlizenz verwenden) enthalten:
{
"license": {
"status": "active",
"uid": "d8c2b566-8c2b-436c-a1ea-5502d6790505",
"type": "trial",
"issue_date": "2026-09-17T23:19:25.053Z",
"issue_date_in_millis": 1789687165053,
"expiry_date": "2026-10-17T23:19:25.053Z",
"expiry_date_in_millis": 1792279165053,
"max_nodes": 1000,
"max_resource_units": null,
"issued_to": "elastic-cluster",
"issuer": "elasticsearch",
"start_date_in_millis": -1
}
}
Integriertes Beispiel-Dataset laden
Wenn Sie die KI-Funktionen von Elastic bewerten möchten, ohne benutzerdefinierte Pipelines für die Datenaufnahme zu schreiben oder externen Internetzugriff zu benötigen, können Sie das in Kibana integrierte Beispiel-Webprotokoll-Dataset (kibana_sample_data_logs) laden. Da das Beispieldatenarchiv im Kibana-Container-Image enthalten ist, wird es in einer Air-Gap-Umgebung in Sekundenschnelle installiert. Das Dataset enthält 14.074 Webzugriffs-Logdokumente mit Client-IP-Adressen (clientip), HTTP-Statuscodes (response), Quell- und Zielländern (geo.src, geo.dest), übertragenen Byte (bytes), URLs und User-Agent-Strings.
Weitere integrierte Datasets (flights und ecommerce) finden Sie unter Beispieldaten in Kibana hinzufügen und elastic-datasets-builtin.md.
Dataset laden
Führen Sie den folgenden Befehl aus, um kibana_sample_data_logs über den internen Beispieldatenendpunkt von Kibana zu laden:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
-X POST "https://${KIBANA_IP}:5601/api/sample_data/logs" \
-H "kbn-xsrf: true" \
-H "x-elastic-internal-origin: Kibana"
Beispiel-Dataset prüfen
Prüfen Sie, ob das Beispiel-Dataset logs in Kibana als installed markiert ist, und bestätigen Sie, dass der zugrunde liegende Datenstream 14,074 Dokumente in Elasticsearch enthält:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
"https://${KIBANA_IP}:5601/api/sample_data" \
-H "kbn-xsrf: true" \
-H "x-elastic-internal-origin: Kibana" \
| jq '.[] | select(.id == "logs") | {id, name, status}'
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
"https://${ELASTICSEARCH_IP}:9200/_cat/indices/kibana_sample_data_logs*?v"
Die Ausgabe sollte in etwa so aussehen:
{
"id": "logs",
"name": "Sample web logs",
"status": "installed"
}
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open .ds-kibana_sample_data_logs-2026.09.22-000001 0YivG3oFQQmb-mYqmULr_g 1 1 14074 0 8.7mb 8.7mb 8.7mb
Anforderungen an den LLM-Dienst
In einer GDC-Umgebung mit Air Gap sind in der Cloud gehostete Elastic Managed LLMs und externe öffentliche SaaS-LLM-Anbieter nicht erreichbar. Je nach GDC-Umgebung:
- Verwaltetes Gemini in GDC: In GDC-Umgebungen, die Gemini als verwalteten LLM-Dienst anbieten, können Sie Kibana direkt mit dem verwalteten Gemini-Dienst verbinden, sofern verfügbar.
- Selbstverwalteter LLM-Dienst: Alternativ können Sie Elastic mit einem selbstverwalteten LLM-Dienst verbinden, der in Ihrer GDC-Umgebung gehostet wird (z. B. auf GDC-GPU-Knoten).
Die Bereitstellung eines selbstverwalteten LLM-Dienstes wird in diesem Leitfaden nicht behandelt. Wenn Sie einen selbstverwalteten LLM-Dienst für Elastic bereitstellen oder auswählen, achten Sie darauf, dass er die Anforderungen erfüllt, die sich aus den offiziellen Leitfäden von Elastic ergeben:
- Zugriff auf LLMs konfigurieren
- Selbstverwaltete benutzerdefinierte LLMs (siehe auch Verbindung zu vLLM in Umgebungen mit Air Gap herstellen)
- Beobachtbarkeit von LLMs und agentischer KI
Zusammenfassung der technischen Anforderungen
Die folgenden Punkte fassen die wichtigsten Anforderungen an API, Modellfunktionen, Kontextfenster und Laufzeit zusammen, die für einen selbstverwalteten LLM-Dienst erforderlich sind, damit er zuverlässig mit dem KI-Agenten, dem Agent Builder und der Attack Discovery von Elastic funktioniert. Die in den folgenden Abschnitten genannten spezifischen Konfigurationsparameternamen (z. B. num_ctx, num_predict, repeat_penalty, repeat_last_n, OLLAMA_FLASH_ATTENTION und OLLAMA_NUM_PARALLEL) werden am Beispiel von Ollama angegeben. Wenden Sie die entsprechenden Einstellungen an, wenn Sie eine andere Inferenz-Engine wie vLLM verwenden.
- OpenAI-kompatible Chat-Vervollständigungs-API (
/v1/chat/completions) mit nativen Funktionsaufrufen:- Jeder selbstverwaltete Inferenzserver (z. B. Ollama oder vLLM), der einen OpenAI-kompatiblen
/v1/chat/completions-Endpunkt (einschließlich Server-Sent Events-Streaming über"stream": true) bereitstellt, kann über den OpenAI-Connector von Kibana eingebunden werden. Der Anbieter muss dabei auf Other (OpenAI Compatible Service) festgelegt werden. - Aktivieren Sie native Funktionsaufrufe (
"enableNativeFunctionCalling": true) für den Kibana-Connector, wenn Sie Modelle verwenden, die cloudnative Toolaufrufe unterstützen (z. B.gemma4:31b). Standardmäßig ("enableNativeFunctionCalling": false) verwendet Kibana promptbasierte simulierte Funktionsaufrufe, die bei verschachtelten Toolaufrufen weniger zuverlässig sind und mit Parsing-Fehlern (z. B.Error: Missing name for tool use) fehlschlagen können. Wenn Sie native Funktionsaufrufe aktivieren, wird die Formatierung von Toolaufrufen direkt an das OpenAI-tools-Protokoll des Inferenzservers delegiert.
- Jeder selbstverwaltete Inferenzserver (z. B. Ollama oder vLLM), der einen OpenAI-kompatiblen
- Anweisungsoptimiertes Modell mit nativen Tool- und Funktionsaufruffunktionen:
- Der Elastic KI-Agent (
elastic-ai-agent) und benutzerdefinierte Agent Builder-Agenten nutzen mehrstufige Toolaufrufe (platform.core.list_indices,platform.core.get_index_mapping,platform.core.search,platform.core.execute_esqlundplatform.core.cases). Sie verwenden diese Tools, um Indexzuordnungen zu ermitteln, ES|QL-Abfragen für Elasticsearch zu generieren und auszuführen und Ergebnisse zusammenzufassen. - Das ausgewählte Modell muss anweisungsoptimiert sein und in der Lage sein, gültige Aufrufe von cloudnativen Tools, strukturierte JSON-Ausgaben und ES|QL-Abfragen zu generieren. Informationen zu den Kriterien für die Modellbewertung finden Sie in der LLM-Leistungsmatrix für Observability und der LLM-Leistungsmatrix für Elastic Security von Elastic.
- Der Elastic KI-Agent (
- Kontextfenster von mindestens
128,000Tokens (z. B.num_ctx: 131072in Ollama):- In der allgemeinen Dokumentation zu selbstverwalteten benutzerdefinierten LLMs von Elastic wird ein Minimum von 64.000 Tokens angegeben. Für den Elastic KI-Agent (
elastic-ai-agent) wird jedoch dringend ein Kontextfenster von 128.000 Tokens (131,072Tokens) empfohlen. - Bei mehrstufigen Untersuchungen kombiniert der Agent Systemanweisungen und Tooldefinitionen mit Indexschemas, ES|QL-Dokumentation und Rohsuchergebnissen (z. B. Abrufen von bis zu 100 Beispieldokumenten, um Feldwerte vor der Aggregation zu prüfen). Eine einzelne Prüfung kann mehr als 70.000 Tokens im Unterhaltungsverlauf umfassen. Bei einem Kontextfenster mit 64.000 Tokens wird der Prompt dann mitten in der Unterhaltung abgeschnitten.
- Beachten Sie, dass in Ollama eine
PARAMETER num_ctx-Anweisung, die in dieModelfileeines Modells eingebettet ist, die UmgebungsvariableOLLAMA_CONTEXT_LENGTHdes Containers überschreibt. Achten Sie darauf, dass sowohlOLLAMA_CONTEXT_LENGTH=131072als auchPARAMETER num_ctx 131072in derModelfiledes Modells konfiguriert sind. Auf einer NVIDIA A100- oder H100-GPU mit 80 GB passtgemma4:31bbei einem Kontext von128Kproblemlos in den VRAM.
- In der allgemeinen Dokumentation zu selbstverwalteten benutzerdefinierten LLMs von Elastic wird ein Minimum von 64.000 Tokens angegeben. Für den Elastic KI-Agent (
- Tokenausgabelimit und mäßige Wiederholungsstrafe (z. B.
num_predict: 8192undrepeat_penalty: 1.05in Ollama):- Der OpenAI-Stream-Adapter von Kibana behandelt
"finish_reason": "length"als schwerwiegendenToken limit reached-Fehler und sendet"temperature": 0(Greedy-Decodierung) in jeder Anfrage. - Konfigurieren Sie für Modelle mit logischen Fähigkeiten (z. B.
gemma4:31b, das interne Denk-Tokens generiert, bevor es Toolaufrufe ausgibt) ein Tokenausgabelimit von mindestens8,192Tokens und eine milde Wiederholungsstrafe. Legen Sie in Ollama beispielsweisenum_predict: 8192,repeat_penalty: 1.05undrepeat_last_n: 64fest. Vermeiden Sie zu aggressive Strafen für Wiederholungen (z. B.1.15+über große Fenster), da das Modell sonst bestraft wird, wenn es eine ES|QL-Abfrage aus seinem internen Reasoning-Block in das endgültige Toolaufruf-JSON kopiert.
- Der OpenAI-Stream-Adapter von Kibana behandelt
- GPU-Beschleunigung, Flash Attention und parallele KV-Cache-Slots (< 60 Sekunden pro Runde):
- Der OpenAI-Connector von Kibana erzwingt ein standardmäßiges HTTP-Zeitlimit von 60 Sekunden pro Streaming-Turn.
- Da ein einzelner Agenten-Turn verschachtelte LLM-Unteraufrufe auslösen kann (z. B. um Suchanfragen in natürlicher Sprache in ES|QL-Abfragen zu übersetzen, während die Hauptunterhaltung des Agenten aktiv ist), kann das Ausführen eines Inferenzservers mit nur einem KV-Cache-Slot dazu führen, dass Unteraufrufe den im Cache gespeicherten Kontext der Hauptunterhaltung entfernen und nachfolgende Turns verlangsamen.
- Legen Sie in Ollama
OLLAMA_FLASH_ATTENTION=1undOLLAMA_NUM_PARALLEL=2fest, damit Flash Attention die Auswertung langer Kontexte beschleunigt und die Hauptunterhaltung und verschachtelte Unteraufrufe separate KV-Cache-Slots im GPU-Speicher beibehalten.
LLM-Connector in Kibana konfigurieren
Sobald Ihr OpenAI-kompatibler LLM-Dienst ausgeführt wird und vom Kibana-Pod aus erreichbar ist, konfigurieren Sie einen OpenAI-Connector in Kibana entweder über die Befehlszeile oder die Kibana-Benutzeroberfläche.
Option 1: Connector über die Befehlszeile erstellen
Führen Sie den folgenden
POST /api/actions/connector-Befehl aus, um einen OpenAI-Connector (.gen-ai) zu erstellen, der auf Ihren LLM-Dienst (${LLM_API_URL}) verweist, wobei native Funktionsaufrufe aktiviert sind ("enableNativeFunctionCalling": true). Kibana generiert und weist automatisch eine eindeutige Connector-ID zu:curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/actions/connector" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d "{ \"name\": \"${LLM_CONNECTOR_NAME}\", \"connector_type_id\": \".gen-ai\", \"config\": { \"apiProvider\": \"Other\", \"apiUrl\": \"${LLM_API_URL}\", \"defaultModel\": \"${LLM_MODEL_NAME}\", \"enableNativeFunctionCalling\": true }, \"secrets\": { \"apiKey\": \"${LLM_API_KEY}\" } }" | jq .Prüfen Sie, ob der Connector
${LLM_CONNECTOR_NAME}vorhanden ist und keine Secrets fehlen. Listen Sie dazu die Connectors von Kibana auf und filtern Sie nach Name:curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ "https://${KIBANA_IP}:5601/api/actions/connectors" \ -H "kbn-xsrf: true" \ | jq ".[] | select(.name == \"${LLM_CONNECTOR_NAME}\")"Die Ausgabe sollte in etwa so aussehen:
{ "id": "<GENERATED_CONNECTOR_ID>", "name": "<LLM_CONNECTOR_NAME>", "config": { "apiProvider": "Other", "apiUrl": "<LLM_API_URL>", "defaultModel": "<LLM_MODEL_NAME>", "enableNativeFunctionCalling": true }, "connector_type_id": ".gen-ai", "is_preconfigured": false, "is_deprecated": false, "referenced_by_count": 0, "is_missing_secrets": false, "is_system_action": false }Wenn Sie die Live-End-to-End-Konnektivität zwischen Kibana und dem LLM-Dienst über die Befehlszeile testen möchten, suchen Sie die automatisch generierte Connector-ID anhand des Namens und rufen Sie den zugehörigen
_execute-Endpunkt auf:export CONNECTOR_ID=$(curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ "https://${KIBANA_IP}:5601/api/actions/connectors" \ -H "kbn-xsrf: true" \ | jq -r ".[] | select(.name == \"${LLM_CONNECTOR_NAME}\") | .id") curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/actions/connector/${CONNECTOR_ID}/_execute" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d "{ \"params\": { \"subAction\": \"invokeAI\", \"subActionParams\": { \"model\": \"${LLM_MODEL_NAME}\", \"messages\": [ { \"role\": \"user\", \"content\": \"Reply with the single word Pong.\" } ] } } }" | jq .Die Ausgabe sollte in etwa so aussehen und
"status": "ok"sowie die Antwort des Modells enthalten:{ "status": "ok", "data": { "message": "Pong", "usage": { "prompt_tokens": 23, "prompt_tokens_details": { "cached_tokens": 0 }, "completion_tokens": 38, "total_tokens": 61 } }, "connector_id": "<GENERATED_CONNECTOR_ID>" }
Option 2: Connector über die Kibana-Benutzeroberfläche erstellen
- Melden Sie sich in Kibana (
https://${KIBANA_IP}:5601) an. - Öffnen Sie das Hauptnavigationsmenü und rufen Sie Verwaltung > Benachrichtigungen und Statistiken > Connectors auf.
- Klicken Sie auf Connector erstellen und wählen Sie OpenAI aus.
- Konfigurieren Sie die Connector-Felder:
- Connector-Name: Geben Sie den Wert von
${LLM_CONNECTOR_NAME}ein (z. B.Gemma4-31B). - OpenAI-Anbieter auswählen: Wählen Sie Sonstiger (OpenAI-kompatibler Dienst) aus.
- URL: Geben Sie den Wert von
${LLM_API_URL}(den/v1/chat/completions-Endpunkt Ihres LLM-Dienstes) ein. - Standardmodell: Geben Sie den Wert von
${LLM_MODEL_NAME}ein (z. B.gemma4:31b). - API-Schlüssel: Geben Sie den Wert von
${LLM_API_KEY}ein (ein beliebiger nicht leerer String, wenn Ihr Server keine Inhaberauthentifizierung erzwingt, oder der API-Schlüssel Ihres Servers). - Native Funktionsaufrufe aktivieren: Aktivieren Sie den Ein/Aus-Button.
- Connector-Name: Geben Sie den Wert von
- Klicken Sie auf Speichern und testen, um den Connector zu speichern und sofort den Tab Test zu öffnen.
- Geben Sie auf dem Tab Test einen Beispiel-Prompt ein (z. B.
Reply with the single word Pong.) und klicken Sie auf Ausführen, um zu prüfen, ob Kibana eine gültige Antwort vom LLM-Dienst erhält.
LLM-Integrationen testen
Nachdem das Dataset kibana_sample_data_logs installiert und Ihr LLM-Connector verifiziert wurde, können Sie die KI-Funktionen von Elastic in Kibana testen.
Elastic KI-Agent
Der Elastic AI Agent (elastic-ai-agent) ist der standardmäßige Konversations-Agent, der in Kibana integriert ist, um Daten in Elasticsearch mithilfe natürlicher Sprache zu untersuchen und zu analysieren.
Der Agent wird von Ihrem konfigurierten LLM-Connector und den integrierten Agent Builder-Tools unterstützt. Er erkennt automatisch Elasticsearch-Indizes und -Zuordnungen (platform.core.list_indices, platform.core.get_index_mapping), generiert und führt ES|QL-Abfragen aus (platform.core.search, platform.core.execute_esql) und fasst die Ergebnisse zusammen, ohne dass Sie das zugrunde liegende Schema im Voraus kennen müssen. Sie können auch eigene benutzerdefinierte Agenten mit maßgeschneiderten Anweisungen und Tools erstellen. Weitere Informationen finden Sie unter Benutzerdefinierte Agenten mit Agent Builder.
So öffnen und konfigurieren Sie den Elastic KI-Agenten in der Kibana-Benutzeroberfläche:
- Öffnen Sie das Hauptnavigationsmenü in Kibana und wählen Sie KI-Agent aus. Alternativ können Sie in der oberen Kopfzeile auf den Button KI fragen klicken oder direkt zu
https://${KIBANA_IP}:5601/app/chatgehen. - Achten Sie darauf, dass Elastic AI Agent als aktiver Agent und Ihr LLM-Connector (
${LLM_CONNECTOR_NAME}) als Modell-Connector ausgewählt ist.
Beispiel 1: Fehlgeschlagene HTTP-Anfragen und potenzielle Scanner untersuchen
Bitten Sie den Elastic KI-Agent, die wichtigsten Client-IP-Adressen zu identifizieren, die in kibana_sample_data_logs HTTP-Antworten generieren, die nicht 200 sind, ihre Herkunftsländer und ob über eine dieser IP-Adressen auch erfolgreicher HTTP-200-Traffic lief:
Option 1: Über die Kibana-Benutzeroberfläche: Geben Sie die folgende Frage in den Chat-Prompt des KI-Agenten ein:
In kibana_sample_data_logs, which client IP addresses had the most failed HTTP requests (non-200 status codes), what countries did they come from, and did any of those IPs also have successful HTTP 200 requests?Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/converse" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d "{ \"agent_id\": \"elastic-ai-agent\", \"connector_id\": \"${CONNECTOR_ID}\", \"input\": \"In kibana_sample_data_logs, which client IP addresses had the most failed HTTP requests (non-200 status codes), what countries did they come from, and did any of those IPs also have successful HTTP 200 requests?\" }" | jq '{ status: .status, tools_called: [.steps[] | select(.type == "tool_call") | {tool_id: .tool_id, params: .params}], response: .response.message }'
Was passiert hinter den Kulissen:
- Der KI-Agent ruft
platform.core.get_index_mapping(indices=["kibana_sample_data_logs"])auf, um die verfügbaren Felder (clientip,geo.src,response,bytes,requestusw.) zu prüfen. Es ruft
platform.core.searchauf, um Beispieldokumente zu prüfen und zu bestätigen, dass HTTP-Statuscodes inresponsegespeichert sind. Anschließend werden ES|QL-Aggregationen ausgeführt, um Nicht-200-Anfragen nachclientipundgeo.srczu sortieren und zu prüfen, welche der Top-IPs auchresponse == "200"-Traffic verzeichnet haben:FROM kibana_sample_data_logs | WHERE response != "200" | STATS failed_count = COUNT(*) BY clientip, geo.src | SORT failed_count DESC | LIMIT 10FROM kibana_sample_data_logs | WHERE clientip IN ("30.156.16.164", "213.235.30.99", "221.241.228.46", "209.94.234.133", "7.127.73.138", "247.240.202.244", "130.125.65.24", "164.85.94.243", "81.194.200.150", "30.145.143.210") AND response == "200" | STATS success_count = COUNT(*) BY clientip
Die Antwort des Elastic KI-Agenten sollte in etwa so aussehen:
Die Client-IP-Adresse mit den meisten fehlgeschlagenen HTTP-Anfragen (Statuscodes ungleich 200) in
kibana_sample_data_logsist 30.156.16.164. Sie stammt aus den USA und hat 100 fehlgeschlagene Anfragen verzeichnet.Weitere Top-IP-Adressen mit fehlgeschlagenen Anfragen, die ebenfalls aus den USA stammen:
- 213.235.30.99: 6 Fehler
- 221.241.228.46: 6 Fehler
- 209.94.234.133: 6 Fehler
- 7.127.73.138: 5 Fehler
- 247.240.202.244: 5 Fehler
- 130.125.65.24: 5 Fehler
- 164.85.94.243: 4 Fehler
- 81.194.200.150: 4 Fehler
- 30.145.143.210: 4 Fehler
Bei erfolgreichen Anfragen hatten alle oben aufgeführten IP-Adressen mindestens einige erfolgreiche HTTP 200-Antworten, mit Ausnahme von 30.156.16.164, die keine erfolgreichen Anfragen hatte.
Beispiel 2: Trafficvolumen und Nutzlastbyte nach HTTP-Statuscode analysieren
Fragen Sie den Elastic KI-Agent nach der Aufschlüsselung der HTTP-Antwortstatuscodes für alle Anfragen in kibana_sample_data_logs und der Gesamtzahl der übertragenen Byte für jeden Statuscode:
Option 1: Über die Kibana-Benutzeroberfläche: Starten Sie eine neue Unterhaltung im KI-Agenten und geben Sie die folgende Frage ein:
In kibana_sample_data_logs, what is the breakdown of HTTP response status codes across all requests, and how much total data (in bytes) was transferred for each status code?Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/converse" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d "{ \"agent_id\": \"elastic-ai-agent\", \"connector_id\": \"${CONNECTOR_ID}\", \"input\": \"In kibana_sample_data_logs, what is the breakdown of HTTP response status codes across all requests, and how much total data (in bytes) was transferred for each status code?\" }" | jq '{ status: .status, tools_called: [.steps[] | select(.type == "tool_call") | {tool_id: .tool_id, params: .params}], response: .response.message }'
Was passiert hinter den Kulissen:
- Der Agent prüft das Schema
kibana_sample_data_logsüberplatform.core.get_index_mappingund identifiziert die Felderresponse.keywordundbytes. Es wird
platform.core.searchaufgerufen, wodurch die folgende ES|QL-Aggregation generiert und ausgeführt wird:FROM kibana_sample_data_logs | STATS request_count = COUNT(*), total_bytes = SUM(bytes) BY response.keyword | LIMIT 100
Die Antwort des Elastic KI-Agenten sollte in etwa so aussehen:
Die Aufschlüsselung der HTTP-Antwortstatuscodes und der insgesamt übertragenen Daten in
kibana_sample_data_logssieht so aus:
| Statuscode | Anzahl der Anfragen | Übertragene Daten insgesamt (Byte) |
|---|---|---|
| 200 | 12.832 | 75.681.246 |
| 404 | 801 | 4.044.443 |
| 503 | 441 | 0 |
Benutzerdefinierte KI-Agenten mit Agent Builder
Mit dem Agent Builder können Sie benutzerdefinierte KI-Agenten erstellen, die auf bestimmte operative Workflows zugeschnitten sind. Dazu kombinieren Sie benutzerdefinierte Systemanweisungen mit integrierten Tools (wie platform.core.cases, platform.core.execute_esql und platform.core.search) und benutzerdefinierten Tools (esql, index_search, workflow und mcp).
Im folgenden Beispiel wird ein Web Security Incident Responder-Agent erstellt, der direkt mit dem Dataset kibana_sample_data_logs arbeitet. Wenn der Agent einen Prompt in natürlicher Sprache erhält, führt er Folgendes aus:
- Führt ein benutzerdefiniertes ES|QL-Tool (
investigate_suspicious_web_clients) aus, um HTTP-Antworten, die nicht200sind, inkibana_sample_data_logsnach Client-IP zu aggregieren. - Unterscheidet schädliche Ausspäh- und Ausnutzungsaktivitäten (
30.156.16.164) von harmlosen Downloadfehlern. - Ruft ein benutzerdefiniertes Kibana-Workflow-Tool (
create_security_case) auf, um automatisch einen strukturierten Kibana-Sicherheitsfall mit den Ergebnissen und Abhilfemaßnahmen zu öffnen.
Benutzerdefinierte ES|QL- und Fallerstellungstools erstellen
Erstellen Sie ein benutzerdefiniertes
esql-Tool mit dem Nameninvestigate_suspicious_web_clients, daskibana_sample_data_logsnach den wichtigsten Client-IP-Adressen abfragt, die HTTP-Statuscodes ungleich200generieren, zusammen mit ihren Statuscodes, dem Ursprungsland (geo.src), den User Agents (agent) und den angeforderten URLs (request):Option 1: Über die Kibana-Benutzeroberfläche:
- Öffnen Sie in Kibana das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf. Klicken Sie dann auf Alle Tools verwalten (oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/agent_builder/toolsauf) und klicken Sie auf Neues Tool. Konfigurieren Sie die Toolfelder:
- Tool-ID:
investigate_suspicious_web_clients - Typ: ES|QL
- Description:
Finds the top client IP addresses generating non-200 HTTP error responses in kibana_sample_data_logs, returning their error count, status codes, source country, user agents, and requested URL paths. - Labels:
security,logs ES|QL-Abfrage:
FROM kibana_sample_data_logs | WHERE response != "200" | STATS error_count = COUNT(*), status_codes = VALUES(response), country = VALUES(geo.src), user_agents = VALUES(agent), sample_requests = VALUES(request) BY clientip | SORT error_count DESC | LIMIT 5
- Tool-ID:
Klicken Sie auf Speichern.
- Öffnen Sie in Kibana das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf. Klicken Sie dann auf Alle Tools verwalten (oder rufen Sie direkt
Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/tools" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "id": "investigate_suspicious_web_clients", "type": "esql", "description": "Finds the top client IP addresses generating non-200 HTTP error responses in kibana_sample_data_logs, returning their error count, status codes, source country, user agents, and requested URL paths.", "tags": ["security", "logs"], "configuration": { "query": "FROM kibana_sample_data_logs | WHERE response != \"200\" | STATS error_count = COUNT(*), status_codes = VALUES(response), country = VALUES(geo.src), user_agents = VALUES(agent), sample_requests = VALUES(request) BY clientip | SORT error_count DESC | LIMIT 5", "params": {} } }' | jq '{id: .id, type: .type}'
Da das integrierte
platform.core.cases-Tool von Agent Builder schreibgeschützt ist (es wird zum Suchen und Abrufen vorhandener Fälle verwendet), erstellen Sie einen Kibana-Workflow (create-security-case), der den nativencases.createCase-Schritt von Kibana aufruft, und registrieren Sie ihn alsworkflow-Tool mit dem Namencreate_security_case:Option 1: Über die Kibana-Benutzeroberfläche:
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Verwaltung > Workflows auf (oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/workflowsauf) und klicken Sie dann auf Neuen Workflow erstellen. Fügen Sie im YAML-Editor die folgende Workflowdefinition ein und klicken Sie auf Speichern:
version: "1" name: Create Security Case description: Creates a new Kibana Case in Elastic Security enabled: true triggers: - type: manual inputs: - name: title type: string required: true description: Title of the security case - name: description type: string required: true description: Detailed markdown description of the incident findings - name: severity type: string default: high description: Severity of the case (low, medium, high, critical) steps: - name: create_case type: cases.createCase with: title: ${{ inputs.title }} description: ${{ inputs.description }} severity: ${{ inputs.severity }} owner: securitySolution tags: - agent-builder - web-logsKehren Sie zur Seite Tools von Agent Builder zurück (
https://${KIBANA_IP}:5601/app/agent_builder/toolsoder rufen Sie Elasticsearch > Agenten auf und klicken Sie auf Alle Tools verwalten) und klicken Sie auf Neues Tool.Konfigurieren Sie die Felder des Workflow-Tools und klicken Sie auf Speichern:
- Tool-ID:
create_security_case - Typ: Workflow
- Workflow: Wählen Sie Sicherheitsfall erstellen (
create-security-case) aus. - Description:
Creates a new Kibana Case in Elastic Security with a title, markdown description of the incident findings, and severity (low, medium, high, critical). - Labels:
security,cases
- Tool-ID:
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Verwaltung > Workflows auf (oder rufen Sie direkt
Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/workflows" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "workflows": [ { "yaml": "version: \"1\"\nname: Create Security Case\ndescription: Creates a new Kibana Case in Elastic Security\nenabled: true\ntriggers:\n - type: manual\ninputs:\n - name: title\n type: string\n required: true\n description: Title of the security case\n - name: description\n type: string\n required: true\n description: Detailed markdown description of the incident findings\n - name: severity\n type: string\n default: high\n description: Severity of the case (low, medium, high, critical)\nsteps:\n - name: create_case\n type: cases.createCase\n with:\n title: ${{ inputs.title }}\n description: ${{ inputs.description }}\n severity: ${{ inputs.severity }}\n owner: securitySolution\n tags:\n - agent-builder\n - web-logs\n" } ] }' | jq '.created[] | {id: .id, valid: .valid}' curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/tools" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "id": "create_security_case", "type": "workflow", "description": "Creates a new Kibana Case in Elastic Security with a title, markdown description of the incident findings, and severity (low, medium, high, critical).", "tags": ["security", "cases"], "configuration": { "workflow_id": "create-security-case" } }' | jq '{id: .id, type: .type}'
Benutzerdefinierten Incident Responder-Agenten erstellen
Erstellen Sie den KI-Agenten web-security-incident-responder und weisen Sie ihm die Tools investigate_suspicious_web_clients, create_security_case und platform.core.cases zu:
Option 1: Über die Kibana-Benutzeroberfläche:
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf (oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/agent_builder/agentsauf) und klicken Sie dann auf Neuer Agent. Konfigurieren Sie die Agentendetails:
- Agenten-ID:
web-security-incident-responder - Display name (Anzeigename):
Web Security Incident Responder. - Display description (Anzeigenbeschreibung):
Investigates suspicious HTTP error activity in web access logs and opens Kibana Security Cases with the findings. - Labels:
security,incident-response Benutzerdefinierte Anweisungen:
You are an automated Web Security Incident Responder. When asked to investigate suspicious web traffic: 1. Call the `investigate_suspicious_web_clients` tool to inspect the top client IPs generating non-200 HTTP responses in `kibana_sample_data_logs`. 2. Identify any client IP exhibiting malicious reconnaissance or exploitation behavior (such as Nmap scans, WordPress login probing, `/etc/passwd` path traversal, or `/level/15/exec` command execution attempts) versus benign download errors. 3. Call the `create_security_case` tool to open a new Kibana Security Case for the malicious client IP. Set an appropriate `title`, `severity` (`high`), and a well-structured Markdown `description` summarizing the source IP, geolocation, total failed requests, observed attack categories (mapped to MITRE ATT&CK where applicable), sample malicious URLs, and recommended remediation steps. 4. Return a concise summary of your investigation and confirm the created Kibana Case details.Tools: Wählen Sie
investigate_suspicious_web_clients,create_security_caseundplatform.core.casesaus.
- Agenten-ID:
Klicken Sie auf Speichern.
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf (oder rufen Sie direkt
Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/agents" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "id": "web-security-incident-responder", "name": "Web Security Incident Responder", "description": "Investigates suspicious HTTP error activity in web access logs and opens Kibana Security Cases with the findings.", "labels": ["security", "incident-response"], "avatar_color": "#E7664C", "avatar_symbol": "IR", "configuration": { "instructions": "You are an automated Web Security Incident Responder. When asked to investigate suspicious web traffic:\n1. Call the `investigate_suspicious_web_clients` tool to inspect the top client IPs generating non-200 HTTP responses in `kibana_sample_data_logs`.\n2. Identify any client IP exhibiting malicious reconnaissance or exploitation behavior (such as Nmap scans, WordPress login probing, `/etc/passwd` path traversal, or `/level/15/exec` command execution attempts) versus benign download errors.\n3. Call the `create_security_case` tool to open a new Kibana Security Case for the malicious client IP. Set an appropriate `title`, `severity` (`high`), and a well-structured Markdown `description` summarizing the source IP, geolocation, total failed requests, observed attack categories (mapped to MITRE ATT&CK where applicable), sample malicious URLs, and recommended remediation steps.\n4. Return a concise summary of your investigation and confirm the created Kibana Case details.", "tools": [ { "tool_ids": [ "investigate_suspicious_web_clients", "create_security_case", "platform.core.cases" ] } ] } }' | jq '{id: .id, name: .name}'
Agenten ausführen und Kibana-Fall prüfen
Führen Sie eine Unterhaltung mit dem KI-Agenten Web Security Incident Responder:
Option 1: Über die Kibana-Benutzeroberfläche:
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/agent_builderauf. - Wählen Sie in der Agentenauswahl Web Security Incident Responder aus und achten Sie darauf, dass Ihr LLM-Connector (
${LLM_CONNECTOR_NAME}) ausgewählt ist. Geben Sie den folgenden Prompt ein:
Investigate the top client IPs generating HTTP errors in our web logs, identify any attacker performing reconnaissance or exploitation, and open a high-severity Kibana Security Case with your findings.
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Elasticsearch > Agents auf oder rufen Sie direkt
Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/agent_builder/converse" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d "{ \"agent_id\": \"web-security-incident-responder\", \"connector_id\": \"${CONNECTOR_ID}\", \"input\": \"Investigate the top client IPs generating HTTP errors in our web logs, identify any attacker performing reconnaissance or exploitation, and open a high-severity Kibana Security Case with your findings.\" }" | jq '{ status: .status, tools_called: [.steps[] | select(.type == "tool_call") | .tool_id], response: .response.message }'Die Ausgabe sollte in etwa so aussehen:
{ "status": "completed", "tools_called": [ "investigate_suspicious_web_clients", "create_security_case" ], "response": "I have completed the investigation into the web logs. \n\nThe analysis identified client IP **`30.156.16.164`** (located in the US) as a malicious actor. This IP generated 100 failed requests (HTTP 404) exhibiting clear patterns of reconnaissance and exploitation:\n\n* **Reconnaissance:** Extensive probing for WordPress installations and plugins, as well as Nmap scan signatures (e.g., `/nmaplowercheck...`).\n* **Path Traversal:** Attempts to access sensitive system files via `/etc/passwd`.\n* **Remote Command Execution (RCE):** Attempts to execute commands through paths such as `/level/15/exec`.\n* **Application Probing:** Targeting common management interfaces including Tomcat, Axis2, and JMX consoles.\n\nAs a result, I have opened a **high-severity** Kibana Security Case to track this incident:\n\n* **Case ID:** `1f0e00a5-cc89-4f62-b305-f286fae3d70e`\n* **Title:** Malicious Reconnaissance and Exploitation Attempt from 30.156.16.164\n* **Recommended Action:** Immediately block the IP at the firewall/WAF and verify that no unauthorized access was achieved." }
Prüfen Sie den neu erstellten Kibana-Sicherheitsfall:
Option 1: Über die Kibana-Benutzeroberfläche:
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Sicherheit > Fälle auf (oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/security/casesauf). - Klicken Sie auf Malicious Reconnaissance and Exploitation Attempt from 30.156.16.164, um die formatierte Markdown-Zusammenfassung des Vorfalls, die MITRE ATT&CK-Analyse, Beispiele für schädliche URLs und die Checkliste zur Problembehebung aufzurufen.
- Öffnen Sie das Hauptnavigationsmenü und rufen Sie Sicherheit > Fälle auf (oder rufen Sie direkt
Option 2: Über die Befehlszeile:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ "https://${KIBANA_IP}:5601/api/cases/_find" \ -H "kbn-xsrf: true" \ | jq '.cases[0] | {id: .id, title: .title, severity: .severity, status: .status, tags: .tags, description: .description}'Die Ausgabe sollte in etwa so aussehen:
{ "id": "1f0e00a5-cc89-4f62-b305-f286fae3d70e", "title": "Malicious Reconnaissance and Exploitation Attempt from 30.156.16.164", "severity": "high", "status": "open", "tags": [ "agent-builder", "web-logs" ], "description": "### Incident Summary\n**Source IP:** `30.156.16.164`\n**Geolocation:** US\n**Total Failed Requests:** 100\n**Status Codes Observed:** 404\n\n### Analysis\nThe client IP exhibited clear patterns of malicious reconnaissance and exploitation attempts:\n\n- **Reconnaissance (MITRE ATT&CK T1595):** Extensive probing for WordPress installations (`/wp-login.php`, various plugin paths) and Nmap scan signatures (`/nmaplowercheck...`).\n- **Path Traversal (MITRE ATT&CK T1083):** Attempted to access sensitive system files via `/cgi-bin/mj_wwwusr?passw=&list=GLOBAL&user=&func=help&extra=/../../../../../../../../etc/passwd`.\n- **Remote Command Execution (MITRE ATT&CK T1203):** Attempts to execute commands via paths like `/level/15/exec/-/configure/http`.\n- **Application Probing:** Targeted common management interfaces such as `/tomcat/manager/html/`, `/axis2/axis2-admin/`, and `/jmx-console/`.\n\n### Sample Malicious URLs\n- `/cgi-bin/mj_wwwusr?passw=&list=GLOBAL&user=&func=help&extra=/../../../../../../../../etc/passwd`\n- `/level/15/exec/-/configure/http`\n- `/nmaplowercheck1331872976`\n- `/wp-login.php`\n\n### Recommended Remediation\n1. **Block IP:** Immediately block `30.156.16.164` at the network firewall/WAF.\n2. **Log Review:** Verify that all requests from this IP resulted in 404 errors and no unauthorized access was gained.\n3. **Hardening:** Ensure that sensitive directories (e.g., `/cgi-bin/`, `/manager/`) are properly restricted." }
Angriffserkennung
Attack Discovery ist eine KI-Funktion in Elastic Security, die offene Sicherheitswarnungen analysiert, sie dem MITRE ATT&CK-Framework zuordnet und zugehörige Warnungen, IP-Adressen und Nutzerkonten in visuelle Angriffsketten korreliert. Da für Attack Discovery ein großes Modell erforderlich ist, um strukturierte JSON-Ausgaben mit mehreren Benachrichtigungen zuverlässig zu synthetisieren, sollten Sie ein Modell der 30B-Klasse oder ein größeres Modell (z. B. gemma4:31b) verwenden.
Sicherheitswarnungen aus den Beispielprotokollen generieren
Standardmäßig enthält das Dataset kibana_sample_data_logs Rohprotokolle für den Webzugriff und füllt den Elastic Security-Warnungsindex (.alerts-security.alerts-default) nicht aus. Darüber hinaus weist der Beispieldatengenerator von Kibana den 100 Scan- und Exploit-Anfragen von 30.156.16.164 zukünftige @timestamp-Werte (bis zu 30 Tage im Voraus) zu, sodass sie außerhalb des Zeitfensters von now-30d bis now liegen, das von den Elastic Security-Erkennungsregeln abgefragt wird.
Wenn Sie die Angriffserkennung mit den Beispielprotokollen demonstrieren möchten, verschieben Sie die @timestamp der Datensätze von 30.156.16.164 um 30 Tage zurück, reichern Sie sie mit den Elastic Common Schema (ECS)-Feldern source.ip und user.name an und erstellen Sie zwei Erkennungsregeln, die Sicherheitswarnungen aus diesen Ereignissen generieren:
Ordnen Sie
clientipsource.ipzu, legen Sieuser.name(www-data) fest und verschieben Sie@timestampin den30.156.16.164-Einträgen inkibana_sample_data_logs*um 30 Tage zurück:curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${ELASTICSEARCH_IP}:9200/kibana_sample_data_logs*/_update_by_query?conflicts=proceed&refresh=true" \ -H "Content-Type: application/json" \ -d '{ "query": { "term": { "clientip": "30.156.16.164" } }, "script": { "source": "ctx._source.source = [\"ip\": ctx._source.clientip]; ctx._source.user = [\"name\": \"www-data\"]; ctx._source[\"@timestamp\"] = ZonedDateTime.parse(ctx._source[\"@timestamp\"]).minusDays(30).toString();", "lang": "painless" } }' | jq '{updated: .updated, failures: .failures}'Erstellen Sie zwei Elastic Security-Erkennungsregeln für
kibana_sample_data_logs*. Die erste Regel erkennt Nmap- und WordPress-Anmeldeversuche (Reconnaissance) und die zweite Regel erkennt/etc/passwd-Pfaddurchlauf- und Remote-Befehlsausführungsversuche (Initial Access):curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/detection_engine/rules" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "name": "Suspicious Web Reconnaissance and Vulnerability Scanning", "description": "Detects Nmap active scanning and WordPress login/plugin probing in web access logs.", "risk_score": 47, "severity": "medium", "type": "query", "language": "kuery", "query": "clientip: \"30.156.16.164\" and (request: *nmap* or request: *wp-login*)", "index": ["kibana_sample_data_logs*"], "from": "now-30d", "interval": "1h", "max_signals": 2, "enabled": true, "threat": [ { "framework": "MITRE ATT&CK", "tactic": { "id": "TA0043", "name": "Reconnaissance", "reference": "https://attack.mitre.org/tactics/TA0043/" }, "technique": [ { "id": "T1595", "name": "Active Scanning", "reference": "https://attack.mitre.org/techniques/T1595/" } ] } ] }' | jq '{id: .id, name: .name, enabled: .enabled}' curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ -X POST "https://${KIBANA_IP}:5601/api/detection_engine/rules" \ -H "kbn-xsrf: true" \ -H "Content-Type: application/json" \ -d '{ "name": "Web Path Traversal and Remote Command Execution Attempt", "description": "Detects path traversal attempts targeting /etc/passwd and Cisco IOS privilege level 15 remote command execution (/level/15/exec).", "risk_score": 73, "severity": "high", "type": "query", "language": "kuery", "query": "clientip: \"30.156.16.164\" and (request: *passwd* or request: *exec*)", "index": ["kibana_sample_data_logs*"], "from": "now-30d", "interval": "1h", "max_signals": 2, "enabled": true, "threat": [ { "framework": "MITRE ATT&CK", "tactic": { "id": "TA0001", "name": "Initial Access", "reference": "https://attack.mitre.org/tactics/TA0001/" }, "technique": [ { "id": "T1190", "name": "Exploit Public-Facing Application", "reference": "https://attack.mitre.org/techniques/T1190/" } ] } ] }' | jq '{id: .id, name: .name, enabled: .enabled}'Warten Sie etwa 60 Sekunden, bis die erste Regelausführung abgeschlossen ist, und prüfen Sie dann, ob vier Benachrichtigungen in
.alerts-security.alerts-defaultindexiert wurden:curl -sk -u "elastic:${ELASTIC_PASSWORD}" \ "https://${ELASTICSEARCH_IP}:9200/.alerts-security.alerts-default/_search?size=4" \ | jq '.hits.hits[]._source | {rule: .["kibana.alert.rule.name"], source_ip: .source.ip, user_name: .user.name, request: .request}'Die Ausgabe sollte in etwa so aussehen:
{ "rule": "Web Path Traversal and Remote Command Execution Attempt", "source_ip": "30.156.16.164", "user_name": "www-data", "request": "/cgi-bin/mj_wwwusr?passw=&list=GLOBAL&user=&func=help&extra=/../../../../../../../../etc/passwd" } { "rule": "Web Path Traversal and Remote Command Execution Attempt", "source_ip": "30.156.16.164", "user_name": "www-data", "request": "/cgi-bin/mj_wwwusr?passw=&list=GLOBAL&user=&func=help&extra=/../../../../../../../../etc/passwd" } { "rule": "Suspicious Web Reconnaissance and Vulnerability Scanning", "source_ip": "30.156.16.164", "user_name": "www-data", "request": "/nmaplowercheck1331872976" } { "rule": "Suspicious Web Reconnaissance and Vulnerability Scanning", "source_ip": "30.156.16.164", "user_name": "www-data", "request": "/nmaplowercheck1331873003" }
Angriffserkennung ausführen
- Öffnen Sie in Kibana das Hauptnavigationsmenü und rufen Sie Sicherheit > Angriffserkennung auf (oder rufen Sie direkt
https://${KIBANA_IP}:5601/app/security/attack_discoveryauf). - Wählen Sie im Connector-Menü oben auf der Seite Ihren LLM-Connector (
${LLM_CONNECTOR_NAME}) aus. - Klicken Sie auf Generieren, um die offenen Benachrichtigungen in
.alerts-security.alerts-defaultzu analysieren.
Sie können Attack Discovery auch über die Befehlszeile auslösen und prüfen:
export EXECUTION_UUID=$(curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
-X POST "https://${KIBANA_IP}:5601/api/attack_discovery/_generate" \
-H "kbn-xsrf: true" \
-H "elastic-api-version: 2023-10-31" \
-H "Content-Type: application/json" \
-d "{
\"alertsIndexPattern\": \".alerts-security.alerts-default\",
\"anonymizationFields\": [
{\"id\": \"_id\", \"field\": \"_id\", \"allowed\": true},
{\"id\": \"@timestamp\", \"field\": \"@timestamp\", \"allowed\": true},
{\"id\": \"kibana.alert.original_time\", \"field\": \"kibana.alert.original_time\", \"allowed\": true},
{\"id\": \"message\", \"field\": \"message\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.name\", \"field\": \"kibana.alert.rule.name\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.description\", \"field\": \"kibana.alert.rule.description\", \"allowed\": true},
{\"id\": \"kibana.alert.severity\", \"field\": \"kibana.alert.severity\", \"allowed\": true},
{\"id\": \"kibana.alert.risk_score\", \"field\": \"kibana.alert.risk_score\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.threat.tactic.id\", \"field\": \"kibana.alert.rule.threat.tactic.id\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.threat.tactic.name\", \"field\": \"kibana.alert.rule.threat.tactic.name\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.threat.technique.id\", \"field\": \"kibana.alert.rule.threat.technique.id\", \"allowed\": true},
{\"id\": \"kibana.alert.rule.threat.technique.name\", \"field\": \"kibana.alert.rule.threat.technique.name\", \"allowed\": true},
{\"id\": \"source.ip\", \"field\": \"source.ip\", \"allowed\": true},
{\"id\": \"user.name\", \"field\": \"user.name\", \"allowed\": true}
],
\"apiConfig\": {
\"actionTypeId\": \".gen-ai\",
\"connectorId\": \"${CONNECTOR_ID}\"
},
\"replacements\": {},
\"size\": 20,
\"subAction\": \"invokeAI\"
}" | jq -r '.execution_uuid')
echo "Attack Discovery execution UUID: ${EXECUTION_UUID}"
Sobald die Generierung abgeschlossen ist (ca. 60–90 Sekunden), rufen Sie die erkannte Angriffskette ab:
curl -sk -u "elastic:${ELASTIC_PASSWORD}" \
"https://${KIBANA_IP}:5601/api/attack_discovery/_find" \
-H "kbn-xsrf: true" \
-H "elastic-api-version: 2023-10-31" \
| jq '.data[0]'
Die generierte Angriffserkennung korreliert die vier Warnungen zu einem einzigen Vorfall mit verknüpfter Quell-IP, verknüpftem Nutzerkonto und verknüpften MITRE ATT&CK-Taktiken:
{
"alert_ids": [
"05c30118398ea2a8b70c55ce81fdb559dbe14c460a8a95253bd81719415a28b5",
"73ebaeca440b463ffa5812da5b68a2485d465a648ffaf16385a54d8bae9a53d2",
"60ae9f16b40cec1bdc27674ade0e5eb69680ccca3d956fbf2a75418843799987",
"de503ae52444db7712d062c54750f413b90a75521cdfff0de9bdf41a64141346"
],
"alert_rule_uuid": "attack_discovery_ad_hoc_rule_id",
"alert_start": "2026-10-03T01:05:00.384Z",
"alert_updated_at": "2026-10-03T01:05:03.460Z",
"alert_workflow_status": "open",
"alert_workflow_status_updated_at": "2026-10-03T01:05:03.460Z",
"connector_id": "<GENERATED_CONNECTOR_ID>",
"connector_name": "<GENERATED_CONNECTOR_ID>",
"details_markdown": "- The attack sequence began at `2026-10-01T12:43:41.756Z` when an actor using IP `30.156.16.164` performed active reconnaissance scanning against the server.\n- Following the initial scan, the attacker attempted to exploit a path traversal vulnerability at `2026-10-01T12:43:51.756Z` and again at `2026-10-01T12:44:02.756Z`, specifically targeting the `/etc/passwd` file via the `mj_wwwusr` CGI endpoint.\n- The activity concluded with further reconnaissance scanning at `2026-10-01T12:44:21.756Z` from the same source IP `30.156.16.164`.\n- All requests were associated with the user `www-data` and resulted in 404 errors, suggesting the attempts were unsuccessful.",
"entity_summary_markdown": "Activity targeting user `www-data` from source IP `30.156.16.164`.",
"generation_uuid": "<EXECUTION_UUID>",
"id": "1f71ed004c7340d5088d242ca2483525a164a9ea9a80a3f90bd1f514d43231bc",
"mitre_attack_tactics": [
"Reconnaissance",
"Initial Access"
],
"risk_score": 240,
"summary_markdown": "An attacker from `30.156.16.164` performed reconnaissance and path traversal attempts against the system.",
"timestamp": "2026-10-03T01:05:00.384Z",
"title": "Web Reconnaissance and Exploitation Attempt",
"user_id": "elastic",
"user_name": "elastic",
"users": [
{
"id": "elastic",
"name": "elastic"
}
],
"index": ".internal.adhoc.alerts-security.attack.discovery.alerts-default-000001"
}