feat: add tenant rls policies
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- RLS-Migration fuer tenant-bezogene Tabellen mit Membership-basierten Policies angelegt.
|
||||||
- Audit-Log-Migration mit append-only Triggern und Tenant-Zeit-Index angelegt.
|
- Audit-Log-Migration mit append-only Triggern und Tenant-Zeit-Index angelegt.
|
||||||
- VMID-Allokator-Migration mit transaktionssicherer Reservation pro Cluster angelegt.
|
- VMID-Allokator-Migration mit transaktionssicherer Reservation pro Cluster angelegt.
|
||||||
- VMs-und-SSH-Keys-Migration mit Ressourcen-Mapping und eindeutigem Proxmox-VMID-Index angelegt.
|
- VMs-und-SSH-Keys-Migration mit Ressourcen-Mapping und eindeutigem Proxmox-VMID-Index angelegt.
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ Arbeitsliste auf Basis von `proxmox-console-entwicklungsplan.md`. Die Entwurfsda
|
|||||||
- [x] Tenant- und Profil-Referenzen gesetzt
|
- [x] Tenant- und Profil-Referenzen gesetzt
|
||||||
- [x] Index auf `(tenant_id, created_at)` gesetzt
|
- [x] Index auf `(tenant_id, created_at)` gesetzt
|
||||||
- [x] UPDATE/DELETE per Trigger blockiert
|
- [x] UPDATE/DELETE per Trigger blockiert
|
||||||
|
- [x] E2-T08: RLS-Policies
|
||||||
|
- [x] RLS auf tenant-bezogenen Tabellen aktiviert
|
||||||
|
- [x] Membership-basierte SELECT-Policies angelegt
|
||||||
|
- [x] Audit-Log auf owner/admin beschraenkt
|
||||||
|
- [x] Direkter Query als Nicht-Mitglied lokal verifiziert
|
||||||
|
|
||||||
## MVP-Backlog
|
## MVP-Backlog
|
||||||
|
|
||||||
@@ -109,3 +114,4 @@ Arbeitsliste auf Basis von `proxmox-console-entwicklungsplan.md`. Die Entwurfsda
|
|||||||
- 2026-06-10: VMs-und-SSH-Keys-Migration `0005_vms_and_ssh_keys` angelegt und lokal gegen Supabase verifiziert.
|
- 2026-06-10: VMs-und-SSH-Keys-Migration `0005_vms_and_ssh_keys` angelegt und lokal gegen Supabase verifiziert.
|
||||||
- 2026-06-10: VMID-Allokator-Migration `0006_vmid_allocator` angelegt und mit 50 parallelen Reservierungen lokal gegen Supabase verifiziert.
|
- 2026-06-10: VMID-Allokator-Migration `0006_vmid_allocator` angelegt und mit 50 parallelen Reservierungen lokal gegen Supabase verifiziert.
|
||||||
- 2026-06-10: Audit-Log-Migration `0007_audit_log` angelegt und Append-only-Verhalten lokal gegen Supabase verifiziert.
|
- 2026-06-10: Audit-Log-Migration `0007_audit_log` angelegt und Append-only-Verhalten lokal gegen Supabase verifiziert.
|
||||||
|
- 2026-06-10: RLS-Migration `0008_rls_policies` angelegt und Mitglied/Nicht-Mitglied-Isolation lokal gegen Supabase verifiziert.
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
DROP POLICY IF EXISTS audit_log_admin_select ON public.audit_log;
|
||||||
|
DROP POLICY IF EXISTS ssh_keys_member_select ON public.ssh_keys;
|
||||||
|
DROP POLICY IF EXISTS vms_member_select ON public.vms;
|
||||||
|
DROP POLICY IF EXISTS project_quotas_member_select ON public.project_quotas;
|
||||||
|
DROP POLICY IF EXISTS projects_member_select ON public.projects;
|
||||||
|
DROP POLICY IF EXISTS memberships_member_select ON public.memberships;
|
||||||
|
DROP POLICY IF EXISTS tenants_member_select ON public.tenants;
|
||||||
|
|
||||||
|
ALTER TABLE public.audit_log DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.ssh_keys DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.vms DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.project_quotas DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.projects DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.memberships DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.tenants DISABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS public.has_tenant_role(uuid, public.membership_role[]);
|
||||||
|
DROP FUNCTION IF EXISTS public.is_tenant_member(uuid);
|
||||||
|
DROP FUNCTION IF EXISTS public.current_profile_id();
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION public.current_profile_id()
|
||||||
|
RETURNS uuid
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
AS $$
|
||||||
|
SELECT nullif(current_setting('request.jwt.claim.sub', true), '')::uuid;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.is_tenant_member(p_tenant_id uuid)
|
||||||
|
RETURNS boolean
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
SECURITY DEFINER
|
||||||
|
SET search_path = public
|
||||||
|
AS $$
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM public.memberships
|
||||||
|
WHERE tenant_id = p_tenant_id
|
||||||
|
AND profile_id = public.current_profile_id()
|
||||||
|
);
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.has_tenant_role(p_tenant_id uuid, p_roles public.membership_role[])
|
||||||
|
RETURNS boolean
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
SECURITY DEFINER
|
||||||
|
SET search_path = public
|
||||||
|
AS $$
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM public.memberships
|
||||||
|
WHERE tenant_id = p_tenant_id
|
||||||
|
AND profile_id = public.current_profile_id()
|
||||||
|
AND role = ANY (p_roles)
|
||||||
|
);
|
||||||
|
$$;
|
||||||
|
|
||||||
|
ALTER TABLE public.tenants ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.memberships ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.project_quotas ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.vms ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.ssh_keys ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.audit_log ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
CREATE POLICY tenants_member_select
|
||||||
|
ON public.tenants
|
||||||
|
FOR SELECT
|
||||||
|
USING (public.is_tenant_member(id));
|
||||||
|
|
||||||
|
CREATE POLICY memberships_member_select
|
||||||
|
ON public.memberships
|
||||||
|
FOR SELECT
|
||||||
|
USING (public.is_tenant_member(tenant_id));
|
||||||
|
|
||||||
|
CREATE POLICY projects_member_select
|
||||||
|
ON public.projects
|
||||||
|
FOR SELECT
|
||||||
|
USING (public.is_tenant_member(tenant_id));
|
||||||
|
|
||||||
|
CREATE POLICY project_quotas_member_select
|
||||||
|
ON public.project_quotas
|
||||||
|
FOR SELECT
|
||||||
|
USING (
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM public.projects
|
||||||
|
WHERE projects.id = project_quotas.project_id
|
||||||
|
AND public.is_tenant_member(projects.tenant_id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE POLICY vms_member_select
|
||||||
|
ON public.vms
|
||||||
|
FOR SELECT
|
||||||
|
USING (
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM public.projects
|
||||||
|
WHERE projects.id = vms.project_id
|
||||||
|
AND public.is_tenant_member(projects.tenant_id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE POLICY ssh_keys_member_select
|
||||||
|
ON public.ssh_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (public.is_tenant_member(tenant_id));
|
||||||
|
|
||||||
|
CREATE POLICY audit_log_admin_select
|
||||||
|
ON public.audit_log
|
||||||
|
FOR SELECT
|
||||||
|
USING (public.has_tenant_role(tenant_id, ARRAY['owner', 'admin']::public.membership_role[]));
|
||||||
Reference in New Issue
Block a user