-- Migration 0018: Achse B (Umsetzungsauftrag_Sonnet5.md Teil D.3) -- -- "Benutzergruppe x Zugangsdatensatz". Beantwortet erstmals, WOMIT sich eine -- Gruppe anmeldet: eine Verbindung soll kuenftig nur zustande kommen, wenn -- ein Zugangsdatensatz existiert, der SOWOHL dem Host zugeordnet ALS AUCH -- einer Gruppe des Benutzers freigegeben ist (Achse A -- ssh_connect/ -- rdp_connect je Hostgruppe -- bleibt unveraendert und bestimmt weiterhin, -- OB ueberhaupt verbunden werden darf). -- -- Drei schmale Freigabetabellen, eine je Credential-Art, Aufbau analog zu -- group_hostgroup_roles (zusammengesetzter PK, FK auf user_groups mit ON -- DELETE CASCADE, FK auf das jeweilige Credential-Objekt, granted_by/ -- granted_at/expires_at). Alle drei Credential-Arten haben seit Migration -- 0012 (RDP) bzw. 0016 (SSH-Passwort, diese Session) eine eigene stabile ID -- -- SSH-Keys hatten sie schon immer (0001_initial.sql). -- -- WICHTIG: diese Migration schafft nur das Schema UND befuellt es -- rechteneutral (siehe unten) -- app/rbac.py/die Proxies pruefen diese -- Tabellen noch NICHT (das ist D.6 Schritt 4, "Lesepfade umstellen", noch -- nicht umgesetzt). Bis dahin bleibt das heutige Verhalten (jeder Nutzer mit -- ssh_connect/rdp_connect auf der Hostgruppe nutzt automatisch das am Host -- haengende Credential) unveraendert in Kraft -- diese Migration allein -- aendert also NICHTS am Laufzeitverhalten. CREATE TABLE IF NOT EXISTS group_ssh_key_grants ( user_group_id INTEGER NOT NULL REFERENCES user_groups(id) ON DELETE CASCADE, ssh_key_id INTEGER NOT NULL REFERENCES ssh_keys(id), granted_by INTEGER REFERENCES users(id), granted_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), expires_at TEXT, PRIMARY KEY (user_group_id, ssh_key_id) ); CREATE INDEX IF NOT EXISTS idx_gskg_group ON group_ssh_key_grants(user_group_id); CREATE INDEX IF NOT EXISTS idx_gskg_key ON group_ssh_key_grants(ssh_key_id); CREATE TABLE IF NOT EXISTS group_rdp_credential_grants ( user_group_id INTEGER NOT NULL REFERENCES user_groups(id) ON DELETE CASCADE, rdp_credential_id INTEGER NOT NULL REFERENCES rdp_credentials(id), granted_by INTEGER REFERENCES users(id), granted_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), expires_at TEXT, PRIMARY KEY (user_group_id, rdp_credential_id) ); CREATE INDEX IF NOT EXISTS idx_grcg_group ON group_rdp_credential_grants(user_group_id); CREATE INDEX IF NOT EXISTS idx_grcg_cred ON group_rdp_credential_grants(rdp_credential_id); CREATE TABLE IF NOT EXISTS group_ssh_password_credential_grants ( user_group_id INTEGER NOT NULL REFERENCES user_groups(id) ON DELETE CASCADE, ssh_password_credential_id INTEGER NOT NULL REFERENCES ssh_password_credentials(id), granted_by INTEGER REFERENCES users(id), granted_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), expires_at TEXT, PRIMARY KEY (user_group_id, ssh_password_credential_id) ); CREATE INDEX IF NOT EXISTS idx_gspcg_group ON group_ssh_password_credential_grants(user_group_id); CREATE INDEX IF NOT EXISTS idx_gspcg_cred ON group_ssh_password_credential_grants(ssh_password_credential_id); -- Rechteneutrale Vorbefuellung (D.4 Schritt 5): fuer jeden Host mit -- zugeordnetem Zugangsdatensatz wird jede Gruppe freigeschaltet, die auf der -- Hostgruppe dieses Hosts die passende Connect-Rolle haelt -- reproduziert -- exakt das heutige (Achse-A-only) Verhalten, bei dem JEDER Nutzer mit -- ssh_connect/rdp_connect automatisch das am Host haengende Credential -- benutzen darf. INSERT OR IGNORE, weil dieselbe (Gruppe, Credential)- -- Kombination ueber mehrere Hosts hinweg mehrfach auftreten kann (ein -- SSH-Key kann an mehreren Hosts derselben Hostgruppe haengen). -- -- Setzt group_hostgroup_roles NACH der Personengruppen-Spiegelung aus -- Migration 0017 voraus (Reihenfolge 0017 vor 0018 ist deshalb zwingend) -- -- sonst wuerden Nutzer, die ihre Verbindungsrechte bisher nur direkt (nicht -- ueber eine Gruppe) hatten, hier uebergangen. INSERT OR IGNORE INTO group_ssh_key_grants (user_group_id, ssh_key_id, granted_by, granted_at) SELECT DISTINCT ghr.user_group_id, hskm.ssh_key_id, NULL, strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM host_ssh_key_map hskm JOIN hosts h ON h.id = hskm.host_id JOIN group_hostgroup_roles ghr ON ghr.host_group_id = h.host_group_id JOIN roles r ON r.id = ghr.role_id AND r.name = 'ssh_connect'; INSERT OR IGNORE INTO group_rdp_credential_grants (user_group_id, rdp_credential_id, granted_by, granted_at) SELECT DISTINCT ghr.user_group_id, hrcm.rdp_credential_id, NULL, strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM host_rdp_credential_map hrcm JOIN hosts h ON h.id = hrcm.host_id JOIN group_hostgroup_roles ghr ON ghr.host_group_id = h.host_group_id JOIN roles r ON r.id = ghr.role_id AND r.name = 'rdp_connect'; INSERT OR IGNORE INTO group_ssh_password_credential_grants (user_group_id, ssh_password_credential_id, granted_by, granted_at) SELECT DISTINCT ghr.user_group_id, hspcm.ssh_password_credential_id, NULL, strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM host_ssh_password_credential_map hspcm JOIN hosts h ON h.id = hspcm.host_id JOIN group_hostgroup_roles ghr ON ghr.host_group_id = h.host_group_id JOIN roles r ON r.id = ghr.role_id AND r.name = 'ssh_connect';