From 27558d7651f906d41bc7b98f559bf3dc33a95b6f Mon Sep 17 00:00:00 2001 From: Xor290 Date: Wed, 10 Jun 2026 13:58:38 +0200 Subject: [PATCH] chore: update ci --- .github/workflows/backend-build.yml | 30 +- .github/workflows/frontend-admin-build.yml | 139 +++- .github/workflows/frontend-client-build.yml | 141 +++- .github/workflows/frontend-web-build.yml | 4 +- monitoring/crowdsec/acquis.yaml | 22 + monitoring/docker-compose.yml | 219 ++++++ monitoring/dozzle/users.yml | 6 + monitoring/nginx/nginx.conf | 155 +++++ monitoring/s3/.env | 9 + monitoring/s3/docker-compose-s3.yml | 99 +++ monitoring/s3/nginx/nginx.conf | 98 +++ monitoring/security/.env | 8 + .../security/docker-compose-security.yml | 160 +++++ monitoring/security/dozzle/users.yml | 6 + monitoring/security/nginx/nginx.conf | 108 +++ monitoring/security/wazuh/config/certs.yml | 10 + .../wazuh_dashboard/opensearch_dashboards.yml | 12 + .../config/wazuh_indexer/internal_users.yml | 45 ++ .../config/wazuh_indexer/wazuh.indexer.yml | 51 ++ .../decoders/modsecurity_decoder.xml | 4 + .../wazuh/config/wazuh_manager/init.sh | 14 + .../wazuh/config/wazuh_manager/ossec.conf | 638 ++++++++++++++++++ .../rules/local_active_response_rules.xml | 45 ++ .../rules/local_modsecurity_rules.xml | 39 ++ .../wazuh_manager/rules/local_sca_noise.xml | 113 ++++ .../rules/local_ssh_pam_noise.xml | 133 ++++ .../wazuh_manager/rules/modsecurity_rules.xml | 44 ++ monitoring/security/wazuh/generate-certs.sh | 24 + 28 files changed, 2329 insertions(+), 47 deletions(-) create mode 100644 monitoring/crowdsec/acquis.yaml create mode 100644 monitoring/docker-compose.yml create mode 100644 monitoring/dozzle/users.yml create mode 100644 monitoring/nginx/nginx.conf create mode 100644 monitoring/s3/.env create mode 100644 monitoring/s3/docker-compose-s3.yml create mode 100644 monitoring/s3/nginx/nginx.conf create mode 100644 monitoring/security/.env create mode 100644 monitoring/security/docker-compose-security.yml create mode 100644 monitoring/security/dozzle/users.yml create mode 100644 monitoring/security/nginx/nginx.conf create mode 100644 monitoring/security/wazuh/config/certs.yml create mode 100644 monitoring/security/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml create mode 100644 monitoring/security/wazuh/config/wazuh_indexer/internal_users.yml create mode 100644 monitoring/security/wazuh/config/wazuh_indexer/wazuh.indexer.yml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/decoders/modsecurity_decoder.xml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/init.sh create mode 100644 monitoring/security/wazuh/config/wazuh_manager/ossec.conf create mode 100644 monitoring/security/wazuh/config/wazuh_manager/rules/local_active_response_rules.xml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/rules/local_modsecurity_rules.xml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/rules/local_sca_noise.xml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/rules/local_ssh_pam_noise.xml create mode 100644 monitoring/security/wazuh/config/wazuh_manager/rules/modsecurity_rules.xml create mode 100755 monitoring/security/wazuh/generate-certs.sh 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"