blabla
This commit is contained in:
486
wazuh.md
486
wazuh.md
@ -1,427 +1,105 @@
|
||||
# Wazuh
|
||||
|
||||
## But
|
||||
## Étude
|
||||
|
||||
Il y a 2 sources de logs qui nous intéressent :
|
||||
- les logs des conteneurs des pods ;
|
||||
- l'audit de l'apiserver.
|
||||
L'étude se trouve dans un autre document.
|
||||
|
||||
Il n'est pas possible de récupérer les logs des pods à travers l'audit de l'apiserver (à part peut-être de façon bancale en interrogeant l'endpoint /logs mais ce n'est pas viable).
|
||||
## Composants Wazuh
|
||||
|
||||
La centralisation des logs de conteneurs de pods a plusieurs objectifs :
|
||||
- l'aide au débogage des applications tournant dans le cluster (ex: portail)
|
||||
- l'aide au débogage des applications "système" tournant dans le cluster (ex: coredns)
|
||||
- la rétention d'informations légales (tentatives de connexion par exemple)
|
||||
L'éco-système Wazuh peut être découpé en 4 éléments :
|
||||
- l'indexer Wazuh qui tourne coté serveur
|
||||
- le manager Wazuh qui tourne coté serveur
|
||||
- le dashboard Wazuh qui tourne coté serveur
|
||||
- l'agent Wazuh qui tourne sur la machine à surveiller
|
||||
|
||||
L'audit de l'apiserveur a plusieurs objectifs :
|
||||
- la détection de comportement suspicieux (accès/modifications/tentatives d'accès aux ressources)
|
||||
- l'aide au débogage en cas de grave disfonctionnement du cluster
|
||||
## Wazuh server
|
||||
|
||||
NUO mets à disposition 1 serveur Wazuh de préprod pour des tests : `wazuh-pp.in.nuonet.fr`. Cadoles a la main complète sur le serveur. Cadoles a installé un serveur wazuh complet (indexer+server+dashboard) avec docker sur ce serveur.
|
||||
|
||||
## Audit de l'apiserver
|
||||
NUO mets à disposition un service Wazuh de production découpé en 3 serveurs :
|
||||
- xdr-dashboard.in.nuonet.fr pour la partie graphique, accessible en https
|
||||
- xdr-server.in.nuonet.fr pour la communication avec les agents entre autre
|
||||
- xdr-indexer.in.nuonet.fr pour l'inexdation (aucune interaction)
|
||||
|
||||
### Solutions explorées
|
||||
### Wazuh server PP
|
||||
|
||||
2 solutions ont été explorées :
|
||||
1. Installer sur chaque noeud le client wazuh et créer un objet k8s de type audit policy ;
|
||||
2. Installer sur le serveur wazuh un listener et créer un objet k8s de type audit policy.
|
||||
Pour faire des tests, le serveur de PP a été configuré. Tout est dans le dossier ~cadoles/wazuh-docker/single-node ou dans le conteneur docker directement, `/var/ossec/etc/ossec.conf`. La documentation suivie est ici : https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html
|
||||
|
||||
La solution 1 n'est pas envisageable, les noeuds étant immutables.
|
||||
|
||||
Après recherches et discussion sur le slack de Wazuh, il semblerait qu'aucun agent wazuh ne supporte un environnement k8s et que la solution 2 soit la meilleure solution.
|
||||
|
||||
### Lab local
|
||||
|
||||
Pour un test local, la manière la plus simple est de suivre les docs suivantes :
|
||||
|
||||
- https://documentation.wazuh.com/4.11/deployment-options/docker/wazuh-container.html#single-node-deployment
|
||||
- https://wazuh.com/blog/auditing-kubernetes-with-wazuh/
|
||||
|
||||
avec quelques modifications cependant pour ajouter un listener sur le port 1580 dans le conteneur de wazuh afin d'envoyer les logs à la socket unix de wazuh.
|
||||
|
||||
Attention : cette procédure est un POC largement améliorable. Cela reste avant tout une piste de démarrage pour travailler sur le sujet.
|
||||
|
||||
#### Installation du serveur wazuh
|
||||
|
||||
Suivre le tutoriel https://documentation.wazuh.com/4.11/deployment-options/docker/wazuh-container.html#single-node-deployment pour la génération des certificats.
|
||||
|
||||
Ajouter localement les fichiers suivants :
|
||||
- custom-webhook.py
|
||||
Une fois up, il est possible d'entrer dans le conteneur `single-node-wazuh.manager-1` pour modifier des config, voir ce que le serveur reçoit de la part des agents (dans `/var/ossec/logs/archives/archives.json`) si les options
|
||||
```
|
||||
#!/var/ossec/framework/python/bin/python3
|
||||
import json
|
||||
from socket import socket, AF_UNIX, SOCK_DGRAM
|
||||
from flask import Flask, request
|
||||
# CONFIG
|
||||
PORT = 1580
|
||||
CERT = '/var/ossec/api/configuration/ssl/server.crt'
|
||||
CERT_KEY = '/var/ossec/api/configuration/ssl/server.key'
|
||||
# Analysisd socket address
|
||||
socket_addr = '/var/ossec/queue/sockets/queue'
|
||||
def send_event(msg):
|
||||
string = '1:k8s:{0}'.format(json.dumps(msg))
|
||||
sock = socket(AF_UNIX, SOCK_DGRAM)
|
||||
sock.connect(socket_addr)
|
||||
sock.send(string.encode())
|
||||
sock.close()
|
||||
return True
|
||||
app = Flask(__name__)
|
||||
context = (CERT, CERT_KEY)
|
||||
@app.route('/', methods=['POST'])
|
||||
def webhook():
|
||||
if request.method == 'POST':
|
||||
if send_event(request.json):
|
||||
print("Request sent to Wazuh")
|
||||
else:
|
||||
print("Failed to send request to Wazuh")
|
||||
return "Webhook received!"
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=PORT, ssl_context=context)
|
||||
```
|
||||
- local_rules.xml
|
||||
```
|
||||
<group name="k8s_audit,">
|
||||
<rule id="110002" level="0">
|
||||
<location>k8s</location>
|
||||
<field name="apiVersion">audit.k8s.io/v1</field>
|
||||
<description>Kubernetes audit log.</description>
|
||||
</rule>
|
||||
<rule id="110003" level="5">
|
||||
<if_sid>110002</if_sid>
|
||||
<regex type="pcre2">requestURI\":.+", \"verb\": \"create</regex>
|
||||
<description>Kubernetes request to create resource</description>
|
||||
</rule>
|
||||
<rule id="110004" level="5">
|
||||
<if_sid>110002</if_sid>
|
||||
<regex type="pcre2">requestURI\":.+", \"verb\": \"delete</regex>
|
||||
<description>Kubernetes request to delete resource</description>
|
||||
</rule>
|
||||
</group>
|
||||
<ossec_config>
|
||||
<global>
|
||||
<logall>yes</logall>
|
||||
<logall_json>yes</logall_json>
|
||||
</global>
|
||||
</ossec_config>
|
||||
```
|
||||
ont bien été ajoutées au fichier de configuration `/var/ossec/etc/ossec.conf`.
|
||||
|
||||
Dans le docker-compose.yml, ajouter :
|
||||
- le mapping de port "1580:1580" au wazuh.manager
|
||||
- le mapping ./custom-webhook.py:/var/ossec/integrations/custom-webhook.py
|
||||
- le mapping ./local_rules.xml:/var/ossec/etc/rules/local_rules.xml
|
||||
`/var/ossec/bin/wazuh-logtest` permet entre autre de tester les `decoders` et les `rules`.
|
||||
|
||||
Ce qui donne :
|
||||
```
|
||||
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
|
||||
version: '3.7'
|
||||
## Wazuh agent
|
||||
|
||||
services:
|
||||
wazuh.manager:
|
||||
image: wazuh/wazuh-manager:4.11.1
|
||||
hostname: wazuh.manager
|
||||
restart: always
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 655360
|
||||
hard: 655360
|
||||
ports:
|
||||
- "1514:1514"
|
||||
- "1515:1515"
|
||||
- "1580:1580"
|
||||
- "514:514/udp"
|
||||
- "55000:55000"
|
||||
environment:
|
||||
- INDEXER_URL=https://wazuh.indexer:9200
|
||||
- INDEXER_USERNAME=admin
|
||||
- INDEXER_PASSWORD=SecretPassword
|
||||
- FILEBEAT_SSL_VERIFICATION_MODE=full
|
||||
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
|
||||
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
|
||||
- SSL_KEY=/etc/ssl/filebeat.key
|
||||
- API_USERNAME=wazuh-wui
|
||||
- API_PASSWORD=MyS3cr37P450r.*-
|
||||
volumes:
|
||||
- wazuh_api_configuration:/var/ossec/api/configuration
|
||||
- wazuh_etc:/var/ossec/etc
|
||||
- wazuh_logs:/var/ossec/logs
|
||||
- wazuh_queue:/var/ossec/queue
|
||||
- wazuh_var_multigroups:/var/ossec/var/multigroups
|
||||
- wazuh_integrations:/var/ossec/integrations
|
||||
- wazuh_active_response:/var/ossec/active-response/bin
|
||||
- wazuh_agentless:/var/ossec/agentless
|
||||
- wazuh_wodles:/var/ossec/wodles
|
||||
- filebeat_etc:/etc/filebeat
|
||||
- filebeat_var:/var/lib/filebeat
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
|
||||
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf
|
||||
- ./custom-webhook.py:/var/ossec/integrations/custom-webhook.py
|
||||
- ./wazuh-webhook.service:/lib/systemd/system/wazuh-webhook.service
|
||||
- ./local_rules.xml:/var/ossec/etc/rules/local_rules.xml
|
||||
|
||||
wazuh.indexer:
|
||||
image: wazuh/wazuh-indexer:4.11.1
|
||||
hostname: wazuh.indexer
|
||||
restart: always
|
||||
ports:
|
||||
- "9200:9200"
|
||||
environment:
|
||||
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 65536
|
||||
hard: 65536
|
||||
volumes:
|
||||
- wazuh-indexer-data:/var/lib/wazuh-indexer
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
|
||||
- ./config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
|
||||
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
|
||||
|
||||
wazuh.dashboard:
|
||||
image: wazuh/wazuh-dashboard:4.11.1
|
||||
hostname: wazuh.dashboard
|
||||
restart: always
|
||||
ports:
|
||||
- 443:5601
|
||||
environment:
|
||||
- INDEXER_USERNAME=admin
|
||||
- INDEXER_PASSWORD=SecretPassword
|
||||
- WAZUH_API_URL=https://wazuh.manager
|
||||
- DASHBOARD_USERNAME=kibanaserver
|
||||
- DASHBOARD_PASSWORD=kibanaserver
|
||||
- API_USERNAME=wazuh-wui
|
||||
- API_PASSWORD=MyS3cr37P450r.*-
|
||||
volumes:
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
|
||||
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
|
||||
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
|
||||
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
|
||||
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
|
||||
depends_on:
|
||||
- wazuh.indexer
|
||||
links:
|
||||
- wazuh.indexer:wazuh.indexer
|
||||
- wazuh.manager:wazuh.manager
|
||||
|
||||
volumes:
|
||||
wazuh_api_configuration:
|
||||
wazuh_etc:
|
||||
wazuh_logs:
|
||||
wazuh_queue:
|
||||
wazuh_var_multigroups:
|
||||
wazuh_integrations:
|
||||
wazuh_active_response:
|
||||
wazuh_agentless:
|
||||
wazuh_wodles:
|
||||
filebeat_etc:
|
||||
filebeat_var:
|
||||
wazuh-indexer-data:
|
||||
wazuh-dashboard-config:
|
||||
wazuh-dashboard-custom:
|
||||
```
|
||||
|
||||
Ensuite, lancer le serveur avec
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Se connecter au conteneur pour installer flask (pour notre listener) :
|
||||
```
|
||||
docker exec single-node-wazuh.manager-1 /var/ossec/framework/python/bin/pip3 install flask
|
||||
```
|
||||
puis démarrer le serveur webhook :
|
||||
```
|
||||
docker exec single-node-wazuh.manager-1 /var/ossec/framework/python/bin/python3 /var/ossec/integrations/custom-webhook.py
|
||||
```
|
||||
|
||||
A ce moment là, le serveur est prêt à recevoir des logs d'audit k8s.
|
||||
|
||||
Le serveur devrait être accessible sur https://127.0.0.1/app/login (admin/SecretPassword).
|
||||
|
||||
Note : il reste un problème avec les dashboard qui ne s'affichent pas dans l'interface web. Ce n'est pas grave, les logs reste accessibles dans l'exploration de données.
|
||||
|
||||
#### Lien entre le cluster et le serveur wazuh
|
||||
|
||||
Pour lier le cluster et le serveur wazuh en réseau, sans s'embêter avec les configurations réseau, on peut faire un tunnel (remplacer l'ip par l'ip du contenur wazuh-server) :
|
||||
```
|
||||
ssh -L 0.0.0.0:1581:172.21.0.3:1580 127.0.0.1
|
||||
```
|
||||
|
||||
#### Création du cluster k8s "kind"
|
||||
|
||||
On va créer un cluster kind nommé "wazuh" avec 1 CP et 1 Worker. On ajoute 2 fichiers de conf pour kubeapi-server : audit-policy.yaml et audit-webhook.yaml.
|
||||
|
||||
wazuh/audit-policy.yaml:
|
||||
```
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
rules:
|
||||
# Don’t log requests to the following API endpoints
|
||||
- level: None
|
||||
nonResourceURLs:
|
||||
- '/healthz*'
|
||||
- '/metrics'
|
||||
- '/swagger*'
|
||||
- '/version'
|
||||
# Limit requests containing tokens to Metadata level so the token is not included in the log
|
||||
#- level: Metadata
|
||||
# omitStages:
|
||||
# - RequestReceived
|
||||
# resources:
|
||||
# - group: authentication.k8s.io
|
||||
# resources:
|
||||
# - tokenreviews
|
||||
# Extended audit of auth delegation
|
||||
#- level: RequestResponse
|
||||
# omitStages:
|
||||
# - RequestReceived
|
||||
# resources:
|
||||
# - group: authorization.k8s.io
|
||||
# resources:
|
||||
# - subjectaccessreviews
|
||||
# Log changes to pods at RequestResponse level
|
||||
- level: RequestResponse
|
||||
omitStages:
|
||||
- RequestReceived
|
||||
resources:
|
||||
# core API group; add third-party API services and your API services if needed
|
||||
- group: ''
|
||||
resources: ['pods']
|
||||
verbs: ['create', 'patch', 'update', 'delete']
|
||||
# Log everything else at Metadata level
|
||||
- level: Metadata
|
||||
omitStages:
|
||||
- RequestReceived
|
||||
- level: RequestResponse
|
||||
nonResourceURLs:
|
||||
- '/logs'
|
||||
```
|
||||
|
||||
wazuh/audit-webhook.yaml (attention, changer MON_IP par 192.168.10.XX):
|
||||
```
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
preferences: {}
|
||||
clusters:
|
||||
- name: wazuh-webhook
|
||||
cluster:
|
||||
insecure-skip-tls-verify: true
|
||||
server: https://MON_IP:1581
|
||||
# kubeconfig files require a context. Provide one for the API server.
|
||||
current-context: webhook
|
||||
contexts:
|
||||
- context:
|
||||
cluster: wazuh-webhook
|
||||
user: kube-apiserver # Replace with name of API server if it’s different
|
||||
name: webhook
|
||||
```
|
||||
|
||||
wazuh.yaml:
|
||||
```
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
name: wazuh
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: reg.cadoles.com/dh/kindest/node:v1.28.7
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: ClusterConfiguration
|
||||
apiServer:
|
||||
extraArgs:
|
||||
audit-webhook-batch-max-size: "1"
|
||||
audit-webhook-config-file: "/etc/kubernetes/audit-webhook.yaml"
|
||||
audit-policy-file: "/etc/kubernetes/policies/audit-policy.yaml"
|
||||
extraVolumes:
|
||||
- name: audit-policies
|
||||
hostPath: "/etc/kubernetes/policies"
|
||||
mountPath: "/etc/kubernetes/policies"
|
||||
readOnly: true
|
||||
pathType: "DirectoryOrCreate"
|
||||
- name: audit-webhook
|
||||
hostPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
mountPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
readOnly: true
|
||||
- |
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
node-labels: "ingress-ready=true"
|
||||
extraMounts:
|
||||
- hostPath: "./wazuh/audit-policy.yaml"
|
||||
containerPath: "/etc/kubernetes/policies/audit-policy.yaml"
|
||||
readOnly: true
|
||||
- hostPath: "./wazuh/audit-webhook.yaml"
|
||||
containerPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
readOnly: true
|
||||
extraPortMappings:
|
||||
- containerPort: 31000
|
||||
hostPort: 31001
|
||||
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
|
||||
- containerPort: 80
|
||||
hostPort: 8081
|
||||
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
|
||||
labels:
|
||||
ingress-ready: true
|
||||
- role: worker
|
||||
image: reg.cadoles.com/dh/kindest/node:v1.28.7
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
system-reserved: memory=2Gi
|
||||
```
|
||||
|
||||
```
|
||||
kind create cluster --config wazuh.yaml
|
||||
```
|
||||
|
||||
À ce moment là, on doit pouvoir voir des logs coté de custom-webhook.py qui reçoit des logs du cluster. Ensuite, dans l'interface web de wazuh, on doit pouvoir retrouver les logs du cluster dans l'exploration de données. Un filtre sur "data.apiVersion=audit.k8s.io/v1" devrait retourner uniquement les logs serveur.
|
||||
|
||||
### Analyse
|
||||
|
||||
Comme indiqué en introduction, cette méthode permet de recevoir dans Wazuh toutes les activités passant par l'apiserver. Cependant :
|
||||
- il faut prendre en compte une augmentation de la consommation mémoire sur les controle-plane ;
|
||||
- il faut customizer audit-policy.yaml afin de filtrer les appels à l'apiserver réellement important et éviter de se retrouver avec trop de logs ;
|
||||
- il faut trouver un moyen de filtrer par cluster (prod et pp)
|
||||
|
||||
> The audit logging feature increases the memory consumption of the API server because some context required for auditing is stored for each request. Memory consumption depends on the audit logging configuration.
|
||||
|
||||
## Journalisation au niveau cluster
|
||||
|
||||
### Solutions explorées
|
||||
|
||||
D'après la documentation [kubernetes](https://kubernetes.io/docs/concepts/cluster-administration/logging/#cluster-level-logging-architectures), la meilleure solution dans notre cas est d'installer un daemonset dans le cluster ayant accès au dossier /var/log/pods.
|
||||
|
||||
Reste à déterminer quel logiciel faire tourner dans le pod.
|
||||
|
||||
|
||||
### DaemonSet
|
||||
|
||||
Après discussion sur le slack de Wazuh, il nous ait conseillé par un employé de Wazuh d'utiliser un DaemonSet géré par OpenNix https://opennix.org/en/opensource/.
|
||||
|
||||
OpenNix offre 2 possibilités : utiliser le DaemonSet ou utiliser un opérateur k8s.
|
||||
L'opérateur n'ayant été pull que peu de fois, et après analyse du dépôt source (https://github.com/pyToshka/wazuh-agent-kubernetes-operator), il semblerait qu'il ne soit utile que pour produire un DaemonSet et un Secret avec les données passées en paramètre. L'ajout d'un DaemonSet et d'un Secret directement semble plus adapté.
|
||||
Sur les 2 clusters k8s (prod et PP) ont été déployé 1 [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/).
|
||||
|
||||
OpenNix est une organization russe. Il a été décidé de réimplémenter une solution pour intégrer l'agent Wazuh dans kubernetes. Cela se présente sous la forme de projets maintenus par Cadoles :
|
||||
- wazuh-agent-k8s-autoadd : programme go pour enregistrer puis démarrer un agent Wazuh + Dockerfile
|
||||
- wazuh-agent-kustom : kustomization d'un DaemonSet, d'une ConfigMap et d'un Secret
|
||||
- wazuh-agent-container : Dockerfile pour créer un conteneur wazuh-agent
|
||||
|
||||
DaemonSet: 2 images, l'une register et produit le fichier de conf ossec, l'autre démarre ensuite avec l'agent wazuh. Health endpoint?
|
||||
- https://forge.cadoles.com/Cadoles/wazuh-agent-k8s-autoadd : programme go pour enregistrer (via API) puis démarrer un agent Wazuh + Dockerfile
|
||||
- https://forge.cadoles.com/CadolesKube/wazuh-agent-kustom : kustomization d'un DaemonSet pour déployer un agent Wazuh et wazuh-agent-k8s-autoadd sur chaque noeud d'un cluster k8s, d'une ConfigMap et d'un Secret
|
||||
|
||||
|
||||
### Configuration
|
||||
|
||||
Au 26 mai 2025, le fichier de configuration de l'agent, `/var/ossec/etc/ossec.conf` est la suivante :
|
||||
```
|
||||
<ossec_config>
|
||||
<client>
|
||||
<server>
|
||||
<address>{{ getenv "WAZUH_MANAGER_HOST" }}</address>
|
||||
<port>{{ getenv "WAZUH_MANAGER_PORT" "1514" }}</port>
|
||||
</server>
|
||||
</client>
|
||||
|
||||
<localfile>
|
||||
<location>/var/log/pods/*/*/*.log</location>
|
||||
<log_format>syslog</log_format>
|
||||
</localfile>
|
||||
</ossec_config>
|
||||
```
|
||||
|
||||
Les parties variables sont remplacées grâce à [gomplate](https://docs.gomplate.ca/).
|
||||
|
||||
### Mise en place
|
||||
|
||||
Dans les projet k8s-deploy et k8s-pp-deploy
|
||||
```
|
||||
kustomize build --load-restrictor LoadRestrictionsNone kustomize/trust-manager/ --enable-helm
|
||||
kustomize build --load-restrictor LoadRestrictionsNone kustomize/wazuh-agent
|
||||
```
|
||||
|
||||
### Ajout d'un agent
|
||||
|
||||
Une fois l'agent déployé, il faut demander à NUO (Nomena) d'ajouter le serveur dans le bon groupe sur NUO afin de le voir.
|
||||
|
||||
### Mise à jour de la config
|
||||
|
||||
Pour mettre à jour la configuration de l'agent Wazuh (ossec.conf), :
|
||||
|
||||
### Mise à jour de l'agent Wazuh
|
||||
|
||||
Il est en théorie possible d'upgrade l'agent Wazuh depuis le serveur Wazuh. Cependant, dans le cadre de kubernetes, Cadoles ne recommande pas l'upgrade d'agent Wazuh depuis le serveur Wazuh car même si la mise-à-jour fonctionne (peu probable à cause de l'environnement conteneurisé), si le pod redémarre, il retournera à la version précédente. Il vaut mieux mettre à jour le Dockerfile du projet https://forge.cadoles.com/CadolesKube/wazuh-agent-kustom puis déployer sur les 2 clusters k8s. Attention à la compatibilité entre l'agent et le serveur Wazuh. L'agent ne doit jamais être plus récent que le serveur.
|
||||
|
||||
### Changement de CA
|
||||
|
||||
La CA utilisée pour signer le certificat du serveur Wazuh de NUO est dans le fichier `kustomize/trust-manager/resources/wazuh-manager-ca.yaml` dans les dépôts git k8s-deploy et k8s-pp-deploy. Pour changer de CA, il suffit d'éditer le fichier puis de déployer le changement avec kubectl apply. Ne pas oublier de pousser ces changements sur les dépôts git.
|
||||
|
||||
Demander :
|
||||
- version du wazuh manager (la version de l'agent doit être inférieure ou égale)
|
||||
- certificats ?
|
||||
- nom/addresse du manager wazuh ou endpoint
|
||||
- version du wazuh manager (la version de l'agent doit être inférieure ou égale) -> v4.11.2 v4.12 cet am
|
||||
- certificats ? -> autosigné (pas sûr)
|
||||
- nom/addresse du manager wazuh et API server -> xdr-dashboard.in.nuonet.fr xdr-server.in.nuonet.fr xdr-indexer.in.nuonet.fr
|
||||
- ouverture du port de l'API depuis les machines du cluster (55000) -> Noména va le faire
|
||||
- OK pour auto-enregistrement via l'API ? -> OK, on ne voit pas de soucis
|
||||
- Création de compte pour nous sur le dashboard -> Noména va le faire
|
||||
- Création de compte de service pour l'enregistrement des clients wazuh -> Noména va le faire
|
||||
- Dans quel groupe mettre les agents -> Noména va y réfléchir (par salle et par environnement prod/pp)
|
||||
- Est-ce qu'ils voient les logs pour d'autre apps ? Ont-ils activé l'archivage des logs ? Ils auront une presta pour voir l'intégration d'applicatifs. Pas exploitable rapidement.
|
||||
- Quelle config ossec.conf ? Veulent-ils quelque chose en particulier ? Peut-être wodle docker-listener mais nécessite de redémarrer docker. Noména va y réfléchir.
|
||||
|
506
étude_wazuh.md
Normal file
506
étude_wazuh.md
Normal file
@ -0,0 +1,506 @@
|
||||
# Wazuh
|
||||
|
||||
## But
|
||||
|
||||
Nous avons 3 objectifs principaux avec Wazuh :
|
||||
1. Lever des alertes sur des comportements suspects :
|
||||
2. Centraliser les logs ;
|
||||
3. Avoir une vision des logs agrégés.
|
||||
|
||||
Il y a 2 sources de logs qui nous intéressent :
|
||||
- les logs des conteneurs des pods ;
|
||||
- l'audit de l'apiserver.
|
||||
|
||||
Il n'est pas possible de récupérer les logs des pods à travers l'audit de l'apiserver (à part peut-être de façon bancale en interrogeant l'endpoint /logs mais ce n'est pas viable), les 2 sources de logs doivent être traîter différemment.
|
||||
|
||||
La centralisation des logs de conteneurs de pods a plusieurs objectifs :
|
||||
- l'aide au débogage des applications tournant dans le cluster (ex: portail)
|
||||
- l'aide au débogage des applications "système" tournant dans le cluster (ex: coredns)
|
||||
- la rétention d'informations légales (tentatives de connexion par exemple)
|
||||
- la détection de comportements suspicieux au niveau applicatif (ex: création de comptes frauduleux)
|
||||
|
||||
L'audit de l'apiserveur a plusieurs objectifs :
|
||||
- la détection de comportements suspicieux au niveau k8s (accès/modifications/tentatives d'accès aux ressources)
|
||||
- l'aide au débogage en cas de grave disfonctionnement du cluster
|
||||
|
||||
|
||||
## Audit de l'apiserver
|
||||
|
||||
### Solutions explorées
|
||||
|
||||
2 solutions ont été explorées :
|
||||
1. Installer sur chaque noeud le client wazuh et créer un objet k8s de type audit policy ;
|
||||
2. Installer sur le serveur wazuh un listener et créer un objet k8s de type audit policy.
|
||||
|
||||
La solution 1 n'est pas envisageable, les noeuds étant immutables.
|
||||
|
||||
Après recherches et discussion sur le slack de Wazuh, il semblerait qu'aucun agent wazuh ne supporte un environnement k8s et que la solution 2 soit la meilleure solution.
|
||||
|
||||
### Lab local
|
||||
|
||||
Pour un test local, la manière la plus simple est de suivre les docs suivantes :
|
||||
|
||||
- https://documentation.wazuh.com/4.11/deployment-options/docker/wazuh-container.html#single-node-deployment
|
||||
- https://wazuh.com/blog/auditing-kubernetes-with-wazuh/
|
||||
|
||||
avec quelques modifications cependant pour ajouter un listener sur le port 1580 dans le conteneur de wazuh afin d'envoyer les logs à la socket unix de wazuh.
|
||||
|
||||
Attention : cette procédure est un POC largement améliorable. Cela reste avant tout une piste de démarrage pour travailler sur le sujet.
|
||||
|
||||
#### Installation du serveur wazuh
|
||||
|
||||
Suivre le tutoriel https://documentation.wazuh.com/4.11/deployment-options/docker/wazuh-container.html#single-node-deployment pour la génération des certificats.
|
||||
|
||||
Ajouter localement les fichiers suivants :
|
||||
- custom-webhook.py
|
||||
```
|
||||
#!/var/ossec/framework/python/bin/python3
|
||||
import json
|
||||
from socket import socket, AF_UNIX, SOCK_DGRAM
|
||||
from flask import Flask, request
|
||||
# CONFIG
|
||||
PORT = 1580
|
||||
CERT = '/var/ossec/api/configuration/ssl/server.crt'
|
||||
CERT_KEY = '/var/ossec/api/configuration/ssl/server.key'
|
||||
# Analysisd socket address
|
||||
socket_addr = '/var/ossec/queue/sockets/queue'
|
||||
def send_event(msg):
|
||||
string = '1:k8s:{0}'.format(json.dumps(msg))
|
||||
sock = socket(AF_UNIX, SOCK_DGRAM)
|
||||
sock.connect(socket_addr)
|
||||
sock.send(string.encode())
|
||||
sock.close()
|
||||
return True
|
||||
app = Flask(__name__)
|
||||
context = (CERT, CERT_KEY)
|
||||
@app.route('/', methods=['POST'])
|
||||
def webhook():
|
||||
if request.method == 'POST':
|
||||
if send_event(request.json):
|
||||
print("Request sent to Wazuh")
|
||||
else:
|
||||
print("Failed to send request to Wazuh")
|
||||
return "Webhook received!"
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=PORT, ssl_context=context)
|
||||
```
|
||||
- local_rules.xml
|
||||
```
|
||||
<group name="k8s_audit,">
|
||||
<rule id="110002" level="0">
|
||||
<location>k8s</location>
|
||||
<field name="apiVersion">audit.k8s.io/v1</field>
|
||||
<description>Kubernetes audit log.</description>
|
||||
</rule>
|
||||
<rule id="110003" level="5">
|
||||
<if_sid>110002</if_sid>
|
||||
<regex type="pcre2">requestURI\":.+", \"verb\": \"create</regex>
|
||||
<description>Kubernetes request to create resource</description>
|
||||
</rule>
|
||||
<rule id="110004" level="5">
|
||||
<if_sid>110002</if_sid>
|
||||
<regex type="pcre2">requestURI\":.+", \"verb\": \"delete</regex>
|
||||
<description>Kubernetes request to delete resource</description>
|
||||
</rule>
|
||||
</group>
|
||||
```
|
||||
|
||||
Dans le docker-compose.yml, ajouter :
|
||||
- le mapping de port "1580:1580" au wazuh.manager
|
||||
- le mapping ./custom-webhook.py:/var/ossec/integrations/custom-webhook.py
|
||||
- le mapping ./local_rules.xml:/var/ossec/etc/rules/local_rules.xml
|
||||
|
||||
Ce qui donne :
|
||||
```
|
||||
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
wazuh.manager:
|
||||
image: wazuh/wazuh-manager:4.11.1
|
||||
hostname: wazuh.manager
|
||||
restart: always
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 655360
|
||||
hard: 655360
|
||||
ports:
|
||||
- "1514:1514"
|
||||
- "1515:1515"
|
||||
- "1580:1580"
|
||||
- "514:514/udp"
|
||||
- "55000:55000"
|
||||
environment:
|
||||
- INDEXER_URL=https://wazuh.indexer:9200
|
||||
- INDEXER_USERNAME=admin
|
||||
- INDEXER_PASSWORD=SecretPassword
|
||||
- FILEBEAT_SSL_VERIFICATION_MODE=full
|
||||
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
|
||||
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
|
||||
- SSL_KEY=/etc/ssl/filebeat.key
|
||||
- API_USERNAME=wazuh-wui
|
||||
- API_PASSWORD=MyS3cr37P450r.*-
|
||||
volumes:
|
||||
- wazuh_api_configuration:/var/ossec/api/configuration
|
||||
- wazuh_etc:/var/ossec/etc
|
||||
- wazuh_logs:/var/ossec/logs
|
||||
- wazuh_queue:/var/ossec/queue
|
||||
- wazuh_var_multigroups:/var/ossec/var/multigroups
|
||||
- wazuh_integrations:/var/ossec/integrations
|
||||
- wazuh_active_response:/var/ossec/active-response/bin
|
||||
- wazuh_agentless:/var/ossec/agentless
|
||||
- wazuh_wodles:/var/ossec/wodles
|
||||
- filebeat_etc:/etc/filebeat
|
||||
- filebeat_var:/var/lib/filebeat
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
|
||||
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf
|
||||
- ./custom-webhook.py:/var/ossec/integrations/custom-webhook.py
|
||||
- ./wazuh-webhook.service:/lib/systemd/system/wazuh-webhook.service
|
||||
- ./local_rules.xml:/var/ossec/etc/rules/local_rules.xml
|
||||
|
||||
wazuh.indexer:
|
||||
image: wazuh/wazuh-indexer:4.11.1
|
||||
hostname: wazuh.indexer
|
||||
restart: always
|
||||
ports:
|
||||
- "9200:9200"
|
||||
environment:
|
||||
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 65536
|
||||
hard: 65536
|
||||
volumes:
|
||||
- wazuh-indexer-data:/var/lib/wazuh-indexer
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
|
||||
- ./config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
|
||||
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
|
||||
|
||||
wazuh.dashboard:
|
||||
image: wazuh/wazuh-dashboard:4.11.1
|
||||
hostname: wazuh.dashboard
|
||||
restart: always
|
||||
ports:
|
||||
- 443:5601
|
||||
environment:
|
||||
- INDEXER_USERNAME=admin
|
||||
- INDEXER_PASSWORD=SecretPassword
|
||||
- WAZUH_API_URL=https://wazuh.manager
|
||||
- DASHBOARD_USERNAME=kibanaserver
|
||||
- DASHBOARD_PASSWORD=kibanaserver
|
||||
- API_USERNAME=wazuh-wui
|
||||
- API_PASSWORD=MyS3cr37P450r.*-
|
||||
volumes:
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
|
||||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
|
||||
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
|
||||
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
|
||||
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
|
||||
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
|
||||
depends_on:
|
||||
- wazuh.indexer
|
||||
links:
|
||||
- wazuh.indexer:wazuh.indexer
|
||||
- wazuh.manager:wazuh.manager
|
||||
|
||||
volumes:
|
||||
wazuh_api_configuration:
|
||||
wazuh_etc:
|
||||
wazuh_logs:
|
||||
wazuh_queue:
|
||||
wazuh_var_multigroups:
|
||||
wazuh_integrations:
|
||||
wazuh_active_response:
|
||||
wazuh_agentless:
|
||||
wazuh_wodles:
|
||||
filebeat_etc:
|
||||
filebeat_var:
|
||||
wazuh-indexer-data:
|
||||
wazuh-dashboard-config:
|
||||
wazuh-dashboard-custom:
|
||||
```
|
||||
|
||||
Ensuite, lancer le serveur avec
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Se connecter au conteneur pour installer flask (pour notre listener) :
|
||||
```
|
||||
docker exec single-node-wazuh.manager-1 /var/ossec/framework/python/bin/pip3 install flask
|
||||
```
|
||||
puis démarrer le serveur webhook :
|
||||
```
|
||||
docker exec single-node-wazuh.manager-1 /var/ossec/framework/python/bin/python3 /var/ossec/integrations/custom-webhook.py
|
||||
```
|
||||
|
||||
A ce moment là, le serveur est prêt à recevoir des logs d'audit k8s.
|
||||
|
||||
Le serveur devrait être accessible sur https://127.0.0.1/app/login (admin/SecretPassword).
|
||||
|
||||
Note : il reste un problème avec les dashboard qui ne s'affichent pas dans l'interface web. Ce n'est pas grave, les logs reste accessibles dans l'exploration de données.
|
||||
|
||||
#### Lien entre le cluster et le serveur wazuh
|
||||
|
||||
Pour lier le cluster et le serveur wazuh en réseau, sans s'embêter avec les configurations réseau, on peut faire un tunnel (remplacer l'ip par l'ip du contenur wazuh-server) :
|
||||
```
|
||||
ssh -L 0.0.0.0:1581:172.21.0.3:1580 127.0.0.1
|
||||
```
|
||||
|
||||
#### Création du cluster k8s "kind"
|
||||
|
||||
On va créer un cluster kind nommé "wazuh" avec 1 CP et 1 Worker. On ajoute 2 fichiers de conf pour kubeapi-server : audit-policy.yaml et audit-webhook.yaml.
|
||||
|
||||
wazuh/audit-policy.yaml:
|
||||
```
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
rules:
|
||||
# Don’t log requests to the following API endpoints
|
||||
- level: None
|
||||
nonResourceURLs:
|
||||
- '/healthz*'
|
||||
- '/metrics'
|
||||
- '/swagger*'
|
||||
- '/version'
|
||||
# Limit requests containing tokens to Metadata level so the token is not included in the log
|
||||
#- level: Metadata
|
||||
# omitStages:
|
||||
# - RequestReceived
|
||||
# resources:
|
||||
# - group: authentication.k8s.io
|
||||
# resources:
|
||||
# - tokenreviews
|
||||
# Extended audit of auth delegation
|
||||
#- level: RequestResponse
|
||||
# omitStages:
|
||||
# - RequestReceived
|
||||
# resources:
|
||||
# - group: authorization.k8s.io
|
||||
# resources:
|
||||
# - subjectaccessreviews
|
||||
# Log changes to pods at RequestResponse level
|
||||
- level: RequestResponse
|
||||
omitStages:
|
||||
- RequestReceived
|
||||
resources:
|
||||
# core API group; add third-party API services and your API services if needed
|
||||
- group: ''
|
||||
resources: ['pods']
|
||||
verbs: ['create', 'patch', 'update', 'delete']
|
||||
# Log everything else at Metadata level
|
||||
- level: Metadata
|
||||
omitStages:
|
||||
- RequestReceived
|
||||
- level: RequestResponse
|
||||
nonResourceURLs:
|
||||
- '/logs'
|
||||
```
|
||||
|
||||
wazuh/audit-webhook.yaml (attention, changer MON_IP par 192.168.10.XX):
|
||||
```
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
preferences: {}
|
||||
clusters:
|
||||
- name: wazuh-webhook
|
||||
cluster:
|
||||
insecure-skip-tls-verify: true
|
||||
server: https://MON_IP:1581
|
||||
# kubeconfig files require a context. Provide one for the API server.
|
||||
current-context: webhook
|
||||
contexts:
|
||||
- context:
|
||||
cluster: wazuh-webhook
|
||||
user: kube-apiserver # Replace with name of API server if it’s different
|
||||
name: webhook
|
||||
```
|
||||
|
||||
wazuh.yaml:
|
||||
```
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
name: wazuh
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: reg.cadoles.com/dh/kindest/node:v1.28.7
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: ClusterConfiguration
|
||||
apiServer:
|
||||
extraArgs:
|
||||
audit-webhook-batch-max-size: "1"
|
||||
audit-webhook-config-file: "/etc/kubernetes/audit-webhook.yaml"
|
||||
audit-policy-file: "/etc/kubernetes/policies/audit-policy.yaml"
|
||||
extraVolumes:
|
||||
- name: audit-policies
|
||||
hostPath: "/etc/kubernetes/policies"
|
||||
mountPath: "/etc/kubernetes/policies"
|
||||
readOnly: true
|
||||
pathType: "DirectoryOrCreate"
|
||||
- name: audit-webhook
|
||||
hostPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
mountPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
readOnly: true
|
||||
- |
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
node-labels: "ingress-ready=true"
|
||||
extraMounts:
|
||||
- hostPath: "./wazuh/audit-policy.yaml"
|
||||
containerPath: "/etc/kubernetes/policies/audit-policy.yaml"
|
||||
readOnly: true
|
||||
- hostPath: "./wazuh/audit-webhook.yaml"
|
||||
containerPath: "/etc/kubernetes/audit-webhook.yaml"
|
||||
readOnly: true
|
||||
extraPortMappings:
|
||||
- containerPort: 31000
|
||||
hostPort: 31001
|
||||
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
|
||||
- containerPort: 80
|
||||
hostPort: 8081
|
||||
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
|
||||
labels:
|
||||
ingress-ready: true
|
||||
- role: worker
|
||||
image: reg.cadoles.com/dh/kindest/node:v1.28.7
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
system-reserved: memory=2Gi
|
||||
```
|
||||
|
||||
```
|
||||
kind create cluster --config wazuh.yaml
|
||||
```
|
||||
|
||||
À ce moment là, on doit pouvoir voir des logs coté de custom-webhook.py qui reçoit des logs du cluster. Ensuite, dans l'interface web de wazuh, on doit pouvoir retrouver les logs du cluster dans l'exploration de données. Un filtre sur "data.apiVersion=audit.k8s.io/v1" devrait retourner uniquement les logs serveur.
|
||||
|
||||
### Analyse
|
||||
|
||||
Comme indiqué en introduction, cette méthode permet de recevoir dans Wazuh toutes les activités passant par l'apiserver. Cependant :
|
||||
- il faut prendre en compte une augmentation de la consommation mémoire sur les controle-plane ;
|
||||
- il faut customizer audit-policy.yaml afin de filtrer les appels à l'apiserver réellement important et éviter de se retrouver avec trop de logs ;
|
||||
- il faut trouver un moyen de filtrer par cluster (prod et pp)
|
||||
|
||||
> The audit logging feature increases the memory consumption of the API server because some context required for auditing is stored for each request. Memory consumption depends on the audit logging configuration.
|
||||
|
||||
Pour le moment, cette source de log est mise de coté.
|
||||
|
||||
## Envoi des logs des conteneurs des pods d'un cluster k8s
|
||||
|
||||
### Solutions explorées
|
||||
|
||||
D'après la documentation [kubernetes](https://kubernetes.io/docs/concepts/cluster-administration/logging/#cluster-level-logging-architectures), la meilleure solution dans notre cas est d'installer un daemonset dans le cluster ayant accès au dossier /var/log/pods.
|
||||
|
||||
### DaemonSet
|
||||
|
||||
Après discussion sur le slack de Wazuh, il nous ait conseillé par un employé de Wazuh d'utiliser un DaemonSet géré par OpenNix https://opennix.org/en/opensource/.
|
||||
|
||||
OpenNix offre 2 possibilités : utiliser le DaemonSet ou utiliser un opérateur k8s.
|
||||
L'opérateur n'ayant été pull que peu de fois, et après analyse du dépôt source (https://github.com/pyToshka/wazuh-agent-kubernetes-operator), il semblerait qu'il ne soit utile que pour produire un DaemonSet et un Secret avec les données passées en paramètre. L'ajout d'un DaemonSet et d'un Secret directement semble plus adapté.
|
||||
|
||||
OpenNix est une organization russe. Il a été décidé de réimplémenter une solution pour intégrer l'agent Wazuh dans kubernetes. Cela se présente sous la forme de projets maintenus par Cadoles :
|
||||
- https://forge.cadoles.com/Cadoles/wazuh-agent-k8s-autoadd : programme go pour enregistrer (via API) puis démarrer un agent Wazuh + Dockerfile
|
||||
- https://forge.cadoles.com/CadolesKube/wazuh-agent-kustom : kustomization d'un DaemonSet pour déployer un agent Wazuh et wazuh-agent-k8s-autoadd sur chaque noeud d'un cluster k8s, d'une ConfigMap et d'un Secret
|
||||
|
||||
## Wazuh server
|
||||
|
||||
NUO mets à disposition 2 serveurs Wazuh :
|
||||
- wazuh-pp.in.nuonet.fr : pour des tests, Cadoles a la main complète sur le serveur.
|
||||
-
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Collecte de log
|
||||
|
||||
Le 14/05/24, sur le slack de Wazuh, Laurent a posé la question suivante :
|
||||
```
|
||||
Hello, I set up a Wazuh server with docker (single node). I registered an agent with monitoring a localfile (/var/log/containers/test.log). I wrote 2 times in this file (4 then 5 bytes more). On wazuh-ui, I see the agent as "active" and in the stats I see my file associated with 1 event and 4 bytes long. I have 2 problems:
|
||||
1. where can I see the content of my file?
|
||||
2. Why is my file indicated 4bytes long while it should be 9 bytes longs (with maybe 2events)?
|
||||
```
|
||||
|
||||
Réponse :
|
||||
|
||||
```
|
||||
You can see the content of the logs read by Wazuh in the /var/ossec/logs/archives/archives.json file. Wazuh reads logs in real time, which means when you're monitoring the /var/log/containers/test.log file, it will only read new log entries written after monitoring starts. All logs, including those that don't trigger alerts in the dashboard, can be found in this file, as long as archive logging is enabled.
|
||||
To enable archive logs, edit the /var/ossec/etc/ossec.conf file. In Docker, this corresponds to wazuh-docker/single-node/config/wazuh_cluster/wazuh_manager.conf:
|
||||
|
||||
|
||||
<ossec_config>
|
||||
<global>
|
||||
...
|
||||
<logall>no</logall>
|
||||
<logall_json>yes</logall_json>
|
||||
...
|
||||
</global>
|
||||
</ossec_config>
|
||||
|
||||
After making the changes, restart the Wazuh manager to apply them.
|
||||
Be sure to disable <logall> again once you're done troubleshooting, as it can cause high disk space usage if left enabled.To verify if Wazuh is reading your /var/log/containers/test.log file correctly, you can run:
|
||||
|
||||
cat /var/ossec/logs/archives/archives.json | grep -i -E "<part_of_your_log>"
|
||||
|
||||
Once you confirm Wazuh is reading the logs, you can test how your logs are being decoded using:
|
||||
|
||||
|
||||
/var/ossec/bin/wazuh-logtest
|
||||
|
||||
You can paste your sample log into this tool to see which decoders and rules are applied. More on this can be found here:
|
||||
https://documentation.wazuh.com/current/user-manual/ruleset/testing.html
|
||||
You can also test logs through the Wazuh dashboard's ruleset test. If no rule or decoder matches, you'll need to create custom ones. Refer to the official docs here:
|
||||
https://documentation.wazuh.com/current/user-manual/ruleset/index.htmlWazuh’s <localfile> monitoring reads only new content added to a file. The event and byte counts you see are based on new entries since the last read, not total file size. If you wrote 4 bytes first, Wazuh likely processed that as one complete event. To check how Wazuh is tracking events and bytes internally, you can use these commands at Server Management >> Dev Tools
|
||||
|
||||
GET /agents/003/daemons/stats?daemons_list=wazuh-analysisd
|
||||
GET /agents/003/stats/logcollector
|
||||
|
||||
These are useful to confirm whether Wazuh is actively reading and processing the logs as expected. For more details: https://documentation.wazuh.com/current/user-manual/reference/statistics-files/wazuh-logcollector-state.htmlLet me know if you need help with testing or creating rules.
|
||||
```
|
||||
|
||||
### Mise en place
|
||||
|
||||
Dans les projet k8s-deploy et k8s-pp-deploy
|
||||
kustomize build --load-restrictor LoadRestrictionsNone kustomize/trust-manager/ --enable-helm
|
||||
kustomize build --load-restrictor LoadRestrictionsNone kustomize/wazuh-agent
|
||||
Demander à Noména d'ajouter le serveur dans le bon groupe.
|
||||
|
||||
### Mise à jour de la config
|
||||
|
||||
Pour mettre à jour la configuration de l'agent Wazuh (ossec.conf), :
|
||||
|
||||
|
||||
Demander :
|
||||
- version du wazuh manager (la version de l'agent doit être inférieure ou égale) -> v4.11.2 v4.12 cet am
|
||||
- certificats ? -> autosigné (pas sûr)
|
||||
- nom/addresse du manager wazuh et API server -> xdr-dashboard.in.nuonet.fr xdr-server.in.nuonet.fr xdr-indexer.in.nuonet.fr
|
||||
- ouverture du port de l'API depuis les machines du cluster (55000) -> Noména va le faire
|
||||
- OK pour auto-enregistrement via l'API ? -> OK, on ne voit pas de soucis
|
||||
- Création de compte pour nous sur le dashboard -> Noména va le faire
|
||||
- Création de compte de service pour l'enregistrement des clients wazuh -> Noména va le faire
|
||||
- Dans quel groupe mettre les agents -> Noména va y réfléchir (par salle et par environnement prod/pp)
|
||||
- Est-ce qu'ils voient les logs pour d'autre apps ? Ont-ils activé l'archivage des logs ? Ils auront une presta pour voir l'intégration d'applicatifs. Pas exploitable rapidement.
|
||||
- Quelle config ossec.conf ? Veulent-ils quelque chose en particulier ? Peut-être wodle docker-listener mais nécessite de redémarrer docker. Noména va y réfléchir.
|
Reference in New Issue
Block a user