Row-level security in Symfony: the role that ran your migrations bypasses every policy you wrote
A comment on my last article was better than the article. The subject was single-database multi-tenancy, and @to21as argued that the predicate should not live in the ORM at all: put it in Postgres as a row-level security policy, and a Messenger worker, a line of native SQL and an ad-hoc psql session all get the same WHERE clause whether anyone remembered it or not. That is correct, and it is the…
The article discusses the issue of row-level security (RLS) in Symfony deployments. It explains that when using Doctrine migrations and enabling RLS, a bug can cause the policies to be bypassed, effectively allowing unauthorized access to data. This problem occurs because the role used to connect to the database also owns the tables, and roles with the BYPASSRLS attribute always bypass RLS.
In Symfony deployments, this oversight can lead to a situation where all tenants' rows are accessible through a query, regardless of the policies written.
To resolve this issue, the article suggests two fixes. The first is to add `ALTER TABLE invoice ENABLE ROW LEVEL SECURITY;` to the migration that enables RLS. The second is to create a separate role for serving requests that does not own any tables. This role can then be granted the necessary permissions on all tables in the schema.
By using a distinct role for serving requests, the risk of bypassing RLS policies is mitigated, as the owning role will now have explicit privileges on the tables. This approach involves additional setup, such as maintaining two connection strings and adjusting the deploy documentation, but it is a necessary trade-off to ensure the integrity of the data protected by RLS policies.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.