Aufgabe: Installation und Konfiguration von Microsoft Defender for Endpoint on Linux für eine Oracle Datenbank Umgebung auf RedHat 7 / 8
Warum macht das Sinn? Gute Frage, es wird gefordert und damit umgesetzt .. evtl. hilft es ja am Ende doch etwas.
Der Name des Kommandos unter Linux bedeutet: Microsoft Defender ATP endpoint detection and response (EDR) , abgekürzt MDATP .
Übersicht über die Umgebung:
Normalerweise würde man erwarten, das sich der Defender an der Firmen Management Console vom Defender anmeldet und von dort verwaltet werden kann.
Leider ist das so noch nicht implementiert, ohne direkten Zugriff der Maschine auf die Microsoft Cloud funktioniert das nicht! D.h. dies ist eine reine Cloud Lösung!
Die Installation vom Defender ist auf dem Microsoft Seiten sehr gut beschrieben, daher wird hier nur der generelle Ablauf mit Ansible beschrieben.
Die Ansible Installation wird in vier Schritte aufgeteilt.
Schritt 1 - MS Repository einrichten
Schritt 2 - Defender installieren
Schritt 3 - Defender konfigurieren
Schritt 4 - Defender Update
Schritt 1 bis 3 wird dann in einem Workflow in Tower zusammen gefasst, Schritt 4 als Schedule alle 3 Wochen aufgerufen.
Lizenz Daten aus dem 365 Portal laden und die Datei „WindowsDefenderATPOnboardingPackage.zip“ herunterladen.
Keyfile microsoft.asc für das Microsoft Repo herunterladen ⇒ https://packages.microsoft.com/keys/microsoft.asc
Python 3.7 als TGZ herunterladen ⇒ https://www.python.org/ftp/python/3.7.11/Python-3.7.11.tgz
Microsoft Repository im Forman registrieren, damit diese nicht direkt von MS heruntergeladen werden müssen.
Dateien Python-3.7.11/Python-3.7.11.tgz / WindowsDefenderATPOnboardingPackage.zi„ / microsoft.asc auf dem Ansible Tower hinterlegen.
Das die MS Repos auch benötigt werden um z.B einen DB Link auf eine SQL Server DB einzurichten ist dieser Schritt in einem eigenen Playbook zusammen gefasst.
Als Vorbereitung die Pool IDS ermitteln! (subscription-manager list –available )
--- - name: check if yum is working and register the microsoft repositories hosts: all become: yes become_user: root tasks: - name: Install packages ansible.builtin.yum: name: - unzip - yum-utils state: present - name: reread all repostioris ansible.builtin.command: argv: - /usr/sbin/subscription-manager - list - --available - name: Check if the 7 repo still exits ansible.builtin.shell: /usr/sbin/subscription-manager repos | grep "Microsoft Repo 7" register: repo7exists ignore_errors: true - name: Result of repo 7 Test debug: msg="Microsoft Repo 7 still registered" when: repo7exists.rc == 0 - name: Add Microsoft Repository for Redhat 7 ansible.builtin.command: argv: - /usr/sbin/subscription-manager - attach - --pool=2c9fa5b47569b04401812974ef080567 when: ( ansible_os_family == "RedHat" and ansible_distribution_major_version == "7") and repo7exists.rc == 1 - name: Check if the 8 repo still exits ansible.builtin.shell: /usr/sbin/subscription-manager repos | grep "Microsoft Repo 8" register: repo8exists ignore_errors: true - name: Result of repo 8 test debug: msg="Microsoft Repo 8 still registered" when: repo8exists.rc == 0 - name: Add Microsoft Repository for Redhat 8 ansible.builtin.command: argv: - /usr/sbin/subscription-manager - attach - --pool=2c9fa5b47569b04401866662810e88059 when: ( ansible_os_family == "RedHat" and ansible_distribution_major_version == "8") and repo8exists.rc == 1 - name: copy the Microsoft Key ansible.builtin.template: src: templates/microsoft.asc dest: /root/microsoft.asc owner: root group: root mode: '0644' - name : Install the key ansible.builtin.command: argv: - /usr/bin/rpm - -import - /root/microsoft.asc - name : refesch yum cache ansible.builtin.command: argv: - /usr/bin/yum - makecache
Im Template Verzeichnis wird der Microsoft Key hinterlegt.
Ablauf:
--- - name: Setup Microsoft defender hosts: all become: yes become_user: root vars: pyInstallDir : "/srv/python37_install/" tasks: - name: check if defender is still installed ansible.builtin.stat: path: /etc/opt/microsoft/mdatp/mdatp_onboard.json register: mdatp_onboard - name: end Play if defender still exits ansible.builtin.meta: end_play when: mdatp_onboard.stat.exists # Setup prerequisites - name: Install packages ansible.builtin.yum: name: - openssl-devel - bzip2-devel - libffi-devel - zlib-devel - xz-devel - yum-utils state: present # Install Python-37 - name: Check if Python3.7 can be called ansible.builtin.shell: python3.7 -V register: phytonExists ignore_errors: true - name: create install directory ansible.builtin.file: path: "{{ pyInstallDir }}" state: directory when: phytonExists.rc != "0" - name: extract Phyton Source File ansible.builtin.unarchive: src: "{{item}}" dest: "{{ pyInstallDir }}" remote_src: no with_fileglob: - /srv/defender_install/Python-3.7.11.tgz when: phytonExists.rc != "0" - name: compile python ansible.builtin.command: "{{ pyInstallDir }}/Python-3.7.11/configure --enable-optimizations" args: chdir: "{{ pyInstallDir }}/Python-3.7.11" when: phytonExists.rc != "0" - name: compile python ansible.builtin.command: make altinstall args: chdir: "{{ pyInstallDir }}/Python-3.7.11" when: phytonExists.rc != "0" #Install Defender - name: Create MDATP directories ansible.builtin.file: path: /etc/opt/microsoft/mdatp/ recurse: true state: directory mode: 0755 owner: root group: root - name: Register mdatp_onboard.json ansible.builtin.stat: path: /etc/opt/microsoft/mdatp/mdatp_onboard.json register: mdatp_onboard - name: Extract Licence File ansible.builtin.unarchive: src: "{{item}}" dest: /etc/opt/microsoft/mdatp remote_src: no with_fileglob: - /srv/defender_install/WindowsDefenderATPOnboardingPackage.zip when: not mdatp_onboard.stat.exists - name: install defender ansible.builtin.yum: name: - mdatp state: present - name: register defender lic ansible.builtin.command: "python3.7 /etc/opt/microsoft/mdatp/MicrosoftDefenderATPOnboardingLinuxServer.py" args: chdir: /etc/opt/microsoft/mdatp - name: Test Scan wit EICAR String ansible.builtin.command: echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/test.txt - name: list all threads ansible.builtin.command: mdatp threat list register: mdatp_result - name: Check thread tesult debug: msg: "Defender has dedect {{ mdatp_result }}" - name: disable realtime protection - full configuration will be done later ansible.builtin.command: mdatp config real-time-protection --value disabled
Nach der Installation sollte der Server auf dem https://security.microsoft.com/machines Portal in der eigenen Organisation erscheinen.
Mit der ersten Virus Erkennung wird der Server auch dann in der lokalen Management Console vom Defenderer angezeigt.
Es wird konfiguriert:
Abweichend vom default:
In einer Datenbank und WLS Umgebung sollten die Oracle DB und WLS Dateien nicht gesannt werden!
D.h. im laufenden System ist zu prüfen, welche Prozesse auf der Maschine aktiv sind um diese dann auszuschließen:
ps afx
Alle *.jar , *.war, *.ear Files
Alle Directory die nur DB Objekte enthalten
Im Speicher alle Datenbank Prozesse
siehe dazu auch ⇒ How To Configure Anti-Virus On Oracle Database Server (Doc ID 782354.1)
Alle *.jar , *.war, *.ear Files
Server log files: <DomainHome>/servers/<ServerInstance>/logs/*.log*
Lock files:
Persistence store files: *.dat or *.DAT in any directory in oder unter <DomainHome>/servers/<ServerInstance>/data/store/
LDAP data files:
Da mein Domain Home : /app/oracle/mw/user_projects/domains/fr_domain/ ergibt sich darauf die folgende Liste:
Im Speicher alle WLS Prozesse wie:
Warum dieser führende „*“ in der Liste? Die Frage ist ja wie der Defender den Prozesse identifiziert, in der Prozessliste stehen ja beim WebLogic viele Parameter, das ist je keine einzelner Demon Prozess der aus einer Binary Datei besteht sondern es werden ja Java Prozesse mit Parametern gestartet. Hoffe der Defender matched das auf den ganzen Namen des Prozesses in der Prozesslist und nicht nur auf das Programm das ursprünglich den Prozesse gestartet hat. In der Doku wird das so genau nicht beschrieben.
siehe auch auf MetaLink
Alternativ werde ich wohl ein Schell Skript schreiben, das entweder die Json Datei erzeugt oder über mdatp Befehle die Ausnahmen einträgt, bei vielen Server gibt es doch immer wieder kleine Unterschied, die dann alles per Hand gepflegt werden müssen und die Datei immer größer werden lassen.
Für die Details
Konfiguration liegt unter /etc/opt/microsoft/mdatp/managed/mdatp_managed.json .
Verwirrend finde ich das kein Unterschied zwischen einer Datei und einem Prozess in der Konfiguration gemacht wird!
Eine mdatp_managed.json Datei:
{ "antivirusEngine": { "enforcementLevel": "real_time", "diagnosticLevel": "optional", "automaticSampleSubmissionConsent": "none", "scanAfterDefinitionUpdate": false, "scanArchives": true, "maximumOnDemandScanThreads": 4, "exclusionsMergePolicy": "merge", "exclusions": [ { "$type": "excludedPath", "isDirectory": true, "path": "/dev/shm" }, { "$type": "excludedPath", "isDirectory": true, "path": "/daten/*DB*" }, { "$type": "excludedPath", "isDirectory": true, "path": "/daten/ctl" }, { "$type": "excludedPath", "isDirectory": true, "path": "/daten/dbf" }, { "$type": "excludedPath", "isDirectory": true, "path": "/daten/wls" }, { "$type": "excludedPath", "isDirectory": true, "path": "/app/oracle/19c/dbs" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/*DB*" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/fast/recover_area" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/ctl" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/wls" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/arc" }, { "$type": "excludedPath", "isDirectory": true, "path": "/sicher/rdo" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/servers/*/logs/*.log*" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/*.lok" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/config/*.lok" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/tmp/*.lok" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/servers/*/data/store/*/*.DAT" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/servers/*/data/ldap/ldapfiles/*.data" }, { "$type": "excludedPath", "isDirectory": false, "path": "/app/oracle/mw/user_projects/domains/fr_domain/servers/*/data/ldap/ldapfiles/*.index" }, { "$type": "excludedFileName", "name": "oracle*" }, { "$type": "excludedFileName", "name": "/app/oracle/19c/bin/tnslsnr" }, { "$type": "excludedFileName", "name": "/usr/bin/vmtoolsd" }, { "$type": "excludedFileName", "name": "/opt/oracle.ahf/jre/bin/java" }, { "$type": "excludedFileName", "name": "/usr/sbin/httpd" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/bin/frmweb" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/bin/frmweb" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/bin/rwserver" }, { "$type": "excludedFileName", "name": "/opt/omi/bin/omiserver" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/wlserver/server/bin/*" }, { "$type": "excludedFileName", "name": "*/app/oracle/mw/user_projects/domains/*" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/ohs/bin/httpd*" }, { "$type": "excludedFileName", "name": "/app/oracle/mw/ohs/bin/odl_rotatelogs*" }, { "$type": "excludedFileName", "name": "/app/oracle/bi/wlserver/server/bin/*" }, { "$type": "excludedFileName", "name": "ora_*_*" }, { "$type": "excludedFileName", "name": "*OSWatcherFM.sh*" }, { "$type": "excludedFileExtension", "extension": ".war" }, { "$type": "excludedFileExtension", "extension": ".jar" }, { "$type": "excludedFileExtension", "extension": ".ear" }, { "$type": "excludedFileExtension", "extension": ".check_if_v24_can_processed" } ], "nonExecMountPolicy": "unmute", "threatTypeSettingsMergePolicy": "merge", "threatTypeSettings": [ { "key": "potentially_unwanted_application", "value": "block" }, { "key": "archive_bomb", "value": "audit" } ] } }
Nach jeder Anpassung auf JSON Syntax Fehler prüfen!
python -m json.tool mdatp_managed.json
Es ist in den MDATP Logfiles vor lauter „normalen“ Fehlen sehr schwer zu erkennen, ob nun der Defender eine neue Konfiguration einließt oder nicht.
Ein grep auf „error“ in /var/log/microsoft/mdatp findet nach einen Defender Neustart sehr, sehr viele unklare Fehler, d.h. hier müsste Microsoft dringend in „mdatp“ einen Parameter aufnehmen, der einem zeigt ob das Config File auch wirklich valid ist.
So ist es etwas mühsam zu erkennen, ob das überhaupt geklappt hat.
Und man merkt auch gleich, das man mal wieder vor den Ansible Lauf vergessen hat die Datei überhaupt zu commiten .
Es werden doch recht viel Log Einträge geschrieben, die werden dann zwar automatisch nach /var/log/microsoft/mdatp/rotated verschoben (bei ca. 500MB Größe) aber es werden mehr und mehr….
D.h. es muss ein Job eingerichtet werden der hier aufräumt.
Skript:
#!/bin/sh FILES=/var/log/microsoft/mdatp/rotated/* LOG_FILE=/tmp/defender_delete_logs_list.log DATE_NOW_EPOCH=`date +%s` #Get the epoch 3 Month ago DATE_DELETE_OLDER=`date --date "now -3 months" +"%s"` echo "Info - check the age of the file - start at -- `date` -- " > $LOG_FILE for f in $FILES do #File date as epoch FILE_DATE=`stat -c %Y ${f}` FILE_LOG_DATE=`stat -c %y ${f}` if [[ $FILE_DATE -lt $DATE_DELETE_OLDER ]]; then echo "Info - delete :: ${FILE_LOG_DATE} ${f}" >> $LOG_FILE rm ${f} fi done echo "Info - finish at -- `date` -- " >> $LOG_FILE
Das kann dann automatisiert regelmäßig laufen und die Umgebung „säubern“, wird zusammen mit der Konfig mit Ansible auch gleich verteilt.
Im ersten Schritt wird die Konfig verteilt und der Scan Cron Job eingerichtet:
--- - name: Configure Microsoft defender hosts: all become: yes become_user: root tasks: - name: Copy the Configuration File to the host ansible.builtin.template: src: templates/mdatp_managed.json.j2 dest: /etc/opt/microsoft/mdatp/managed/mdatp_managed.json owner: root group: root mode: '0644' - name: create crontab entry for quick scan all 2 days ansible.builtin.cron: name: 'Scan with defender' job: '"/bin/mdatp scan quick" > /tmp/defender_scan_quick.log 2> /dev/null' minute: '30' hour: '2' weekday: '2,4' user: root state: present - name: create crontab entry for full scan on weekend ansible.builtin.cron: name: 'Scan with defender' job: '"/bin/mdatp scan full" > /tmp/defender_scan_full.log 2> /dev/null' minute: '30' hour: '6' weekday: '6' user: root state: present - name: check if Directory exist and create if needed ansible.builtin.file: path: /root/bin owner: root group: root state: directory - name: Copy Clean Log Script ansible.builtin.template: src: templates/delete_defender_log_older_then.sh dest: /root/bin/delete_defender_log_older_then.sh owner: root group: root mode: '0744' - name: create crontab entry for logfile handling ansible.builtin.cron: name: 'Clean old defender logfiles older than 3 month' job: '"/root/bin/delete_defender_log_older_then.sh" > /tmp/defender_crontab_clean_logs.log 2> /dev/null' minute: '30' hour: '4' weekday: '1,3,5' user: root state: present
Nach einer gewissen Zeit (6 Monate?) läuft der Defender ab und muss neu installiert werden:
mdatp health --field product_expiration Jul 05, 2023 at 09:59:00 AM
Daher wird min. alle 3 Wochen mit einem Ansible Tower Job nach einer neuen Version gesucht ein Update durchgeführt.
--- - name: Update Microsoft defender hosts: all become: yes become_user: root tasks: - name: install defender ansible.builtin.yum: name: - mdatp state: latest
systemctl status mdatp:
systemctl status mdatp ● mdatp.service - Microsoft Defender Loaded: loaded (/usr/lib/systemd/system/mdatp.service; enabled; vendor preset: disabled) Active: active (running) since Sat 2022-11-05 19:02:45 CET; 5h 24min ago Main PID: 108088 (wdavdaemon) CGroup: /system.slice/mdatp.service ├─108088 /opt/microsoft/mdatp/sbin/wdavdaemon ├─108133 /opt/microsoft/mdatp/sbin/wdavdaemon edr 11 10 --log_level info ├─110685 /opt/microsoft/mdatp/sbin/telemetryd_v2 33" └─125261 /opt/microsoft/mdatp/sbin/wdavdaemon unprivileged 23 25 27 29 19 --log_level info Nov 05 19:02:45 bvmwls32.bo-it.de systemd[1]: Started Microsoft Defender.
mdatp connectivity test
mdatp connectivity test Testing connection with https://cdn.x.cp.wd.microsoft.com/ping ... [OK] Testing connection with https://eu-cdn.x.cp.wd.microsoft.com/ping ... [OK] Testing connection with https://wu-cdn.x.cp.wd.microsoft.com/ping ... [OK] Testing connection with https://nf.smartscreen.microsoft.com/api/network/mac ... [OK] Testing connection with https://unitedstates.x.cp.wd.microsoft.com/api/report ... [OK] Testing connection with https://usseu1northprod.blob.core.windows.net ... [OK] Testing connection with https://usseu1westprod.blob.core.windows.net ... [OK] Testing connection with https://europe.smartscreen.microsoft.com/api/network/mac ... [OK] Testing connection with https://europe.smartscreen-prod.microsoft.com/api/network/mac ... [OK] Testing connection with https://go.microsoft.com/fwlink/?linkid=2144709 ... [OK] Testing connection with https://winatp-gw-weu.microsoft.com/test ... [OK] Testing connection with https://winatp-gw-neu.microsoft.com/test ... [OK] Testing connection with https://eu-v20.events.data.microsoft.com/ping ... [OK] Testing connection with https://automatedirstrprdneu.blob.core.windows.net ... [OK] Testing connection with https://automatedirstrprdweu.blob.core.windows.net ... [OK]
Diese Server müssen dann freigeschaltet sein, bzw. dafür ein Proxy in der Konfiguration hinterlegt werden!
Mit „mdatp health“ die Laufzeit Konfiguration vom Defender anzeigen lassen und zu Beispiel bei „real_time_protection_enabled“ auf den Zusatz „[managed]“ achten!
mdatp health
mdatp health healthy : true ... passive_mode_enabled : false [managed] real_time_protection_enabled : true [managed]
Exklusion anzeigen lassen:
mdatp exclusion list ===================================== Excluded folder Path: "/app/oracle/19c/dbs" .. --- Excluded process Process name: oracle* =====================================
Unter: /var/log/microsoft/mdatp/
Virus erzeugen:
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/test.txt
Manuell scannen:
mdatp scan custom --path /tmp/test.txt
Erkennung testen mit mdatp threat list
mdatp threat list Id: "5df00da4-b15c-42af-ba9f-a2d690983ee9" Name: Virus:DOS/EICAR_Test_File Type: "virus" Detection time: Sat Nov 5 19:06:35 2022 Status: "quarantined" Path: "/tmp/test.txt" File size: 69 Sha256 hash: 131f95c51cc819465fa1797f6ccacf9d494aaaff46fa3eac73ae63ffbdfd8267
Datei liegt dann mit der ID „5df00da4-b15c-42af-ba9f-a2d690983ee9“ unter /var/opt/microsoft/mdatp/quarantine
ls /var/opt/microsoft/mdatp/quarantine 5df00da4-b15c-42af-ba9f-a2d690983ee9
Gelegentlich fällt der „wdavdaemon“ in der Prozessliste mit hohen CPU Verbrauch auf.
Siehe für das Parser Script ⇒ https://learn.microsoft.com/de-de/microsoft-365/security/defender-endpoint/linux-support-perf?view=o365-worldwide
# Parser Script holen wget -c https://raw.githubusercontent.com/microsoft/mdatp-xplat/master/linux/diagnostic/high_cpu_parser.py #Rechte vergeben chmod 744 high_cpu_parser.py #Daten aus dem Defender auslesen mdatp diagnostic real-time-protection-statistics --output json > real_time_protection.json #Daten Parsen cat real_time_protection.json | python high_cpu_parser.py > real_time_protection.log #Ergebniss auswerten head -n 10 real_time_protection.log
In der Liste wird angezeit
Die mit hoher Anzahl an Scan Vorgängen prüfen und dann in den Exclude aufnehmen, damit diese nicht mehr gescannt werden.
Linux 7
yum install yum-utils yum-config-manager --add-repo=https://packages.microsoft.com/config/rhel/7/prod.repo rpm --import http://packages.microsoft.com/keys/microsoft.asc yum repolist yum --enablerepo=packages-microsoft-com-prod install mdatp
Linux 8
yum install yum-utils yum-config-manager --add-repo=https://packages.microsoft.com/config/rhel/8/prod.repo yum repolist rpm --import http://packages.microsoft.com/keys/microsoft.asc yum --enablerepo=packages-microsoft-com-prod install mdatp
Onboarding in der Oberfläche, Datei WindowsDefenderATPOnboardingPackage.zip herunterladen
Einbinden mit:
mdatp health --field org_id unzip WindowsDefenderATPOnboardingPackage.zip python3 MicrosoftDefenderATPOnboardingLinuxServer.py mdatp health --field org_id
Doku
Microsoft Repo einrichten
Bei Installations-Problemen