# LIAM NTFS AdditionalConfiguration Blacklist / Whitelist - Technischer Entwurf ## Ziel Dieses Dokument beschreibt einen kleinen technischen Entwurf, um dem NTFS-Provider ueber `AdditionalConfiguration` eine Blacklist und spaeter optional auch eine Whitelist fuer NTFS-Pfade mitzugeben. Die Policy soll klassifizierungsunabhaengig arbeiten und damit fuer Shares, DFS-Links, DFS-Namespaces und Folder dieselbe Matching-Logik verwenden. ## Ausgangslage Der NTFS-Provider verfuegt heute bereits ueber `AdditionalConfiguration`, nutzt diese im NTFS-Code aber im Wesentlichen nur fuer boolesche Feature-Flags. Die Ermittlung der DataAreas erfolgt aktuell rekursiv ueber: - Root-Aufbau in `getDataAreasAsync()` - Kind-Ermittlung in `GetChildDataAreasAsync()` - Dateisystem-Enumeration je Ebene ueber `ntfsBase.RequestFoldersListAsync(parentPath, 1)` Der bestehende Filter `ShouldIncludeDataArea()` wirkt nur auf den `DisplayName` und basiert auf `DataAreaRegEx`. Das ist fuer gezielte Ordnerausschluesse fachlich und technisch zu grob. ## Zielbild Die neue Logik soll eine explizite Pfad-Policy fuer den NTFS-Provider einfuehren. Diese Policy entscheidet fuer jeden gefundenen Pfad: - darf als DataArea materialisiert werden - darf weiter traversiert werden Ein ausgeschlossener Pfad soll weder als DataArea geliefert noch weiter traversiert werden. ## Vorgeschlagene Konfigurationsschluessel ### Aktueller Stand - `NtfsExcludePaths` - `NtfsIncludePaths` Beispiel: ```text NtfsExcludePaths=Archiv;*\Temp;Abteilung\Alt;\\server\share\legacy\* NtfsIncludePaths=Fachbereiche\*;Shares\Produktion\*;\\server\dfs\namespace\link\* ``` ## Aktueller Implementierungsstand Die nachfolgend beschriebene Path-Policy ist im NTFS-Provider inzwischen implementiert. ### 1. Materialisierung und Traversierung sind getrennt In `GetChildDataAreasAsync()` wird pro gefundenem Pfad heute getrennt entschieden: - darf der Pfad als DataArea geliefert werden - darf unterhalb des Pfads weiter traversiert werden Das ist wichtig fuer Include-Regeln. Ein Zwischenpfad darf fuer die Traversierung erlaubt sein, auch wenn erst ein tiefer liegendes Zielobjekt tatsaechlich auf der Whitelist steht. ### 2. Matching ist klassifizierungsunabhaengig Die Path-Policy arbeitet fuer: - `ServerRoot` - `ClassicShare` - `DfsNamespaceRoot` - `DfsLink` - `Folder` mit derselben Matching-Logik. Die Klassifikation bleibt fuer die fachliche Verarbeitung der DataArea relevant, nicht mehr fuer Blacklist-/Whitelist-Matching. ### 3. Relative und absolute Pfade werden parallel ausgewertet Jeder klassifizierte Pfad wird gegen mehrere Kandidaten gematcht: - relativer Pfad unterhalb von `RootPath` - normalisierter absoluter UNC-Pfad Dadurch koennen Regeln sowohl knapp relativ als auch explizit absolut formuliert werden. ### 4. Include-Regeln duerfen Traversierungs-Vorpfade freischalten Wenn `NtfsIncludePaths` gesetzt ist, darf ein Pfad auch dann traversiert werden, wenn er selbst noch nicht final matcht, aber zu einem spaeter passenden Zielpfad fuehren kann. Beispiel: ```text NtfsIncludePaths=Abteilung\IT\* ``` Dann darf `Abteilung` fuer die Traversierung erhalten bleiben, damit `Abteilung\IT\TeamA` ueberhaupt erreicht werden kann. ### 5. `LoadDataArea()` respektiert die Policy Direktes Laden eines Pfads ueber `LoadDataArea()` wird ebenfalls durch die Path-Policy eingeschraenkt. Ausnahme: - der konfigurierte `RootPath` selbst bleibt ladbar Damit kann die Filterung nicht einfach durch direktes Laden einer UID umgangen werden. ### 6. Permission-Management bleibt fachlich auf Folder beschraenkt `IsPermissionManagedFolderPath()` verwendet dieselbe generische Path-Policy, bleibt aber weiterhin nur fuer als `Folder` klassifizierte Pfade zulaessig. Die Path-Policy ist also klassifizierungsunabhaengig, das Berechtigungs-Handling selbst aber bewusst nicht. ### 7. Automatisches Permission-Ensure und Traverse `EnsureNtfsPermissionGroups` wird ebenfalls ueber `AdditionalConfiguration` gesteuert. Die Werte kommen aus `C4IT_GCC_DataArea_Collector_AdditionalAttributes` und werden beim Provider-Aufbau in `AdditionalConfiguration` uebernommen. Wenn `EnsureNtfsPermissionGroups=1` gesetzt ist, wird beim Laden von NTFS-Folder-DataAreas der Soll-Zustand fuer Berechtigungsgruppen sichergestellt: - Owner-/Write-/Read-Gruppen werden angelegt oder wiederverwendet - fehlende NTFS-ACLs werden auf dem Zielordner gesetzt - Traverse-Gruppen werden analog zur Ordner-Neuanlage verarbeitet Damit ist der nachtraegliche Ensure-Pfad fachlich mit der bestehenden Ordner-Neuanlage gleichgezogen. Share-Pfade bleiben gesondert ueber `EnsureNtfsPermissionGroupsForShares` behandelt; Traverse wird dabei nicht implizit fuer Shares erweitert. ### 8. Optionale Traverse-Boundary Die neue Einstellung `NtfsTraverseBoundaryPath` ist optional und wird ebenfalls aus `AdditionalConfiguration` gelesen. Ohne `NtfsTraverseBoundaryPath` bleibt die bestehende Traverse-Reichweite unveraendert. Die Verarbeitung folgt dann der bisherigen `baseFolder`-/`createTraverseGroupLvl`-Logik der Ordner-Neuanlage. Mit `NtfsTraverseBoundaryPath` kann die sichtbare Parent-Kette explizit erweitert werden. Die Traverse-Verarbeitung laeuft dann vom Parent des Zielordners bis inklusive dieser Boundary. Beispiel: ```text RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2 EnsureNtfsPermissionGroups=1 NtfsTraverseBoundaryPath=\\SRVWSM001.imagoverum.com\file_shares ``` Fuer den Zielordner: ```text \\SRVWSM001.imagoverum.com\file_shares\share2\test33 ``` werden Traverse-Gruppen und Parent-ACLs fuer folgende Pfade sichergestellt: - `\\SRVWSM001.imagoverum.com\file_shares\share2` - `\\SRVWSM001.imagoverum.com\file_shares` Nicht verarbeitet wird der Serverroot `\\SRVWSM001.imagoverum.com`. Die Boundary muss ein Parent-Pfad des Zielordners sein und erreichbar sein. Ist das nicht der Fall, bricht der Ensure-/Create-Vorgang mit einer klaren Fehlermeldung ab, bevor Gruppen oder ACLs veraendert werden. ### 9. Traverse-Naming-Platzhalter Fuer Traverse-Naming-Conventions gibt es zusaetzliche optionale Platzhalter: - `{{TRAVERSE_NAME}}`: Name des aktuell verarbeiteten Traverse-Parents, z.B. `share2` - `{{TRAVERSE_VISIBLEPATH}}`: sichtbarer Parent-Pfad ab dem Parent der Boundary, segmentweise mit `_`, z.B. `file_shares_share2` Bestehende Platzhalter wie `{{NAME}}` und `{{RELATIVEPATH}}` bleiben unveraendert und behalten ihre bisherige Bedeutung. Beispiel fuer eine Traverse-Namenskonvention: ```text {{ADGroupPrefix}}_{{SCOPETAG}}_{{TRAVERSE_VISIBLEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}} ``` Bei: ```text ADGroupPrefix=ACL Filesystem_GroupGlobalTag=G Filesystem_GroupTraverseTag=_T ``` entstehen daraus z.B.: ```text ACL_G_FILE_SHARES_T ACL_G_FILE_SHARES_SHARE2_T ``` Wenn das Traverse-`NamingTemplate` leer ist, ist das kein Fehler. Es wird dann keine neue Traverse-Gruppe angelegt. Bestehende Gruppen werden aber weiterhin ueber ACLs und, sofern gepflegt, ueber `Wildcard` gesucht und konfiguriert. Sind `NamingTemplate` und `Wildcard` leer, ist die Traverse-Verarbeitung fuer diesen Parent ein No-op. Der Scope von Traverse-Gruppen wird aus der NTFS-Gruppenstrategie abgeleitet: - `Ntfs_AGP`: Traverse-Gruppen werden als Global-Gruppen erstellt - `Ntfs_AGDLP`: Traverse-Gruppen werden als DomainLocal-Gruppen erstellt Wenn mehrere Traverse-Naming-Conventions vorhanden sind, wird die zur Strategie passende Konvention bevorzugt. Ist keine passende Konvention vorhanden, wird die vorhandene Traverse-Konvention weiterverwendet, der Scope aber trotzdem strategy-driven gesetzt. ### 10. Root-Path-Platzhalter Naming Conventions koennen zusaetzlich Bestandteile des konfigurierten `RootPath` verwenden. Die Platzhalter funktionieren in `NamingTemplate`, `DescriptionTemplate` und `Wildcard`. Fuer: ```text RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2 Zielpfad=\\SRVWSM001.imagoverum.com\file_shares\share2\test33 ``` stehen folgende Root-Platzhalter zur Verfuegung: - `{{ROOT_SERVER}}`: Serveranteil, z.B. `SRVWSM001.imagoverum.com` - `{{ROOT_NAME}}`: letzter Root-Segmentname, z.B. `share2` - `{{ROOT_PATH}}`: alle Root-Segmente nach dem Server, z.B. `file_shares_share2` - `{{ROOT_PATH(1)}}`: die letzten `n` Root-Segmente, z.B. `share2` - `{{ROOT_PATH(2)}}`: z.B. `file_shares_share2` - `{{ROOT_SEGMENT(0)}}`: erstes Root-Segment nach dem Server, z.B. `file_shares` - `{{ROOT_SEGMENT(1)}}`: zweites Root-Segment nach dem Server, z.B. `share2` Root-Segmente werden wie Ordnersegmente sanitisiert. Leerzeichen und Bindestriche werden standardmaessig zu `_`. Nicht vorhandene `ROOT_SEGMENT(n)`-Werte werden zu einem leeren String. Wenn `ROOT_PATH(n)` mehr Segmente anfordert als vorhanden sind, werden alle vorhandenen Root-Segmente verwendet. Beispiel: ```text {{ADGroupPrefix}}_{{ROOT_NAME}}.{{NAME}}{{GROUPTYPEPOSTFIX}} ``` ergibt fuer die Owner-Gruppe des Zielordners: ```text ACL_SHARE2.TEST33_O ``` Alternativ mit Namespace-/Root-Anteil: ```text {{ADGroupPrefix}}_{{ROOT_PATH(2)}}.{{NAME}}{{GROUPTYPEPOSTFIX}} ``` ergibt: ```text ACL_FILE_SHARES_SHARE2.TEST33_O ``` Die bestehenden Platzhalter `{{NAME}}`, `{{RELATIVEPATH}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}` bleiben unveraendert. ### 11. Konfigurierbares Sanitizing und Gross-/Kleinschreibung fuer NTFS-Gruppennamen Die Normalisierung der dynamischen Pfadbestandteile wird ueber `AdditionalConfiguration` gesteuert. Die Werte kommen wie `EnsureNtfsPermissionGroups` aus `C4IT_GCC_DataArea_Collector_AdditionalAttributes`. `NtfsGroupNameSanitizeReplacement` steuert das Ersatz-/Trennzeichen fuer dynamische Pfadbestandteile: - nicht gesetzt: AD-kritische Zeichen werden durch `_` ersetzt und Pfadsegmente werden mit `_` verbunden - gesetzt auf z.B. `.`: AD-kritische Zeichen werden durch `.` ersetzt und Pfadsegmente werden mit `.` verbunden - gesetzt auf einen leeren Wert, ``, `empty`, `none` oder `remove`: AD-kritische Zeichen werden entfernt und Pfadsegmente ohne Trennzeichen verbunden Als AD-kritisch gelten in dynamischen Pfadbestandteilen derzeit Whitespace, Bindestrich, Steuerzeichen sowie `/ \ [ ] : ; | = , + * ? < > @ ( ) ' "`. Diese Zeichen sind fuer AD-`sAMAccountName`, LDAP-DNs/Search-Filter oder Entra-/Graph-kompatible Gruppennamen problematisch. `.` und `_` bleiben erhalten. Die Einstellung wirkt auf `{{NAME}}`, `{{RELATIVEPATH}}`, `{{ROOT_*}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}`. Sie aendert nicht die statischen Zeichen, die direkt im Naming Template stehen. Soll z.B. zwischen Root und Ordner immer ein Punkt stehen, bleibt der Punkt Bestandteil des Templates. Beispiel: ```text RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2 Zielpfad=\\SRVWSM001.imagoverum.com\file_shares\share2\test-33 NamingTemplate={{ADGroupPrefix}}_{{ROOT_NAME}}.{{NAME}}{{GROUPTYPEPOSTFIX}} NtfsGroupNameSanitizeReplacement= ``` ergibt bei deaktivierter automatischer Grossschreibung: ```text ACL_share2.test33_O ``` `PreserveNtfsAdGroupNameCase=1` unterbindet die bisher automatische Grossschreibung der erzeugten AD-Gruppennamen. Ohne diesen Schalter bleibt das bisherige Verhalten erhalten und die generierten CN-/sAMAccountName-Werte werden in Grossbuchstaben erzeugt. ### 12. Domain-Controller-Pinning fuer direkte AD-Readbacks Der NTFS-Provider pinnt seine AD-Zugriffe auf einen konkreten Domain Controller, damit neu angelegte Gruppen unmittelbar im gleichen oder in einem direkt folgenden Workflow-Lauf wieder gefunden werden koennen. Ohne Pinning kann Windows bei getrennten WF-Instanzen unterschiedliche DCs auswaehlen; bei langen AD-Replikationsintervallen waeren frisch angelegte Gruppen dann auf dem zweiten DC noch nicht sichtbar. Standardverhalten ohne Konfiguration: - der Provider ermittelt automatisch den PDC Emulator der Domain - alle NTFS-AD-Zugriffe innerhalb des Provider-Laufs verwenden diesen DC - der verwendete DC wird einmal beim AD-Logon im Debug-Log ausgegeben Optional kann ueber `AdditionalConfiguration` eine priorisierte, kommagetrennte DC-Liste gesetzt werden: ```text NtfsAdDomainControllers=dc01.imagoverum.com,dc02.imagoverum.com ``` Der Provider testet die Eintraege in Reihenfolge. Der erste erreichbare DC wird verwendet. Wenn kein konfigurierter DC erreichbar ist, faellt der Provider auf den automatisch ermittelten PDC Emulator zurueck. Wenn auch dieser nicht ermittelt werden kann, wird wie bisher die Domain selbst verwendet und damit wieder der Windows-DC-Locator genutzt. ## Matching-Regeln Empfohlene Semantik: - Trennzeichen fuer Mehrfachwerte: `;` - Auswertung case-insensitive - Leerzeichen an Eintraegen vor dem Match trimmen - Matching gegen relative Pfade unter `RootPath` und gegen normalisierte absolute UNC-Pfade - Interne Normalisierung auf konsistente UNC-/Directory-Notation - Zunaechst nur einfache Wildcards `*` unterstuetzen, keine freien Regex-Ausdruecke - Include-Regeln duerfen fuer die Traversierung auch uebergeordnete Pfade freischalten, wenn diese zu einem spaeter passenden Zielpfad fuehren Empfohlene Prioritaet: 1. Wenn keine Include-Regel gesetzt ist, sind alle Pfade grundsaetzlich erlaubt. 2. Wenn Include-Regeln gesetzt sind, sind nur passende Pfade erlaubt. 3. Exclude-Regeln werden danach angewendet und gewinnen bei Kollision. Das entspricht dem aktuell implementierten Verhalten. ## Beispiele ### 1. Einzelnen Teilbaum ausschliessen Konfiguration: ```text NtfsExcludePaths=Abteilung\Alt\* ``` Wirkung: - `Abteilung\Alt` und alles darunter wird nicht mehr als DataArea geliefert - unterhalb von `Abteilung\Alt` wird auch nicht weiter traversiert - andere Teilbaeume bleiben unveraendert sichtbar ### 2. Bestimmte Ordnernamen ueberall ausschliessen Konfiguration: ```text NtfsExcludePaths=*\Temp;*\Archiv ``` Wirkung: - jeder Pfad, dessen letzter oder einer spaeteren Segmente `Temp` oder `Archiv` entspricht, wird ausgeschlossen - das ist praktisch fuer technische oder historische Unterordner, die in vielen Shares gleich benannt sind ### 3. Nur einen Fachbereich sichtbar lassen Konfiguration: ```text NtfsIncludePaths=Fachbereiche\HR\* ``` Wirkung: - nur Pfade unterhalb von `Fachbereiche\HR` werden als DataAreas geliefert - notwendige Zwischenpfade wie `Fachbereiche` duerfen fuer die Traversierung erhalten bleiben - alle anderen Teilbaeume unterhalb von `RootPath` fallen aus der Ergebnismenge ### 4. Whitelist und Blacklist kombinieren Konfiguration: ```text NtfsIncludePaths=Fachbereiche\IT\* NtfsExcludePaths=Fachbereiche\IT\Test;Fachbereiche\IT\Alt\* ``` Wirkung: - grundsaetzlich ist nur `Fachbereiche\IT` relevant - innerhalb dieses Bereichs werden `Test` und der komplette Teilbaum `Alt` wieder ausgeschlossen - Exclude gewinnt also auch innerhalb eines eingeschraenkten Include-Bereichs ### 5. Absoluten UNC-Pfad fuer DFS-Link verwenden Konfiguration: ```text NtfsIncludePaths=\\server\dfs\namespace\link\Produktion\* ``` Wirkung: - die Regel greift auch dann, wenn der Root ueber DFS klassifiziert wird - benoetigte Vorpfade wie `\\server\dfs`, `\\server\dfs\namespace` und `\\server\dfs\namespace\link` duerfen fuer die Traversierung erhalten bleiben - dadurch kann ein bestimmter DFS-Zweig sehr gezielt freigegeben werden ### 6. Nur bestimmte Shares unter einem Server-Root zulassen Konfiguration: ```text NtfsIncludePaths=ShareA\*;ShareB\* ``` Voraussetzung: - `RootPath` zeigt auf einen Server-Root wie `\\fileserver` Wirkung: - nur Kinder unterhalb von `ShareA` und `ShareB` werden sichtbar - andere Shares des Servers werden nicht materialisiert und nicht weiter traversiert ### 7. Direktes Laden eines ausgeschlossenen Pfads Konfiguration: ```text NtfsExcludePaths=Abteilung\Alt\* ``` Wirkung: - ein direkter `LoadDataArea()` auf einen Pfad unterhalb von `Abteilung\Alt` liefert kein Objekt mehr - der konfigurierte `RootPath` selbst bleibt davon ausgenommen und kann weiterhin geladen werden ## Technische Einhaengepunkte ### 1. Provider-seitige Policy-Methoden Im NTFS-Provider existiert dafuer inzwischen eine kleine Policy-Schicht, insbesondere: - `GetAdditionalConfigurationValues(string key)` - `ShouldIncludeDataArea(...)` - `ShouldTraverseDataArea(...)` - `MatchesPathPolicy(...)` - `TryMatchPathPolicy(...)` - `CanPathLeadToPattern(...)` Die Methode `IsAdditionalConfigurationEnabled()` bleibt fuer boolesche Flags bestehen und wird durch Listen-/String-Helfer ergaenzt. ### 2. Anwendung in der DataArea-Traversierung Der erste und wichtigste Einhaengepunkt ist `GetChildDataAreasAsync()`. Dort wird heute jede gefundene Ebene verarbeitet und vor `BuildDataAreaAsync()` sowie vor dem rekursiven Abstieg durch die Path-Policy geprueft. Vorteil: - geringe Eingriffstiefe - kein Umbau der allgemeinen NTFS-Basis erforderlich - fachliche Wirkung genau dort, wo DataAreas erzeugt werden ### 3. Wiederverwendung fuer Permission-Management `IsPermissionManagedFolderPath()` bleibt fachlich auf Folder beschraenkt, verwendet fuer Black-/Whitelist aber dieselbe generische Path-Policy. Damit wird vermieden, dass ein Ordner zwar nicht mehr als DataArea sichtbar ist, aber weiterhin im Permission-Flow auftaucht. ### 4. Wiederverwendung fuer `LoadDataArea()` Auch `LoadDataArea()` verwendet die Path-Policy inzwischen, damit gefilterte Pfade nicht per Direktzugriff wieder sichtbar werden. ## Offene Abgrenzung Bewusst weiterhin nicht umgesetzt: - Umbau von `cNtfsBase` auf generische Filter-Callbacks - freie Regex-Konfiguration in `AdditionalConfiguration` - unterschiedliche Regeln je Klassifikationstyp Diese Themen koennen spaeter folgen, sind fuer den aktuellen Nutzen aber nicht noetig. ## Logging Fuer ausgeschlossene Pfade sollte auf `Debug` geloggt werden: - welcher Pfad verworfen wurde - welche Regel gegriffen hat - ob der Pfad nur nicht materialisiert oder auch nicht traversiert wurde Beispiel: ```text Skip NTFS path '\\server\share\IT\_disabled' due to AdditionalConfiguration rule 'NtfsExcludePaths=IT\_disabled' ``` Das ist wichtig, damit fehlende DataAreas spaeter im Betrieb nachvollziehbar bleiben. ## Empfohlener Umsetzungsplan 1. Listenparser fuer `AdditionalConfiguration` im NTFS-Provider einfuehren. 2. Pfadnormalisierung und Matching fuer relative sowie absolute Pfade kapseln. 3. `GetChildDataAreasAsync()` um `ShouldTraverseDataArea(...)` erweitern. 4. Debug-Logging fuer Skip-Faelle einfuehren. 5. Dieselbe Policy in `IsPermissionManagedFolderPath()` und `LoadDataArea()` wiederverwenden. Diese Punkte sind im aktuellen Implementierungsstand umgesetzt. ## Kurzfazit Die generische Path-Policy im NTFS-Provider ist klein genug fuer eine risikoarme Implementierung, passt in die vorhandene `AdditionalConfiguration`-Architektur und arbeitet ohne Sonderregeln pro Klassifikationstyp.