Multi-Vendor-Architektur¶
TCM365 ist von Grund auf für Multi-Vendor-Erweiterbarkeit konzipiert. Das VendorAdapter-Pattern abstrahiert vendor-spezifische API-Interaktionen hinter einem einheitlichen Interface, sodass die Plattform Microsoft 365, Zscaler, Atlassian Cloud und zukuenftige Vendor unterstützen kann, ohne die Kern-Geschaeftslogik zu ändern.
Designziele¶
- Vendor-Agnostik -- Kern-Plattformfeatures (Snapshots, Drift, Baselines, Compliance) arbeiten auf vendor-agnostischen Datenstrukturen.
- Pluggable Adapter -- Neue Vendor werden durch Implementierung eines einzigen Interface und Registrierung bei der Adapter-Registry hinzugefügt.
- Konsistente UX -- Benutzer erleben dieselben Workflows unabhängig vom Vendor.
- Unabhaengige Lebenszyklen -- Vendor-Adapter können unabhängig aktualisiert werden, ohne andere Vendor oder Kernlogik zu beeinflussen.
- Typsichere Ressourcen-Identifikation -- Ressourcen werden über eine strukturierte
vendor.service.resource-Namenskonvention identifiziert.
VendorAdapter Interface¶
Das VendorAdapter-Interface definiert 7 Methoden, die jede Vendor-Implementierung bereitstellen muss:
// backend-js/src/common/interfaces/vendor-adapter.interface.ts
export interface VendorAdapter {
/** Gibt Vendor-Metadaten zurück (Name, Version, unterstützte Features). */
getInfo(): VendorInfo;
/** Gibt die vom Adapter unterstützten Fähigkeiten zurück. */
capabilities(): VendorCapabilities;
/** Entdeckt verfügbare Ressourcentypen und Konfigurationen. */
discover(tenant: VendorTenant): Promise<DiscoveryResult>;
/** Erfasst einen Point-in-Time Snapshot aller (oder ausgewaehlter) Konfigurationen. */
capture(tenant: VendorTenant, options?: CaptureOptions): Promise<CaptureResult>;
/** Erkennt Drift zwischen zwei Snapshots oder zwischen Snapshot und Live-Konfiguration. */
detectDrift(tenant: VendorTenant, baseline: Snapshot, current?: Snapshot): Promise<DriftResult>;
/** Wendet eine Konfiguration auf den Ziel-Tenant an (Rollback oder Blueprint). */
apply(tenant: VendorTenant, configuration: any, options?: ApplyOptions): Promise<ApplyResult>;
/** Ruft Audit Logs vom Vendor für Change Attribution ab. */
getAuditLogs(tenant: VendorTenant, timeRange: TimeRange): Promise<AuditLogEntry[]>;
}
Interface-Typen¶
interface VendorInfo {
vendorId: string; // 'microsoft' | 'zscaler' | 'atlassian'
displayName: string; // 'Microsoft 365' | 'Zscaler' | 'Atlassian Cloud'
version: string; // Adapter-Version
documentationUrl: string; // Link zur Vendor-Dokumentation
}
interface VendorCapabilities {
canCapture: boolean; // Snapshot Capture unterstützt
canDetectDrift: boolean; // Drift Detection unterstützt
canApply: boolean; // Rollback/Apply unterstützt
canAudit: boolean; // Audit Log-Abruf unterstützt
canDiscover: boolean; // Resource Discovery unterstützt
supportedResourceTypes: string[]; // Liste der Ressourcentyp-Identifier
}
interface CaptureResult {
success: boolean;
data: Record<string, any>; // Ressourcentyp -> Konfigurationsdaten
resourceCount: number;
errors?: CaptureError[];
duration: number;
}
VendorAdapterRegistry¶
Die VendorAdapterRegistry ist ein injizierbarer NestJS-Service, der die Adapter-Registrierung und -Suche verwaltet.
@Injectable()
export class VendorAdapterRegistry {
private adapters = new Map<string, VendorAdapter>();
/** Registriert einen Vendor-Adapter. Wird bei Modulinitialisierung aufgerufen. */
register(vendorId: string, adapter: VendorAdapter): void {
this.adapters.set(vendorId, adapter);
}
/** Sucht einen Adapter nach Vendor ID. Wirft Exception, wenn nicht registriert. */
get(vendorId: string): VendorAdapter {
const adapter = this.adapters.get(vendorId);
if (!adapter) {
throw new NotFoundException(`No adapter registered for vendor: ${vendorId}`);
}
return adapter;
}
/** Gibt alle registrierten Vendor IDs zurück. */
getRegisteredVendors(): string[] {
return Array.from(this.adapters.keys());
}
/** Prüft, ob ein Vendor-Adapter registriert ist. */
has(vendorId: string): boolean {
return this.adapters.has(vendorId);
}
}
Registrierungs-Pattern¶
Jeder Vendor-Adapter registriert sich während der NestJS-Modulinitialisierung:
@Module({
providers: [M365Adapter, VendorAdapterRegistry],
})
export class M365Module implements OnModuleInit {
constructor(
private readonly registry: VendorAdapterRegistry,
private readonly m365Adapter: M365Adapter,
) {}
onModuleInit() {
this.registry.register('microsoft', this.m365Adapter);
}
}
Aktuelle Vendor-Implementierungen¶
M365Adapter (Microsoft 365)¶
Vendor ID: microsoft
Der M365 Adapter delegiert je nach Workload an zwei Kern-Services:
| Service | Workloads | Strategie |
|---|---|---|
| GraphService | Entra ID, Intune, Defender | Direkte Microsoft Graph API-Aufrufe |
| UtcmService | Teams, Exchange | UTCM Snapshot Job API |
Fähigkeiten:
| Fähigkeit | Status | Details |
|---|---|---|
| Capture | Vollständig | 52 Ressourcentypen über 8 Workloads |
| Drift Detection | Vollständig | Per-Ressourcentyp-Vergleich mit Aenderungskategorisierung |
| Rollback | Vollständig | 52 Ressourcentypen mit Pre-Flight-Validierung |
| Audit Logs | Vollständig | Azure AD Directory Audit Log-Integration |
| Discovery | Vollständig | Workload- und Berechtigungs-Discovery |
Ressourcentypen (52):
microsoft.entra.conditionalAccess
microsoft.entra.namedLocations
microsoft.entra.authenticationMethods
microsoft.entra.authenticationStrengths
microsoft.entra.directorySettings
microsoft.entra.roleAssignments
microsoft.entra.securityDefaults
microsoft.entra.authorizationPolicy
microsoft.entra.crossTenantAccess
microsoft.entra.appRegistrations
microsoft.entra.servicePrincipals
microsoft.intune.deviceCompliance
microsoft.intune.deviceConfiguration
microsoft.intune.enrollmentConfig
microsoft.intune.endpointSecurity
microsoft.intune.appProtection
microsoft.defender.secureScore
microsoft.defender.secureScoreControls
microsoft.teams.*
microsoft.exchange.*
... (52 gesamt)
ZscalerAdapter¶
Vendor ID: zscaler
Der Zscaler Adapter verwendet zwei API Clients für ZIA und ZPA:
| Client | Plattform | Endpoint-Gruppen |
|---|---|---|
| ZscalerZiaClient | Zscaler Internet Access | 12 Gruppen |
| ZscalerZpaClient | Zscaler Private Access | 9 Gruppen |
ZIA Endpoint-Gruppen (12):
| Gruppe | Ressourcen |
|---|---|
| URL Filtering | URL Filtering Rules, URL Categories |
| Firewall | Firewall Rules, IP Destination Groups |
| DLP | DLP Dictionaries, DLP Engines, DLP Rules |
| SSL Inspection | SSL Inspection Rules, Certificates |
| Security | Advanced Threat Protection, Malware Protection |
| Bandwidth Control | Bandwidth Control Rules |
| Authentication | Authentication Settings |
| Traffic Forwarding | GRE Tunnels, VPN Credentials, Static IPs |
| Location Management | Locations, Sub-Locations |
| User Management | Users, Groups, Departments |
| Admin Management | Admin Users, Admin Roles |
| Sandbox | Cloud Sandbox Settings |
ZPA Endpoint-Gruppen (9):
| Gruppe | Ressourcen |
|---|---|
| App Segments | Application Segments, Segment Groups |
| Server Groups | Server Groups, Application Servers |
| Connectors | Connector Groups, Connectors |
| Access Policies | Access Policies, Policy Rules |
| Forwarding Policies | Forwarding Rules |
| Timeout Policies | Timeout Policy Rules |
| Inspection Policies | AppProtection Profiles, Inspection Rules |
| Certificates | Browser Access Certificates, Enrollment Certificates |
| SCIM | SCIM Attribute Headers, SCIM Groups |
Authentifizierung und Rate Limiting:
| Plattform | Auth-Methode | Read-Limit | Write-Limit |
|---|---|---|---|
| ZIA | Cookie-basiert (28-Min TTL) | 80 Req / 10s | 10 Req / 10s |
| ZPA | OAuth 2.0 (5-Min Pre-Expiry Buffer) | 15 Req / 10s | 15 Req / 10s |
AtlassianAdapter (v2.5.0)¶
Vendor ID: atlassian
Der Atlassian Adapter verwendet drei spezialisierte API Clients:
| Client | Plattform | Beschreibung |
|---|---|---|
| AtlassianJiraClient | Jira Cloud | 16 Getter-Methoden für Jira v3 REST API |
| AtlassianConfluenceClient | Confluence Cloud | Confluence v2 REST API |
| AtlassianAdminClient | Atlassian Admin | Admin REST API mit Cursor-Body-Pagination |
Fähigkeiten:
| Fähigkeit | Status | Details |
|---|---|---|
| Capture | Vollständig | 28 Resource Types über Jira, Confluence und Org Security |
| Drift Detection | Vollständig | deep-diff-basierter Vergleich |
| Rollback | Vollständig | Direct Write Methods für unterstützte Resource Types |
| Audit Logs | Vollständig | Two-Tier Audit Log-Abruf (Org + Produkt) |
| Discovery | Vollständig | Site Discovery und Resource Type Enumeration |
Ressourcentypen (28):
| Bereich | Anzahl | Beispiele |
|---|---|---|
| Jira | 16 | Projekte, Workflows, Permission Schemes, Issue Security, Notification Schemes |
| Confluence | 5 | Spaces, Global Templates, Space Permissions, Look and Feel |
| Org Security | 7 | Authentication Policies, IP Allowlists, Audit Log Settings, External Users |
Authentifizierung und Rate Limiting:
| Aspekt | Details |
|---|---|
| Auth-Methode | OAuth 2LO (Two-Legged OAuth) |
| Rate Limiting | Points-basiertes System (AtlassianRateLimiter) |
| Pagination | Cursor-Body-Pagination für Admin API |
Ressourcentyp-Namenskonvention¶
Ressourcentypen verwenden ein strukturiertes vendor.service.resource-Format:
| Segment | Beschreibung | Beispiele |
|---|---|---|
vendor |
Vendor-Identifier | microsoft, zscaler, atlassian |
service |
Service/Produkt innerhalb des Vendors | entra, intune, teams, zia, zpa, jira, confluence, orgSecurity |
resource |
Spezifischer Ressourcentyp | conditionalAccess, urlFilteringRules |
Beispiele:
microsoft.entra.conditionalAccess
microsoft.intune.deviceCompliance
microsoft.teams.messagingSettings
zscaler.zia.urlFilteringRules
zscaler.zia.firewallRules
zscaler.zpa.appSegments
zscaler.zpa.accessPolicies
atlassian.jira.projects
atlassian.jira.workflows
atlassian.confluence.spaces
atlassian.orgSecurity.authenticationPolicies
Resource Registry¶
Ressourcendefinitionen sind in backend-js/src/config/resource-registry/ gespeichert:
| Datei | Inhalt |
|---|---|
m365-entra.ts |
Microsoft Entra ID Ressourcendefinitionen |
m365-intune.ts |
Microsoft Intune Ressourcendefinitionen |
m365-defender.ts |
Microsoft Defender Ressourcendefinitionen |
m365-teams.ts |
Microsoft Teams Ressourcendefinitionen |
m365-exchange.ts |
Microsoft Exchange Ressourcendefinitionen |
zscaler-zia.ts |
Zscaler ZIA Ressourcendefinitionen |
zscaler-zpa.ts |
Zscaler ZPA Ressourcendefinitionen |
vendor-alias-map.ts |
Cross-Vendor Ressourcen-Aliasing für einheitliche Abfragen |
atlassian-jira.ts |
Atlassian Jira Ressourcendefinitionen (v2.5.0) |
atlassian-confluence.ts |
Atlassian Confluence Ressourcendefinitionen (v2.5.0) |
atlassian-org-security.ts |
Atlassian Org Security Ressourcendefinitionen (v2.5.0) |
Architekturdiagramm¶
graph TB
SS[SnapshotService] -->|"Adapter aufloesen"| REG[VendorAdapterRegistry]
REG --> M365[M365Adapter]
REG --> ZS[ZscalerAdapter]
REG --> ATL[AtlassianAdapter]
REG --> FUTURE["[Zukuenftige Adapter]"]
M365 --> GS[GraphService]
M365 --> US[UtcmService]
ZS --> ZIA[ZscalerZiaClient]
ZS --> ZPA[ZscalerZpaClient]
ATL --> JIRA[AtlassianJiraClient]
ATL --> CONF[AtlassianConfluenceClient]
ATL --> ADM[AtlassianAdminClient]
GS --> GAPI["Microsoft Graph API"]
US --> UAPI["UTCM Snapshot Job API"]
ZIA --> ZIAAPI["Zscaler ZIA REST API"]
ZPA --> ZPAAPI["Zscaler ZPA REST API"]
JIRA --> ATLAPI["Atlassian Cloud REST APIs"]
CONF --> ATLAPI
ADM --> ATLAPI
Vendor-agnostischer Datenfluss¶
Der Plattformkern verarbeitet Daten über eine vendor-agnostische Pipeline:
- Benutzer fordert Snapshot Capture für einen VendorTenant an
- SnapshotService löst den VendorAdapter über die VendorAdapterRegistry auf
Adapter.capture()ruft vendor-spezifische APIs auf- Adapter gibt ein standardisiertes
CaptureResultzurück - SnapshotService speichert das Ergebnis im Tenant-Schema
- Drift/Baseline/Compliance-Bewertungen arbeiten auf den standardisierten Daten
Dies stellt sicher, dass alle nachgelagerten Features (Diff, Drift, Baselines, Compliance, Reports) identisch funktionieren, unabhängig davon, welcher Vendor die Daten erzeugt hat.
Neuen Vendor hinzufügen¶
Um Unterstützung für einen neuen Vendor (z.B. AWS, Google Workspace) hinzuzufuegen, folgen Sie diesen Schritten:
Schritt 1: Child-Entity erstellen¶
// backend-js/src/entities/aws-vendor-tenant.entity.ts
@ChildEntity('aws')
export class AwsVendorTenant extends VendorTenant {
@Column({ name: 'aws_account_id', nullable: true })
awsAccountId: string;
@Column({ name: 'aws_access_key_id', nullable: true })
awsAccessKeyId: string;
@Column({ name: 'aws_secret_access_key', nullable: true })
awsSecretAccessKey: string;
}
Schritt 2: Migration erstellen¶
Tenant-Schema-Updates
Die Migration muss auch alle bestehenden tenant_*-Schemas aktualisieren, wenn der neue Vendor Änderungen an Data-Plane-Tabellen einfuehrt.
Schritt 3: VendorAdapter implementieren¶
@Injectable()
export class AwsAdapter implements VendorAdapter {
getInfo(): VendorInfo {
return {
vendorId: 'aws',
displayName: 'Amazon Web Services',
version: '1.0.0',
documentationUrl: 'https://docs.aws.amazon.com',
};
}
capabilities(): VendorCapabilities {
return {
canCapture: true, canDetectDrift: true, canApply: true,
canAudit: true, canDiscover: true,
supportedResourceTypes: ['aws.iam.policies', 'aws.iam.roles', /* ... */],
};
}
async discover(tenant: VendorTenant): Promise<DiscoveryResult> { /* ... */ }
async capture(tenant: VendorTenant, options?: CaptureOptions): Promise<CaptureResult> { /* ... */ }
async detectDrift(tenant: VendorTenant, baseline: Snapshot, current?: Snapshot): Promise<DriftResult> { /* ... */ }
async apply(tenant: VendorTenant, config: any, options?: ApplyOptions): Promise<ApplyResult> { /* ... */ }
async getAuditLogs(tenant: VendorTenant, timeRange: TimeRange): Promise<AuditLogEntry[]> { /* ... */ }
}
Schritt 4: Modul erstellen und registrieren¶
@Module({
imports: [VendorRegistryModule],
providers: [AwsAdapter, AwsApiClient],
exports: [AwsAdapter],
})
export class AwsModule implements OnModuleInit {
constructor(
private readonly registry: VendorAdapterRegistry,
private readonly awsAdapter: AwsAdapter,
) {}
onModuleInit() {
this.registry.register('aws', this.awsAdapter);
}
}
Schritt 5: Ressourcendefinitionen und AppModule¶
- Ressourcendefinitionen in
backend-js/src/config/resource-registry/erstellen - Modul in
app.module.tsimportieren - Frontend aktualisieren: Vendor-Option im Tenant-Formular, credential-spezifische Felder, Renderer