diff --git a/.github/workflows/backend-build.yml b/.github/workflows/backend-build.yml
index c0682d10..f83b4674 100644
--- a/.github/workflows/backend-build.yml
+++ b/.github/workflows/backend-build.yml
@@ -2,17 +2,17 @@ name: Backend - Build & Lint
on:
push:
- branches: [main]
+ branches: [main, pre-prod]
paths:
- "backend/**/**"
pull_request:
- branches: [main]
+ branches: [main, pre-prod]
paths:
- "backend/**/**"
jobs:
lint:
- name: Static Analysis (golangci-lint)
+ name: Static Analysis (golangci-lint + gosec)
runs-on: ubuntu-latest
steps:
@@ -24,6 +24,10 @@ jobs:
go-version: "1.24.4"
cache-dependency-path: backend/gestion/go.sum
+ - name: Download dependencies
+ working-directory: backend/gestion
+ run: go mod download
+
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
continue-on-error: true
@@ -32,6 +36,14 @@ jobs:
working-directory: backend/gestion
args: --timeout=5m
+ - name: Install gosec
+ run: go install github.com/securego/gosec/v2/cmd/gosec@latest
+
+ - name: Run Gosec Security Scanner
+ working-directory: backend/gestion
+ run: gosec ./...
+ continue-on-error: true
+
build:
name: Build
needs: lint
@@ -65,7 +77,9 @@ jobs:
name: Docker Build & Push
needs: build
runs-on: ubuntu-latest
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+ if: >
+ github.event_name == 'push' &&
+ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/pre-prod')
steps:
- uses: actions/checkout@v4
@@ -86,7 +100,7 @@ jobs:
file: docker/backend/Dockerfile
target: runtime
push: true
- tags: xor1234/backend-mln:latest
+ tags: xor1234/backend-mln:${{ github.ref == 'refs/heads/main' && 'latest' || 'pre-prod' }}
- name: Build & push WAF
uses: docker/build-push-action@v6
@@ -95,7 +109,7 @@ jobs:
file: docker/backend/Dockerfile
target: waf
push: true
- tags: xor1234/backend-mln:waf
+ tags: xor1234/backend-mln:${{ github.ref == 'refs/heads/main' && 'waf' || 'waf-pre-prod' }}
deploy:
name: SSH Deploy
@@ -106,9 +120,9 @@ jobs:
- name: SSH deploy
uses: appleboy/ssh-action@v1
with:
- host: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_HOST_PROD || secrets.SERVER_HOST }}
+ host: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_HOST_PROD || secrets.SERVER_HOST_PRE_PROD }}
username: ${{ secrets.SERVER_USER }}
- key: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_SSH_KEY_PROD || secrets.SERVER_SSH_KEY }}
+ key: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_SSH_KEY_PROD || secrets.SERVER_SSH_KEY_PRE_PROD }}
script: |
docker compose -f ${{ secrets.COMPOSE_PATH }} pull backend waf
docker compose -f ${{ secrets.COMPOSE_PATH }} up -d --no-deps backend waf
diff --git a/.github/workflows/frontend-admin-build.yml b/.github/workflows/frontend-admin-build.yml
index 498c1a3a..d864d6ff 100644
--- a/.github/workflows/frontend-admin-build.yml
+++ b/.github/workflows/frontend-admin-build.yml
@@ -13,7 +13,6 @@ on:
jobs:
typecheck:
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v4
@@ -35,7 +34,6 @@ jobs:
build-apk:
needs: typecheck
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v4
@@ -46,11 +44,19 @@ jobs:
cache: npm
cache-dependency-path: frontend-admin/package-lock.json
- - name: Setup Expo & EAS CLI
- uses: expo/expo-github-action@v8
+ - name: Setup Java
+ uses: actions/setup-java@v4
with:
- eas-version: latest
- token: ${{ secrets.EXPO_TOKEN }}
+ distribution: temurin
+ java-version: 17
+
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
+
+ - name: Install EAS CLI & cache deps
+ run: |
+ npm install -g eas-cli
+ pip install -r scripts/requirements.txt --quiet
- name: Install dependencies
working-directory: frontend-admin
@@ -62,21 +68,120 @@ jobs:
jq '.expo.extra.eas.projectId = "${{ secrets.EXPO_PROJECT_ID }}"' app.json > app.tmp.json
mv app.tmp.json app.json
- - name: Build APK
+ - name: Determine build profile & env
+ id: config
+ run: |
+ if [ "${{ github.ref_name }}" = "main" ] || [ "${{ github.base_ref }}" = "main" ]; then
+ echo "profile=production" >> $GITHUB_OUTPUT
+ echo "channel=production-admin" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "update_url=${{ secrets.XAVIA_API_URL }}" >> $GITHUB_OUTPUT
+ echo "apk_name=admin-panel-production-$(date +%Y%m%d-%H%M).apk" >> $GITHUB_OUTPUT
+ else
+ echo "profile=pre-prod" >> $GITHUB_OUTPUT
+ echo "channel=pre-prod-admin" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PREPROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "update_url=${{ secrets.XAVIA_API_URL }}" >> $GITHUB_OUTPUT
+ echo "apk_name=admin-panel-pre-prod-$(date +%Y%m%d-%H%M).apk" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Restore Gradle cache (RustFS)
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ S3_ENDPOINT: https://rustfs.uber-stup.club
+ S3_BUCKET: apk-builds
+ run: python scripts/eas_cache.py restore --app frontend-admin
+
+ - name: Build APK (local)
working-directory: frontend-admin
env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ EXPO_PUBLIC_API_URL: ${{ steps.config.outputs.api_url }}
+ EXPO_PUBLIC_UPDATE_URL: ${{ steps.config.outputs.update_url }}
EAS_BUILD_NO_EXPO_GO_WARNING: true
- run: eas build --platform android ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && '--profile production' || '--profile preview' }} --non-interactive
+ GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
+ JAVA_TOOL_OPTIONS: "-Xmx4096m"
+ run: eas build --platform android --profile ${{ steps.config.outputs.profile }} --local --non-interactive
- - name: Download APK
+ - name: Save Gradle cache (RustFS)
+ if: success() || failure()
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ S3_ENDPOINT: https://rustfs.uber-stup.club
+ S3_BUCKET: apk-builds
+ run: python scripts/eas_cache.py save --app frontend-admin
+
+ - name: Rename APK
+ working-directory: frontend-admin
+ run: mv *.apk ${{ steps.config.outputs.apk_name }}
+
+ - name: Upload APK to RustFS
+ working-directory: frontend-admin
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ AWS_DEFAULT_REGION: us-east-1
+ run: |
+ aws s3 cp ${{ steps.config.outputs.apk_name }} \
+ s3://apk-builds/${{ steps.config.outputs.profile }}/${{ steps.config.outputs.apk_name }} \
+ --endpoint-url https://rustfs.uber-stup.club \
+ --no-verify-ssl
+
+ ota-update:
+ needs: build-apk
+ runs-on: ubuntu-latest
+ # Ne publie pas sur les PR, seulement sur les pushs
+ if: github.event_name == 'push'
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ cache-dependency-path: frontend-admin/package-lock.json
+
+ - name: Install dependencies
+ working-directory: frontend-admin
+ run: npm ci
+
+ - name: Determine channel & env
+ id: config
+ run: |
+ if [ "${{ github.ref_name }}" = "main" ]; then
+ echo "channel=production-admin" >> $GITHUB_OUTPUT
+ echo "api_url=https://mln-uber.club" >> $GITHUB_OUTPUT
+ echo "message=Production update $(date +%Y%m%d-%H%M)" >> $GITHUB_OUTPUT
+ else
+ echo "channel=pre-prod-admin" >> $GITHUB_OUTPUT
+ echo "api_url=https://5.181.0.112.nip.io" >> $GITHUB_OUTPUT
+ echo "message=Pre-prod update $(date +%Y%m%d-%H%M)" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Inject EAS project ID
working-directory: frontend-admin
run: |
- APK_URL=$(eas build:list --platform android --status finished --limit 1 --json --non-interactive | jq -r '.[0].artifacts.buildUrl')
- curl -L -o admin-panel-prod.apk "$APK_URL"
+ jq '.expo.extra.eas.projectId = "${{ secrets.EXPO_PROJECT_ID }}"' app.json > app.tmp.json
+ mv app.tmp.json app.json
- - name: Upload production APK artifact
- uses: actions/upload-artifact@v4
- with:
- name: admin-panel-android-prod-apk
- path: frontend-admin/admin-panel-prod.apk
- retention-days: 14
+ - name: Publish OTA update to Xavia
+ working-directory: frontend-admin
+ env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ EXPO_PUBLIC_API_URL: ${{ steps.config.outputs.api_url }}
+ EXPO_PUBLIC_UPDATE_URL: ${{ secrets.XAVIA_API_URL }}
+ run: |
+ RUNTIME_VERSION=$(jq -r '.expo.version' app.json)
+ npx expo export --platform android --output-dir dist
+ cd dist && zip -r ../bundle.zip . && cd ..
+ curl -X POST "${{ secrets.XAVIA_API_URL }}/api/upload" \
+ -H "Authorization: Bearer ${{ secrets.XAVIA_API_KEY }}" \
+ -F "file=@bundle.zip" \
+ -F "runtimeVersion=$RUNTIME_VERSION" \
+ -F "channel=${{ steps.config.outputs.channel }}" \
+ -F "commitHash=${{ github.sha }}" \
+ -F "commitMessage=${{ steps.config.outputs.message }}" \
+ --fail
diff --git a/.github/workflows/frontend-client-build.yml b/.github/workflows/frontend-client-build.yml
index 3bdeed9d..2da3bc23 100644
--- a/.github/workflows/frontend-client-build.yml
+++ b/.github/workflows/frontend-client-build.yml
@@ -13,7 +13,6 @@ on:
jobs:
typecheck:
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v4
@@ -35,7 +34,6 @@ jobs:
build-apk:
needs: typecheck
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v4
@@ -46,11 +44,19 @@ jobs:
cache: npm
cache-dependency-path: mobile/package-lock.json
- - name: Setup Expo & EAS CLI
- uses: expo/expo-github-action@v8
+ - name: Setup Java
+ uses: actions/setup-java@v4
with:
- eas-version: latest
- token: ${{ secrets.EXPO_TOKEN }}
+ distribution: temurin
+ java-version: 17
+
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
+
+ - name: Install EAS CLI & cache deps
+ run: |
+ npm install -g eas-cli
+ pip install -r scripts/requirements.txt --quiet
- name: Install dependencies
working-directory: mobile
@@ -62,25 +68,120 @@ jobs:
jq '.expo.extra.eas.projectId = "${{ secrets.EXPO_PROJECT_ID_CLIENT }}"' app.json > app.tmp.json
mv app.tmp.json app.json
- - name: Debug app.json
- working-directory: mobile
- run: cat app.json
+ - name: Determine build profile & env
+ id: config
+ run: |
+ if [ "${{ github.ref_name }}" = "main" ] || [ "${{ github.base_ref }}" = "main" ]; then
+ echo "profile=production" >> $GITHUB_OUTPUT
+ echo "channel=production-client" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "update_url=${{ secrets.XAVIA_API_URL }}" >> $GITHUB_OUTPUT
+ echo "apk_name=mobile-production-$(date +%Y%m%d-%H%M).apk" >> $GITHUB_OUTPUT
+ else
+ echo "profile=pre-prod" >> $GITHUB_OUTPUT
+ echo "channel=pre-prod-client" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PREPROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "update_url=${{ secrets.XAVIA_API_URL }}" >> $GITHUB_OUTPUT
+ echo "apk_name=mobile-pre-prod-$(date +%Y%m%d-%H%M).apk" >> $GITHUB_OUTPUT
+ fi
- - name: Build APK
+ - name: Restore Gradle cache (RustFS)
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ S3_ENDPOINT: https://rustfs.uber-stup.club
+ S3_BUCKET: apk-builds
+ run: python scripts/eas_cache.py restore --app mobile
+
+ - name: Build APK (local)
working-directory: mobile
env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ EXPO_PUBLIC_API_URL: ${{ steps.config.outputs.api_url }}
+ EXPO_PUBLIC_UPDATE_URL: ${{ steps.config.outputs.update_url }}
EAS_BUILD_NO_EXPO_GO_WARNING: true
- run: eas build --platform android ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && '--profile production' || '--profile preview' }} --non-interactive
+ GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
+ JAVA_TOOL_OPTIONS: "-Xmx4096m"
+ run: eas build --platform android --profile ${{ steps.config.outputs.profile }} --local --non-interactive
- - name: Download production APK
+ - name: Save Gradle cache (RustFS)
+ if: success() || failure()
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ S3_ENDPOINT: https://rustfs.uber-stup.club
+ S3_BUCKET: apk-builds
+ run: python scripts/eas_cache.py save --app mobile
+
+ - name: Rename APK
+ working-directory: mobile
+ run: mv *.apk ${{ steps.config.outputs.apk_name }}
+
+ - name: Upload APK to RustFS
+ working-directory: mobile
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.RUSTFS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.RUSTFS_SECRET_KEY }}
+ AWS_DEFAULT_REGION: us-east-1
+ run: |
+ aws s3 cp ${{ steps.config.outputs.apk_name }} \
+ s3://apk-builds/${{ steps.config.outputs.profile }}/${{ steps.config.outputs.apk_name }} \
+ --endpoint-url https://rustfs.uber-stup.club \
+ --no-verify-ssl
+
+ ota-update:
+ needs: build-apk
+ runs-on: ubuntu-latest
+ # Ne publie pas sur les PR, seulement sur les pushs
+ if: github.event_name == 'push'
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ cache-dependency-path: mobile/package-lock.json
+
+ - name: Install dependencies
+ working-directory: mobile
+ run: npm ci
+
+ - name: Determine channel & env
+ id: config
+ run: |
+ if [ "${{ github.ref_name }}" = "main" ]; then
+ echo "channel=production-client" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "message=Production update $(date +%Y%m%d-%H%M)" >> $GITHUB_OUTPUT
+ else
+ echo "channel=pre-prod-client" >> $GITHUB_OUTPUT
+ echo "api_url=${{ secrets.PREPROD_API_URL }}" >> $GITHUB_OUTPUT
+ echo "message=Pre-prod update $(date +%Y%m%d-%H%M)" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Inject EAS project ID
working-directory: mobile
run: |
- APK_URL=$(eas build:list --platform android --status finished --limit 1 --json --non-interactive | jq -r '.[0].artifacts.buildUrl')
- curl -L -o client-panel-prod.apk "$APK_URL"
+ jq '.expo.extra.eas.projectId = "${{ secrets.EXPO_PROJECT_ID_CLIENT }}"' app.json > app.tmp.json
+ mv app.tmp.json app.json
- - name: Upload production APK artifact
- uses: actions/upload-artifact@v4
- with:
- name: client-panel-android-prod-apk
- path: mobile/client-panel-prod.apk
- retention-days: 14
+ - name: Publish OTA update to Xavia
+ working-directory: mobile
+ env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ EXPO_PUBLIC_API_URL: ${{ steps.config.outputs.api_url }}
+ EXPO_PUBLIC_UPDATE_URL: ${{ secrets.XAVIA_API_URL }}
+ run: |
+ RUNTIME_VERSION=$(jq -r '.expo.version' app.json)
+ npx expo export --platform android --output-dir dist
+ cd dist && zip -r ../bundle.zip . && cd ..
+ curl -X POST "${{ secrets.XAVIA_API_URL }}/api/upload" \
+ -H "Authorization: Bearer ${{ secrets.XAVIA_API_KEY }}" \
+ -F "file=@bundle.zip" \
+ -F "runtimeVersion=$RUNTIME_VERSION" \
+ -F "channel=${{ steps.config.outputs.channel }}" \
+ -F "commitHash=${{ github.sha }}" \
+ -F "commitMessage=${{ steps.config.outputs.message }}" \
+ --fail
diff --git a/.github/workflows/frontend-web-build.yml b/.github/workflows/frontend-web-build.yml
index 5538fef5..26d1172e 100644
--- a/.github/workflows/frontend-web-build.yml
+++ b/.github/workflows/frontend-web-build.yml
@@ -103,9 +103,9 @@ jobs:
- name: SSH deploy
uses: appleboy/ssh-action@v1
with:
- host: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_HOST_PROD || secrets.SERVER_HOST }}
+ host: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_HOST_PROD || secrets.SERVER_HOST_PRE_PROD }}
username: ${{ secrets.SERVER_USER }}
- key: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_SSH_KEY_PROD || secrets.SERVER_SSH_KEY }}
+ key: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && secrets.SERVER_SSH_KEY_PROD || secrets.SERVER_SSH_KEY_PRE_PROD }}
script: |
docker compose -f ${{ secrets.COMPOSE_PATH }} pull frontend
docker compose -f ${{ secrets.COMPOSE_PATH }} up -d --no-deps frontend
diff --git a/monitoring/crowdsec/acquis.yaml b/monitoring/crowdsec/acquis.yaml
new file mode 100644
index 00000000..a54e4da8
--- /dev/null
+++ b/monitoring/crowdsec/acquis.yaml
@@ -0,0 +1,22 @@
+# Logs nginx depuis le container Docker
+source: docker
+container_name:
+ - monitoring_nginx
+labels:
+ type: nginx
+
+---
+# Logs SSH du VPS hôte
+source: file
+filenames:
+ - /var/log/auth.log
+labels:
+ type: syslog
+
+---
+# Logs système du VPS hôte
+source: file
+filenames:
+ - /var/log/syslog
+labels:
+ type: syslog
diff --git a/monitoring/docker-compose.yml b/monitoring/docker-compose.yml
new file mode 100644
index 00000000..47d4d5fa
--- /dev/null
+++ b/monitoring/docker-compose.yml
@@ -0,0 +1,219 @@
+services:
+ # ─── Dozzle ───────────────────────────────────────────────
+ dozzle:
+ image: amir20/dozzle:latest
+ container_name: dozzle
+ restart: unless-stopped
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ - ./dozzle/users.yml:/data/users.yml:ro
+ environment:
+ DOZZLE_AUTH_PROVIDER: simple
+ DOZZLE_AUTH_TTL: 48h
+ DOZZLE_REMOTE_AGENT: "5.181.0.112:7007|demo-uber|VPS,185.234.9.102:7007|mln-uber|VPS"
+ networks:
+ - monitoring_net
+
+ # ─── Nginx ────────────────────────────────────────────────
+ nginx:
+ image: nginx:alpine
+ container_name: monitoring_nginx
+ restart: unless-stopped
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./nginx/certs:/etc/nginx/certs:ro
+ - nginx_logs:/var/log/nginx
+ depends_on:
+ - dozzle
+ - wazuh.dashboard
+ networks:
+ - monitoring_net
+
+ # ─── Wazuh Manager ────────────────────────────────────────
+ wazuh.manager:
+ image: wazuh/wazuh-manager:4.14.5
+ hostname: wazuh.manager
+ container_name: wazuh_manager
+ restart: unless-stopped
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ nofile:
+ soft: 655360
+ hard: 655360
+ ports:
+ - "1514:1514" # Communication agents
+ - "1515:1515" # Enrôlement agents
+ - "514:514/udp" # Syslog entrant
+ environment:
+ - INDEXER_URL=https://wazuh.indexer:9200
+ - INDEXER_USERNAME=admin
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ - 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=${WAZUH_API_PASSWORD}
+ entrypoint: ["/bin/bash", "/wazuh-custom/init.sh"]
+ volumes:
+ - ./wazuh/config/wazuh_manager/:/wazuh-custom/:ro
+ - 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
+ - ./wazuh/certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
+ - ./wazuh/certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
+ - ./wazuh/certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
+ networks:
+ - monitoring_net
+
+ # ─── Wazuh Indexer (OpenSearch) ───────────────────────────
+ wazuh.indexer:
+ image: wazuh/wazuh-indexer:4.14.5
+ hostname: wazuh.indexer
+ container_name: wazuh_indexer
+ restart: unless-stopped
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ nofile:
+ soft: 65536
+ hard: 65536
+ environment:
+ - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ volumes:
+ - wazuh_indexer_data:/var/lib/wazuh-indexer
+ - ./wazuh/certs/root-ca.pem:/usr/share/wazuh-indexer/config/certs/root-ca.pem
+ - ./wazuh/certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.key
+ - ./wazuh/certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem
+ - ./wazuh/certs/admin.pem:/usr/share/wazuh-indexer/config/certs/admin.pem
+ - ./wazuh/certs/admin-key.pem:/usr/share/wazuh-indexer/config/certs/admin-key.pem
+ - ./wazuh/config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/config/opensearch.yml
+ - ./wazuh/config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/config/opensearch-security/internal_users.yml
+ networks:
+ - monitoring_net
+
+ # ─── Wazuh Dashboard ──────────────────────────────────────
+ wazuh.dashboard:
+ image: wazuh/wazuh-dashboard:4.14.5
+ hostname: wazuh.dashboard
+ container_name: wazuh_dashboard
+ restart: unless-stopped
+ environment:
+ - INDEXER_USERNAME=admin
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ - WAZUH_API_URL=https://wazuh.manager
+ - DASHBOARD_USERNAME=kibanaserver
+ - DASHBOARD_PASSWORD=${WAZUH_DASHBOARD_PASSWORD}
+ - API_USERNAME=wazuh-wui
+ - API_PASSWORD=${WAZUH_API_PASSWORD}
+ volumes:
+ - ./wazuh/certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
+ - ./wazuh/certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
+ - ./wazuh/certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
+ - ./wazuh/config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
+ depends_on:
+ - wazuh.indexer
+ - wazuh.manager
+ networks:
+ - monitoring_net
+
+ rustfs_perm:
+ image: alpine:latest
+ container_name: rustfs_perm
+ volumes:
+ - /mnt/data:/data
+ command: chown -R 1000:1000 /data
+ rustfs:
+ image: rustfs/rustfs:latest
+ depends_on:
+ rustfs_perm:
+ condition: service_completed_successfully
+ hostname: rustfs
+ container_name: rustfs
+ restart: unless-stopped
+ volumes:
+ - /mnt/data:/data
+ environment:
+ - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY:-rustfsadmin}
+ - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY:-rustfsadmin}
+ - RUSTFS_SERVER_DOMAINS=rustfs.uber-stup.club
+ - RUSTFS_CONSOLE_ENABLE=true
+ - RUSTFS_ADDRESS=:9000
+ - RUSTFS_CONSOLE_ADDRESS=:9001
+ networks:
+ - monitoring_net
+
+ # ─── Xavia OTA — PostgreSQL ───────────────────────────────
+ xavia_db:
+ image: postgres:16-alpine
+ container_name: xavia_db
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=${XAVIA_POSTGRES_USER:-xavia}
+ - POSTGRES_PASSWORD=${XAVIA_POSTGRES_PASSWORD}
+ - POSTGRES_DB=${XAVIA_POSTGRES_DB:-releases_db}
+ volumes:
+ - xavia_db_data:/var/lib/postgresql/data
+ networks:
+ - monitoring_net
+
+ # ─── Xavia OTA ────────────────────────────────────────────
+ xavia:
+ image: xaviaio/xavia-ota:latest
+ container_name: xavia
+ restart: unless-stopped
+ environment:
+ - HOST=https://ota.uber-stup.club
+ - BLOB_STORAGE_TYPE=local
+ - DB_TYPE=postgres
+ - ADMIN_PASSWORD=${XAVIA_ADMIN_PASSWORD}
+ - UPLOAD_KEY=${XAVIA_UPLOAD_KEY}
+ - PRIVATE_KEY_BASE_64=${XAVIA_PRIVATE_KEY_BASE_64}
+ - POSTGRES_USER=${XAVIA_POSTGRES_USER:-xavia}
+ - POSTGRES_PASSWORD=${XAVIA_POSTGRES_PASSWORD}
+ - POSTGRES_DB=${XAVIA_POSTGRES_DB:-releases_db}
+ - POSTGRES_HOST=xavia_db
+ - POSTGRES_PORT=5432
+ volumes:
+ - xavia_blobs:/app/blobs
+ depends_on:
+ - xavia_db
+ networks:
+ - monitoring_net
+networks:
+ monitoring_net:
+ driver: bridge
+
+volumes:
+ # Xavia
+ xavia_db_data:
+ xavia_blobs:
+ # Wazuh
+ 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:
+ nginx_logs:
diff --git a/monitoring/dozzle/users.yml b/monitoring/dozzle/users.yml
new file mode 100644
index 00000000..7dfe9194
--- /dev/null
+++ b/monitoring/dozzle/users.yml
@@ -0,0 +1,6 @@
+users:
+ admin:
+ name: Admin
+ email: admin@uber-stup.club
+ password: $2b$11$AOUC5QG2l8Ee0gUKIyZGKuHdL0iuvDa3C0bVAl2Gyt6Axx7.E/hHm
+ roles: download
diff --git a/monitoring/nginx/nginx.conf b/monitoring/nginx/nginx.conf
new file mode 100644
index 00000000..3a847a36
--- /dev/null
+++ b/monitoring/nginx/nginx.conf
@@ -0,0 +1,155 @@
+worker_processes auto;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ # Redirect HTTP -> HTTPS
+ server {
+ listen 80;
+ server_name _;
+ return 301 https://$host$request_uri;
+ }
+
+ # ── Dozzle ──────────────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name dozzle.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/dozzle_access.log;
+ error_log /var/log/nginx/dozzle_error.log;
+
+ location / {
+ proxy_pass http://dozzle:8080;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "";
+ proxy_buffering off;
+ proxy_cache off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 3600s;
+ }
+ }
+
+ # ── RustFS Console ──────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name rustfs.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/rustfs_access.log;
+ error_log /var/log/nginx/rustfs_error.log;
+
+ # Console web (port 9001)
+ location / {
+ proxy_pass http://rustfs:9001;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 300s;
+ client_max_body_size 500m;
+ }
+ }
+
+ # ── RustFS S3 API ───────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name s3.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/rustfs_s3_access.log;
+ error_log /var/log/nginx/rustfs_s3_error.log;
+
+ location / {
+ proxy_pass http://rustfs:9000;
+ proxy_http_version 1.1;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 300s;
+ client_max_body_size 2g;
+ }
+ }
+
+ # ── Xavia OTA ───────────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name ota.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/xavia_access.log;
+ error_log /var/log/nginx/xavia_error.log;
+
+ location / {
+ proxy_pass http://xavia:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 300s;
+ client_max_body_size 500m;
+ }
+ }
+
+ # ── Wazuh Dashboard ─────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name wazuh.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/wazuh_access.log;
+ error_log /var/log/nginx/wazuh_error.log;
+
+ location / {
+ proxy_pass https://wazuh.dashboard:5601;
+
+ proxy_ssl_verify off;
+
+ proxy_http_version 1.1;
+
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+
+ proxy_read_timeout 300s;
+
+ proxy_hide_header Content-Security-Policy;
+ proxy_hide_header X-Frame-Options;
+ proxy_hide_header X-XSS-Protection;
+ }
+ }
+}
diff --git a/monitoring/s3/.env b/monitoring/s3/.env
new file mode 100644
index 00000000..49a8ef53
--- /dev/null
+++ b/monitoring/s3/.env
@@ -0,0 +1,9 @@
+RUSTFS_ACCESS_KEY=iBacJPHUHSf6SMTnxrr
+RUSTFS_SECRET_KEY=4jNzZhstv1WkwTwtvR4gHSbrx01m4sJl4LBBleeJ
+
+XAVIA_ADMIN_PASSWORD=2VYfheOweyMiP510GGfjNYmq3vJGJ
+XAVIA_UPLOAD_KEY=dNW2tiNXRR6w1cLwlmCOyKFIKvoTz8xQMSyd
+XAVIA_PRIVATE_KEY_BASE_64=MlRvcGlyNHpFRjhYOTlvUjMxbHFCVHRQdjYyelh4Wnc0MDM4TkZaVQ==
+XAVIA_POSTGRES_USER=xavia
+XAVIA_POSTGRES_PASSWORD=6DzLcsb5rgWukuGdrHtRBQ222f
+XAVIA_POSTGRES_DB=releases_db
diff --git a/monitoring/s3/docker-compose-s3.yml b/monitoring/s3/docker-compose-s3.yml
new file mode 100644
index 00000000..a9fcb30a
--- /dev/null
+++ b/monitoring/s3/docker-compose-s3.yml
@@ -0,0 +1,99 @@
+services:
+ nginx:
+ image: nginx:alpine
+ container_name: s3_nginx
+ restart: unless-stopped
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./nginx/certs:/etc/nginx/certs:ro
+ - nginx_logs:/var/log/nginx
+ depends_on:
+ - rustfs
+ - xavia
+ networks:
+ - s3_net
+
+ rustfs_perm:
+ image: alpine:latest
+ container_name: rustfs_perm
+ volumes:
+ - /mnt/data:/data
+ command: chown -R 10001:10001 /data
+
+ rustfs:
+ image: rustfs/rustfs:latest
+ depends_on:
+ rustfs_perm:
+ condition: service_completed_successfully
+ hostname: rustfs
+ container_name: rustfs
+ restart: unless-stopped
+ volumes:
+ - /mnt/data:/data
+ - /mnt/logs:/logs
+ environment:
+ - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY:-iBacJPHUHSf6SMTnxrr}
+ - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY:-4jNzZhstv1WkwTwtvR4gHSbrx01m4sJl4LBBleeJ}
+ - RUSTFS_SERVER_DOMAINS=rustfs.uber-stup.club
+ - RUSTFS_CONSOLE_ENABLE=true
+ - RUSTFS_ADDRESS=:9000
+ - RUSTFS_CONSOLE_ADDRESS=:9001
+ networks:
+ - s3_net
+
+ xavia_db:
+ image: postgres:16-alpine
+ container_name: xavia_db
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=${XAVIA_POSTGRES_USER:-xavia}
+ - POSTGRES_PASSWORD=${XAVIA_POSTGRES_PASSWORD}
+ - POSTGRES_DB=${XAVIA_POSTGRES_DB:-releases_db}
+ volumes:
+ - xavia_db_data:/var/lib/postgresql/data
+ networks:
+ - s3_net
+
+ xavia:
+ image: xaviaio/xavia-ota:latest
+ container_name: xavia
+ restart: unless-stopped
+ environment:
+ - HOST=https://ota.uber-stup.club
+ - BLOB_STORAGE_TYPE=local
+ - DB_TYPE=postgres
+ - ADMIN_PASSWORD=${XAVIA_ADMIN_PASSWORD}
+ - UPLOAD_KEY=${XAVIA_UPLOAD_KEY}
+ - PRIVATE_KEY_BASE_64=${XAVIA_PRIVATE_KEY_BASE_64}
+ - POSTGRES_USER=${XAVIA_POSTGRES_USER:-xavia}
+ - POSTGRES_PASSWORD=${XAVIA_POSTGRES_PASSWORD}
+ - POSTGRES_DB=${XAVIA_POSTGRES_DB:-releases_db}
+ - POSTGRES_HOST=xavia_db
+ - POSTGRES_PORT=5432
+ volumes:
+ - xavia_blobs:/app/blobs
+ depends_on:
+ - xavia_db
+ networks:
+ - s3_net
+
+ dozzle-agent:
+ image: amir20/dozzle:latest
+ command: agent
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ ports:
+ - "7007:7007"
+ restart: unless-stopped
+
+networks:
+ s3_net:
+ driver: bridge
+
+volumes:
+ nginx_logs:
+ xavia_db_data:
+ xavia_blobs:
diff --git a/monitoring/s3/nginx/nginx.conf b/monitoring/s3/nginx/nginx.conf
new file mode 100644
index 00000000..11f90cec
--- /dev/null
+++ b/monitoring/s3/nginx/nginx.conf
@@ -0,0 +1,98 @@
+worker_processes auto;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ resolver 127.0.0.11 valid=10s ipv6=off;
+
+ # Redirect HTTP -> HTTPS
+ server {
+ listen 80;
+ server_name _;
+ return 301 https://$host$request_uri;
+ }
+
+ # ── RustFS Console ──────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name rustfs.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/rustfs_access.log;
+ error_log /var/log/nginx/rustfs_error.log;
+
+ location / {
+ set $upstream http://rustfs:9001;
+ proxy_pass $upstream;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 300s;
+ client_max_body_size 500m;
+ }
+ }
+
+ # ── RustFS S3 API ───────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name s3.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/rustfs_s3_access.log;
+ error_log /var/log/nginx/rustfs_s3_error.log;
+
+ location / {
+ set $upstream http://rustfs:9000;
+ proxy_pass $upstream;
+ proxy_http_version 1.1;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 300s;
+ client_max_body_size 2g;
+ }
+ }
+
+ # ── Xavia OTA ───────────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name ota.uber-stup.club;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/xavia_access.log;
+ error_log /var/log/nginx/xavia_error.log;
+
+ location / {
+ set $upstream http://xavia:3000;
+ proxy_pass $upstream;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 300s;
+ client_max_body_size 500m;
+ }
+ }
+}
diff --git a/monitoring/security/.env b/monitoring/security/.env
new file mode 100644
index 00000000..a69851b5
--- /dev/null
+++ b/monitoring/security/.env
@@ -0,0 +1,8 @@
+# Dozzle
+DOZZLE_USERNAME=admin_mln_monitoring
+DOZZLE_PASSWORD=dX753n05Jo4T6B66cR
+
+# Wazuh — changer TOUS ces mots de passe avant de déployer
+WAZUH_INDEXER_PASSWORD=9qB523OjLyFSp6vMpH!
+WAZUH_API_PASSWORD=myAJYqnemF544nsD33!
+WAZUH_DASHBOARD_PASSWORD=E9Jpr6586kQ3wYrCS2!
diff --git a/monitoring/security/docker-compose-security.yml b/monitoring/security/docker-compose-security.yml
new file mode 100644
index 00000000..e88b63e3
--- /dev/null
+++ b/monitoring/security/docker-compose-security.yml
@@ -0,0 +1,160 @@
+services:
+ dozzle:
+ image: amir20/dozzle:latest
+ container_name: dozzle
+ restart: unless-stopped
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ - ./dozzle/users.yml:/data/users.yml:ro
+ environment:
+ DOZZLE_AUTH_PROVIDER: simple
+ DOZZLE_AUTH_TTL: 48h
+ DOZZLE_REMOTE_AGENT: "185.103.166.112:7007|pre-prod-uber|VPS,185.103.166.119:7007|prod-uber|VPS"
+ networks:
+ - monitoring_net
+
+ nginx:
+ image: nginx:alpine
+ container_name: monitoring_nginx
+ restart: unless-stopped
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./nginx/certs:/etc/nginx/certs:ro
+ - nginx_logs:/var/log/nginx
+ depends_on:
+ - dozzle
+ - wazuh.dashboard
+ - beszel
+ networks:
+ - monitoring_net
+
+ # ─── Beszel Hub ───────────────────────────────────────────
+ beszel:
+ image: henrygd/beszel:latest
+ container_name: beszel
+ restart: unless-stopped
+ volumes:
+ - beszel_data:/beszel_data
+ networks:
+ - monitoring_net
+
+ wazuh.manager:
+ image: wazuh/wazuh-manager:4.14.5
+ hostname: wazuh.manager
+ container_name: wazuh_manager
+ restart: unless-stopped
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ nofile:
+ soft: 655360
+ hard: 655360
+ ports:
+ - "1514:1514" # Communication agents
+ - "1515:1515" # Enrôlement agents
+ - "514:514/udp" # Syslog entrant
+ environment:
+ - INDEXER_URL=https://wazuh.indexer:9200
+ - INDEXER_USERNAME=admin
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ - 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=${WAZUH_API_PASSWORD}
+ entrypoint: ["/bin/bash", "/wazuh-custom/init.sh"]
+ volumes:
+ - ./wazuh/config/wazuh_manager/:/wazuh-custom/:ro
+ - 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
+ - ./wazuh/certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
+ - ./wazuh/certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
+ - ./wazuh/certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
+ networks:
+ - monitoring_net
+
+ # ─── Wazuh Indexer (OpenSearch) ───────────────────────────
+ wazuh.indexer:
+ image: wazuh/wazuh-indexer:4.14.5
+ hostname: wazuh.indexer
+ container_name: wazuh_indexer
+ restart: unless-stopped
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ nofile:
+ soft: 65536
+ hard: 65536
+ environment:
+ - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ volumes:
+ - wazuh_indexer_data:/var/lib/wazuh-indexer
+ - ./wazuh/certs/root-ca.pem:/usr/share/wazuh-indexer/config/certs/root-ca.pem
+ - ./wazuh/certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.key
+ - ./wazuh/certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem
+ - ./wazuh/certs/admin.pem:/usr/share/wazuh-indexer/config/certs/admin.pem
+ - ./wazuh/certs/admin-key.pem:/usr/share/wazuh-indexer/config/certs/admin-key.pem
+ - ./wazuh/config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/config/opensearch.yml
+ - ./wazuh/config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/config/opensearch-security/internal_users.yml
+ networks:
+ - monitoring_net
+
+ # ─── Wazuh Dashboard ──────────────────────────────────────
+ wazuh.dashboard:
+ image: wazuh/wazuh-dashboard:4.14.5
+ hostname: wazuh.dashboard
+ container_name: wazuh_dashboard
+ restart: unless-stopped
+ environment:
+ - INDEXER_USERNAME=admin
+ - INDEXER_PASSWORD=${WAZUH_INDEXER_PASSWORD}
+ - WAZUH_API_URL=https://wazuh.manager
+ - DASHBOARD_USERNAME=kibanaserver
+ - DASHBOARD_PASSWORD=${WAZUH_DASHBOARD_PASSWORD}
+ - API_USERNAME=wazuh-wui
+ - API_PASSWORD=${WAZUH_API_PASSWORD}
+ volumes:
+ - ./wazuh/certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
+ - ./wazuh/certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
+ - ./wazuh/certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
+ - ./wazuh/config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
+ depends_on:
+ - wazuh.indexer
+ - wazuh.manager
+ networks:
+ - monitoring_net
+networks:
+ monitoring_net:
+ driver: bridge
+
+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:
+ nginx_logs:
+ beszel_data:
diff --git a/monitoring/security/dozzle/users.yml b/monitoring/security/dozzle/users.yml
new file mode 100644
index 00000000..7dfe9194
--- /dev/null
+++ b/monitoring/security/dozzle/users.yml
@@ -0,0 +1,6 @@
+users:
+ admin:
+ name: Admin
+ email: admin@uber-stup.club
+ password: $2b$11$AOUC5QG2l8Ee0gUKIyZGKuHdL0iuvDa3C0bVAl2Gyt6Axx7.E/hHm
+ roles: download
diff --git a/monitoring/security/nginx/nginx.conf b/monitoring/security/nginx/nginx.conf
new file mode 100644
index 00000000..fe53e7b8
--- /dev/null
+++ b/monitoring/security/nginx/nginx.conf
@@ -0,0 +1,108 @@
+worker_processes auto;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ resolver 127.0.0.11 valid=10s ipv6=off;
+
+ # Redirect HTTP -> HTTPS
+ server {
+ listen 80;
+ server_name _;
+ return 301 https://$host$request_uri;
+ }
+
+ # ── Dozzle ──────────────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name dozzle.demo-uber.xyz;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/dozzle_access.log;
+ error_log /var/log/nginx/dozzle_error.log;
+
+ location / {
+ set $upstream http://dozzle:8080;
+ proxy_pass $upstream;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "";
+ proxy_buffering off;
+ proxy_cache off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 3600s;
+ }
+ }
+
+ # ── Wazuh Dashboard ─────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name wazuh.demo-uber.xyz;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/wazuh_access.log;
+ error_log /var/log/nginx/wazuh_error.log;
+
+ location / {
+ set $upstream https://wazuh.dashboard:5601;
+ proxy_pass $upstream;
+
+ proxy_ssl_verify off;
+
+ proxy_http_version 1.1;
+
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+
+ proxy_read_timeout 300s;
+
+ proxy_hide_header Content-Security-Policy;
+ proxy_hide_header X-Frame-Options;
+ proxy_hide_header X-XSS-Protection;
+ }
+ }
+
+ # ── Beszel ──────────────────────────────────────────────
+ server {
+ listen 443 ssl;
+ server_name beszel.demo-uber.xyz;
+
+ ssl_certificate /etc/nginx/certs/fullchain.pem;
+ ssl_certificate_key /etc/nginx/certs/privkey.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ access_log /var/log/nginx/beszel_access.log;
+ error_log /var/log/nginx/beszel_error.log;
+
+ location / {
+ set $upstream http://beszel:8090;
+ proxy_pass $upstream;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 3600s;
+ }
+ }
+}
diff --git a/monitoring/security/wazuh/config/certs.yml b/monitoring/security/wazuh/config/certs.yml
new file mode 100644
index 00000000..077dc66a
--- /dev/null
+++ b/monitoring/security/wazuh/config/certs.yml
@@ -0,0 +1,10 @@
+nodes:
+ indexer:
+ - name: wazuh.indexer
+ ip: "wazuh.indexer"
+ server:
+ - name: wazuh.manager
+ ip: "wazuh.manager"
+ dashboard:
+ - name: wazuh.dashboard
+ ip: "wazuh.dashboard"
diff --git a/monitoring/security/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml b/monitoring/security/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml
new file mode 100644
index 00000000..d1abcf1d
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml
@@ -0,0 +1,12 @@
+server.host: 0.0.0.0
+server.port: 5601
+opensearch.hosts: https://wazuh.indexer:9200
+opensearch.ssl.verificationMode: certificate
+opensearch.ssl.certificateAuthorities: ["/usr/share/wazuh-dashboard/certs/root-ca.pem"]
+opensearch.requestHeadersWhitelist: ["securitytenant","Authorization"]
+opensearch_security.multitenancy.enabled: false
+opensearch_security.readonly_mode.roles: ["kibana_read_only"]
+server.ssl.enabled: true
+server.ssl.key: "/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem"
+server.ssl.certificate: "/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem"
+uiSettings.overrides.defaultRoute: /app/wz-home
diff --git a/monitoring/security/wazuh/config/wazuh_indexer/internal_users.yml b/monitoring/security/wazuh/config/wazuh_indexer/internal_users.yml
new file mode 100644
index 00000000..bd530c0f
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_indexer/internal_users.yml
@@ -0,0 +1,45 @@
+---
+_meta:
+ type: "internalusers"
+ config_version: 2
+
+admin:
+ hash: "$2b$12$lNbkFg7B3IN.BXwZHjztteTDd3hTIvT/kTJhRFqfUY/228Bw45POO"
+ reserved: true
+ backend_roles:
+ - "admin"
+ description: "Admin user"
+
+kibanaserver:
+ hash: "$2b$12$czi/zi7uht/K5.vcCvsXueFi6ot7GFwFfVBax7rCaNqBq1jhTOZ7u"
+ reserved: true
+ description: "Kibanaserver user"
+
+kibanaro:
+ hash: "$2b$12$lNbkFg7B3IN.BXwZHjztteTDd3hTIvT/kTJhRFqfUY/228Bw45POO"
+ reserved: false
+ backend_roles:
+ - "kibanauser"
+ - "readall"
+ description: "Kibana read-only user"
+
+logstash:
+ hash: "$2b$12$lNbkFg7B3IN.BXwZHjztteTDd3hTIvT/kTJhRFqfUY/228Bw45POO"
+ reserved: false
+ backend_roles:
+ - "logstash"
+ description: "Logstash user"
+
+readall:
+ hash: "$2b$12$lNbkFg7B3IN.BXwZHjztteTDd3hTIvT/kTJhRFqfUY/228Bw45POO"
+ reserved: false
+ backend_roles:
+ - "readall"
+ description: "Readall user"
+
+snapshotrestore:
+ hash: "$2b$12$lNbkFg7B3IN.BXwZHjztteTDd3hTIvT/kTJhRFqfUY/228Bw45POO"
+ reserved: false
+ backend_roles:
+ - "snapshotrestore"
+ description: "Snapshotrestore user"
diff --git a/monitoring/security/wazuh/config/wazuh_indexer/wazuh.indexer.yml b/monitoring/security/wazuh/config/wazuh_indexer/wazuh.indexer.yml
new file mode 100644
index 00000000..c88a6987
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_indexer/wazuh.indexer.yml
@@ -0,0 +1,51 @@
+network.host: "0.0.0.0"
+node.name: "wazuh.indexer"
+cluster.name: "wazuh-cluster"
+
+# Compatibilité Filebeat 7.x (libbeat) avec OpenSearch 2.x
+# Filebeat envoie _type dans les requêtes bulk — OpenSearch 2.x le rejette
+# sans ce flag.
+compatibility.override_main_response_version: true
+
+path.data: /var/lib/wazuh-indexer
+path.logs: /var/log/wazuh-indexer
+
+plugins.security.ssl.http.pemcert_filepath: /usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem
+plugins.security.ssl.http.pemkey_filepath: /usr/share/wazuh-indexer/config/certs/wazuh.indexer.key
+plugins.security.ssl.http.pemtrustedcas_filepath: /usr/share/wazuh-indexer/config/certs/root-ca.pem
+plugins.security.ssl.transport.pemcert_filepath: /usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem
+plugins.security.ssl.transport.pemkey_filepath: /usr/share/wazuh-indexer/config/certs/wazuh.indexer.key
+plugins.security.ssl.transport.pemtrustedcas_filepath: /usr/share/wazuh-indexer/config/certs/root-ca.pem
+plugins.security.ssl.http.enabled: true
+plugins.security.ssl.transport.enforce_hostname_verification: false
+plugins.security.ssl.transport.resolve_hostname: false
+
+plugins.security.authcz.admin_dn:
+ - "CN=admin,OU=Wazuh,O=Wazuh,L=California,C=US"
+plugins.security.nodes_dn:
+ - "CN=wazuh.indexer,OU=Wazuh,O=Wazuh,L=California,C=US"
+
+plugins.security.check_snapshot_restore_write_privileges: true
+plugins.security.enable_snapshot_restore_privilege: true
+plugins.security.restapi.roles_enabled:
+ - "all_access"
+ - "security_rest_api_access"
+
+plugins.security.system_indices.enabled: true
+plugins.security.system_indices.indices:
+ - ".opendistro-alerting-config"
+ - ".opendistro-alerting-alert*"
+ - ".opendistro-anomaly-results*"
+ - ".opendistro-anomaly-detector*"
+ - ".opendistro-anomaly-checkpoints"
+ - ".opendistro-anomaly-detection-state"
+ - ".opendistro-reports-*"
+ - ".opendistro-notifications-*"
+ - ".opendistro-notebooks"
+ - ".opensearch-observability"
+ - ".opendistro-asynchronous-search-response*"
+ - ".replication-metadata-store"
+
+discovery.type: single-node
+plugins.security.allow_default_init_securityindex: true
+cluster.routing.allocation.disk.threshold_enabled: false
diff --git a/monitoring/security/wazuh/config/wazuh_manager/decoders/modsecurity_decoder.xml b/monitoring/security/wazuh/config/wazuh_manager/decoders/modsecurity_decoder.xml
new file mode 100644
index 00000000..b796f1e4
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/decoders/modsecurity_decoder.xml
@@ -0,0 +1,4 @@
+
+
+ UNUSED_MODSEC_PLACEHOLDER_NEVER_MATCHES
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/init.sh b/monitoring/security/wazuh/config/wazuh_manager/init.sh
new file mode 100644
index 00000000..25ecb054
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/init.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -e
+
+# ─── Copie de la config custom (montée hors du volume wazuh_etc) ──────────────
+CUSTOM=/wazuh-custom
+
+cp "$CUSTOM/ossec.conf" /var/ossec/etc/ossec.conf
+
+mkdir -p /var/ossec/etc/decoders /var/ossec/etc/rules
+cp "$CUSTOM/decoders/"*.xml /var/ossec/etc/decoders/ 2>/dev/null || true
+cp "$CUSTOM/rules/"*.xml /var/ossec/etc/rules/ 2>/dev/null || true
+
+# ─── Démarrage Wazuh Manager (entrypoint original) ────────────────────────────
+exec /init
diff --git a/monitoring/security/wazuh/config/wazuh_manager/ossec.conf b/monitoring/security/wazuh/config/wazuh_manager/ossec.conf
new file mode 100644
index 00000000..15df776b
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/ossec.conf
@@ -0,0 +1,638 @@
+
+
+
+
+ yes
+ yes
+ no
+ no
+ no
+ 10m
+ 0
+
+
+
+
+ 3
+
+
+
+
+ plain
+
+
+
+
+ secure
+ 1514
+ tcp
+ 131072
+
+
+
+
+ no
+ yes
+ yes
+ yes
+ yes
+ yes
+ yes
+ yes
+ 43200
+ etc/rootcheck/rootkit_files.txt
+ etc/rootcheck/rootkit_trojans.txt
+ yes
+
+
+
+ yes
+ 1800
+ 1d
+ yes
+ wodles/java
+ wodles/ciscat
+
+
+
+ yes
+ yes
+ /var/log/osquery/osqueryd.results.log
+ /etc/osquery/osquery.conf
+ yes
+
+
+
+
+ no
+ 1h
+ yes
+ yes
+ yes
+ yes
+ yes
+ yes
+ yes
+
+ 10
+
+
+
+
+
+ yes
+ yes
+ 12h
+ yes
+
+
+
+
+ yes
+ yes
+ 60m
+
+
+
+
+ yes
+
+ https://wazuh.indexer:9200
+
+
+
+ /etc/ssl/root-ca.pem
+
+ /etc/ssl/filebeat.pem
+ /etc/ssl/filebeat.key
+
+
+
+
+
+ no
+ 43200
+ yes
+ yes
+ no
+ /etc,/usr/bin,/usr/sbin
+ /bin,/sbin,/boot
+ /etc/mtab
+ /etc/hosts.deny
+ /etc/mail/statistics
+ /etc/random-seed
+ /etc/random.seed
+ /etc/adjtime
+ /etc/httpd/logs
+ /etc/utmpx
+ /etc/wtmpx
+ /etc/cups/certs
+ /etc/dumpdates
+ /etc/svc/volatile
+ .log$|.swp$
+ /etc/ssl/private.key
+ yes
+ yes
+ yes
+ yes
+ 10
+ 100
+
+ yes
+ 5m
+ 1h
+ 10
+
+
+
+
+
+ 127.0.0.1
+ ^localhost.localdomain$
+ 90.50.148.138
+
+
+
+
+ disable-account
+ disable-account
+ yes
+
+
+
+ restart-wazuh
+ restart-wazuh
+
+
+
+ firewall-drop
+ firewall-drop
+ yes
+
+
+
+ host-deny
+ host-deny
+ yes
+
+
+
+ route-null
+ route-null
+ yes
+
+
+
+ win_route-null
+ route-null.exe
+ yes
+
+
+
+ netsh
+ netsh.exe
+ yes
+
+
+
+ clamav-quarantine
+ clamav-quarantine
+ no
+
+
+
+
+
+
+ firewall-drop
+ local
+ 5710,5711,5712,5716,5720,5760,5763
+ 0
+
+
+
+
+ firewall-drop
+ local
+ authentication_failures
+ 0
+
+
+
+
+ firewall-drop
+ local
+ authentication_failed
+ 0
+
+
+
+
+ host-deny
+ local
+ 5710,5711,5712,5716,5720,5760,5763
+ 0
+
+
+
+
+ firewall-drop
+ local
+ 7
+ web,attack
+ 300
+
+
+
+
+ firewall-drop
+ local
+ 1002,2502,2503,2504
+ 3600
+
+
+
+
+ host-deny
+ local
+ authentication_failures,authentication_failed
+ 0
+
+
+
+
+ firewall-drop
+ local
+ 100202,100203,100205
+ 21600
+
+
+
+
+ firewall-drop
+ local
+ 100204,100206
+ 86400
+
+
+
+
+ clamav-quarantine
+ local
+ 52502
+
+
+
+
+ firewall-drop
+ local
+ 100210
+ 86400
+
+
+
+
+ firewall-drop
+ local
+ 100300
+ 3600
+
+
+
+
+ firewall-drop
+ local
+ 100301
+ 86400
+
+
+
+
+ disable-account
+ local
+ 100310
+ 7200
+
+
+
+ firewall-drop
+ local
+ 100310
+ 21600
+
+
+
+ no
+ host-deny
+ all
+ 100210
+ 86400
+
+
+
+ firewall-drop
+ all
+ 100204,100206
+ 86400
+
+
+
+ firewall-drop
+ all
+ 5710,5711,5712,5716,5720,5760,5763
+ 0
+
+
+
+
+ firewall-drop
+ all
+ authentication_failures
+ 0
+
+
+
+
+ firewall-drop
+ all
+ authentication_failed
+ 0
+
+
+
+
+ host-deny
+ all
+ 5710,5711,5712,5716,5720,5760,5763
+ 0
+
+
+
+
+ firewall-drop
+ all
+ 7
+ web,attack
+ 300
+
+
+
+
+ firewall-drop
+ all
+ 1002,2502,2503,2504
+ 3600
+
+
+
+
+ host-deny
+ all
+ authentication_failures,authentication_failed
+ 0
+
+
+
+
+ firewall-drop
+ all
+ 100202,100203,100205
+ 21600
+
+
+
+
+ firewall-drop
+ all
+ 100300
+ 3600
+
+
+
+
+ firewall-drop
+ all
+ 100301
+ 86400
+
+
+
+
+ command
+ df -P
+ 360
+
+
+
+ full_command
+ netstat -tulpn | sed 's/\([[:alnum:]]\+\)\ \+[[:digit:]]\+\ \+[[:digit:]]\+\ \+\(.*\):\([[:digit:]]*\)\ \+\([0-9\.\:\*]\+\).\+\ \([[:digit:]]*\/[[:alnum:]\-]*\).*/\1 \2 == \3 == \4 \5/' | sort -k 4 -g | sed 's/ == \(.*\) ==/:\1/' | sed 1,2d
+ netstat listening ports
+ 360
+
+
+
+ full_command
+ last -n 20
+ 360
+
+
+
+
+
+ ruleset/decoders
+ ruleset/rules
+
+ 0025-sendmail_rules.xml
+ 0030-postfix_rules.xml
+ 0035-spamd_rules.xml
+ 0040-imapd_rules.xml
+ 0045-mailscanner_rules.xml
+ 0050-ms-exchange_rules.xml
+ 0055-courier_rules.xml
+ 0065-pix_rules.xml
+ 0070-netscreenfw_rules.xml
+ 0075-cisco-ios_rules.xml
+ 0080-sonicwall_rules.xml
+ 0090-telnetd_rules.xml
+ 0100-solaris_bsm_rules.xml
+ 0105-asterisk_rules.xml
+ 0110-ms_dhcp_rules.xml
+ 0115-arpwatch_rules.xml
+ 0130-trend-osce_rules.xml
+ 0135-hordeimp_rules.xml
+ 0155-dovecot_rules.xml
+ 0160-vmpop3d_rules.xml
+ 0165-vpopmail_rules.xml
+ 0170-ftpd_rules.xml
+ 0175-proftpd_rules.xml
+ 0185-vsftpd_rules.xml
+ 0190-ms_ftpd_rules.xml
+ 0195-named_rules.xml
+ 0215-policy_rules.xml
+ 0750-github_rules.xml
+ 0250-apache_rules.xml
+ 0255-zeus_rules.xml
+ 0265-php_rules.xml
+ 0275-squid_rules.xml
+ 0295-mysql_rules.xml
+ 0305-dropbear_rules.xml
+ 0315-apparmor_rules.xml
+ 0350-amazon_rules.xml
+ 0360-serv-u_rules.xml
+ 0385-oscap_rules.xml
+ 0390-fortiddos_rules.xml
+ 0391-fortigate_rules.xml
+ 0392-fortimail_rules.xml
+ 0393-fortiauth_rules.xml
+ 0120-symantec-av_rules.xml
+ 0125-symantec-ws_rules.xml
+ 0395-hp_rules.xml
+ 0405-rsa-auth-manager_rules.xml
+ 0410-imperva_rules.xml
+ 0415-sophos_rules.xml
+ 0990-amazon-security-lake_rules.xml
+ 0435-ms_logs_rules.xml
+ 0445-identity_guard_rules.xml
+ 0450-mongodb_rules.xml
+ 0460-jenkins_rules.xml
+ 0470-vshell_rules.xml
+ 0475-suricata_rules.xml
+ 0480-qualysguard_rules.xml
+ 0485-cylance_rules.xml
+ 0700-paloalto_rules.xml
+ 0500-owncloud_rules.xml
+ 0505-vuls_rules.xml
+ 0525-openvas_rules.xml
+ 0530-mysql_audit_rules.xml
+ 0535-mariadb_rules.xml
+ 0540-pfsense_rules.xml
+ 0545-osquery_rules.xml
+ 0550-kaspersky_rules.xml
+ 0555-azure_rules.xml
+ 0565-ms_ipsec_rules.xml
+ 0575-win-base_rules.xml
+ 0580-win-security_rules.xml
+ 0585-win-application_rules.xml
+ 0590-win-system_rules.xml
+ 0601-win-vipre_rules.xml
+ 0602-win-wfirewall_rules.xml
+ 0610-win-ms_logs_rules.xml
+ 0630-nextcloud_rules.xml
+ 0675-panda-paps_rules.xml
+ 0680-checkpoint-smart1_rules.xml
+ 0770-gitlab_rules.xml
+ 0775-arbor_rules.xml
+ 0780-fireeye_rules.xml
+ 0785-huawei-usg_rules.xml
+ 0800-sysmon_id_1.xml
+ 0810-sysmon_id_3.xml
+ 0820-sysmon_id_7.xml
+ 0830-sysmon_id_11.xml
+ 0840-win_event_channel.xml
+ 0860-sysmon_id_13.xml
+ 0870-sysmon_id_8.xml
+ 0905-cisco-ftd_rules.xml
+ 0690-gcp_rules.xml
+ 0910-ms-exchange-proxylogon_rules.xml
+ 0920-oracledb_rules.xml
+ 0925-eset-remote_rules.xml
+ 0955-WEF-baseline_rules.xml
+ 0960-macos_rules.xml
+ 0995-microsoft-graph_rules.xml
+ 0755-office365_rules.xml
+ 0140-roundcube_rules.xml
+ 0998-aws-security-hub-rules.xml
+ 0400-openvpn_rules.xml
+ etc/lists/audit-keys
+ etc/lists/amazon/aws-eventnames
+ etc/lists/security-eventchannel
+ etc/lists/malicious-ioc/malicious-ip
+ etc/lists/malicious-ioc/malicious-domains
+ etc/lists/malicious-ioc/malware-hashes
+
+ etc/decoders
+ etc/rules
+
+
+
+
+ yes
+ 1
+ 64
+ 15m
+
+
+
+
+ no
+ 1515
+ no
+ yes
+ no
+ HIGH:!ADH:!EXP:!MD5:!RC4:!3DES:!CAMELLIA:@STRENGTH
+ no
+ etc/sslmanager.cert
+ etc/sslmanager.key
+ no
+
+
+
+
+ wazuh
+ node01
+ master
+ aa093264ef885029653eea20dfcf51ae
+ 1516
+ 0.0.0.0
+
+ wazuh.manager
+
+ no
+ yes
+
+
+
+
+
+
+ syslog
+ /var/ossec/logs/active-responses.log
+
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/rules/local_active_response_rules.xml b/monitoring/security/wazuh/config/wazuh_manager/rules/local_active_response_rules.xml
new file mode 100644
index 00000000..ea942f32
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/rules/local_active_response_rules.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ 5716
+
+ SSH: brute-force — 3 mots de passe faux en 60s depuis $(srcip)
+ authentication_failures,ssh_brute,
+
+
+
+
+ 5710
+
+ SSH: scan de comptes — 3 users inexistants en 60s depuis $(srcip)
+ authentication_failures,ssh_scan,
+
+
+
+
+
+
+
+
+
+ 5401
+
+ Sudo: 3 échecs d'auth en 5 min — tentative d'escalade de privilèges
+ authentication_failures,sudo_brute,
+
+
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/rules/local_modsecurity_rules.xml b/monitoring/security/wazuh/config/wazuh_manager/rules/local_modsecurity_rules.xml
new file mode 100644
index 00000000..706803a5
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/rules/local_modsecurity_rules.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ json
+ modsec_audit.log
+ \.+
+ ModSecurity: WAF event capturé
+ web,modsecurity,
+
+
+
+
+ 100100
+ ^403$
+ ModSecurity: accès bloqué (403) — $(transaction.client_ip) → $(transaction.request.uri)
+ web,modsecurity,attack,blocked,
+
+
+
+
+ 100100
+ ModSecurity: règle WAF déclenchée (non bloqué) — $(transaction.client_ip)
+ web,modsecurity,attack,
+
+
+
+
+ 100102
+ ModSecurity: blocages répétés — possible scan ou attaque soutenue
+ web,modsecurity,attack,blocked,
+
+
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/rules/local_sca_noise.xml b/monitoring/security/wazuh/config/wazuh_manager/rules/local_sca_noise.xml
new file mode 100644
index 00000000..fa1c4085
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/rules/local_sca_noise.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+ 19000
+ ^summary
+ no_full_log
+ SCA summary — supprimé (voir onglet SCA du dashboard).
+
+
+
+ 19001
+ ^8\d
+ no_full_log
+ SCA summary: score < 90% — supprimé.
+
+
+
+ 19001
+ ^7\d|^6\d|^5\d
+ no_full_log
+ SCA summary: score < 80% — supprimé.
+
+
+
+ 19001
+ ^4\d|^3\d
+ no_full_log
+ SCA summary: score < 50% — supprimé.
+
+
+
+ 19001
+ ^2\d|^1\d$|^\d$
+ no_full_log
+ SCA summary: score < 30% — supprimé.
+
+
+
+
+ 19006
+ ^failed
+ no_full_log
+ SCA check failed — supprimé.
+
+
+
+ 19006
+ ^passed
+ no_full_log
+ SCA check passed — supprimé.
+
+
+
+ 19006
+ ^not applicable
+ no_full_log
+ SCA check not applicable — supprimé.
+
+
+
+
+ 19008
+ ^failed
+ no_full_log
+ SCA: failed → passed — supprimé.
+
+
+
+ 19007
+ ^passed
+ no_full_log
+ SCA: passed → failed — supprimé.
+
+
+
+ 19009
+ ^passed
+ no_full_log
+ SCA: passed → not applicable — supprimé.
+
+
+
+ 19009
+ ^failed
+ no_full_log
+ SCA: failed → not applicable — supprimé.
+
+
+
+ 19007
+ ^not applicable
+ no_full_log
+ SCA: not applicable → failed — supprimé.
+
+
+
+ 19008
+ ^not applicable
+ no_full_log
+ SCA: not applicable → passed — supprimé.
+
+
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/rules/local_ssh_pam_noise.xml b/monitoring/security/wazuh/config/wazuh_manager/rules/local_ssh_pam_noise.xml
new file mode 100644
index 00000000..cd719a7a
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/rules/local_ssh_pam_noise.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+ 2900
+ Dpkg: supprimé.
+
+
+ 2900
+ Dpkg: supprimé.
+
+
+ 2900
+ Dpkg: supprimé.
+
+
+ 2900
+ Dpkg: supprimé.
+
+
+
+
+
+
+
+ 5715
+ 90.50.148.138
+ sshd: auth success IP admin — supprimé.
+
+
+
+
+
+
+
+
+ 5500
+ session opened for user
+ PAM: Login session opened (bruit supprimé).
+
+
+
+
+ 5500
+ session closed for user
+ PAM: Login session closed (bruit supprimé).
+
+
+
+
+
+
+
+
+
+ 5700
+ fatal: Timeout before authentication for
+ sshd: Timeout individuel supprimé (fréquence 5705 active).
+
+
+
+
+ 5700
+ Did not receive identification string from
+ sshd: Sonde sans identification (bruit de scan supprimé).
+
+
+
+
+ 5700
+ Connection reset by peer$
+ sshd: Connection reset by peer (bruit supprimé).
+
+
+
+
+ 5700
+ Connection refused$
+ sshd: Connection refused (bruit supprimé).
+
+
+
+
+ 5700
+ ^Bad packet length
+ sshd: Bad packet length (bruit de scan supprimé).
+
+
+
+
+ 5700
+ Connection reset
+ sshd: Connection reset (bruit supprimé).
+
+
+
+
+
+
+
+ WAZUH_PLACEHOLDER_SURICATA_NEVER_MATCHES
+ Suricata: malicious domain — overwrite placeholder (non applicable).
+
+
+ WAZUH_PLACEHOLDER_SURICATA_DNS_NEVER_MATCHES
+ Suricata: malicious domain DNS — overwrite placeholder (non applicable).
+
+
+
+
+
+ WAZUH_PLACEHOLDER_WINDOWS_FAILED_NEVER_MATCHES
+ Windows: failed logon malicious IP — overwrite placeholder (non applicable).
+
+
+ WAZUH_PLACEHOLDER_WINDOWS_SUCCESS_NEVER_MATCHES
+ Windows: successful logon malicious IP — overwrite placeholder (non applicable).
+
+
diff --git a/monitoring/security/wazuh/config/wazuh_manager/rules/modsecurity_rules.xml b/monitoring/security/wazuh/config/wazuh_manager/rules/modsecurity_rules.xml
new file mode 100644
index 00000000..b22bca25
--- /dev/null
+++ b/monitoring/security/wazuh/config/wazuh_manager/rules/modsecurity_rules.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ 100102
+ SQL Injection\|SQLi\|942[0-9]
+ ModSecurity: SQL Injection bloquée — $(transaction.client_ip) → $(transaction.request.uri)
+ modsecurity_sqli,sql_injection,
+
+
+
+
+ 100102
+ XSS\|941[0-9]
+ ModSecurity: XSS bloqué — $(transaction.client_ip) → $(transaction.request.uri)
+ modsecurity_xss,xss,
+
+
+
+
+ 100102
+ RCE\|930[0-9]\|932[0-9]
+ ModSecurity: tentative RCE bloquée — $(transaction.client_ip) → $(transaction.request.uri)
+ modsecurity_rce,rce,
+
+
+
+
+ 100102
+ LFI\|930[0-9]
+ ModSecurity: LFI bloqué — $(transaction.client_ip) → $(transaction.request.uri)
+ modsecurity_lfi,lfi,
+
+
+
+
+ 100102
+ ModSecurity: blocages répétés en 2 min — attaque soutenue
+ modsecurity_repeated,
+
+
+
diff --git a/monitoring/security/wazuh/generate-certs.sh b/monitoring/security/wazuh/generate-certs.sh
new file mode 100755
index 00000000..4fcebfff
--- /dev/null
+++ b/monitoring/security/wazuh/generate-certs.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+CERTS_DIR="$SCRIPT_DIR/certs"
+
+mkdir -p "$CERTS_DIR"
+cd /tmp
+
+echo "[*] Téléchargement de l'outil de génération de certificats Wazuh..."
+curl -sO https://packages.wazuh.com/4.14/wazuh-certs-tool.sh
+cp "$SCRIPT_DIR/config/certs.yml" config.yml
+
+echo "[*] Génération des certificats..."
+bash wazuh-certs-tool.sh -A
+
+echo "[*] Copie des certificats..."
+cp /tmp/wazuh-certificates/*.pem "$CERTS_DIR/"
+cp /tmp/wazuh-certificates/root-ca.pem "$CERTS_DIR/root-ca-manager.pem"
+
+chmod 640 "$CERTS_DIR"/*.pem
+rm -rf /tmp/wazuh-certificates /tmp/wazuh-install-files /tmp/wazuh-install-files.tar /tmp/wazuh-certs-tool.sh /tmp/config.yml
+
+echo "[OK] Certificats générés dans $CERTS_DIR"