RLS restrictive hook policies
In get_row_security_policies():
/*
* If the only built-in policy is the default-deny one, and hook policies
* exist, then use the hook policies only and do not apply the
* default-deny policy. Otherwise, we will apply both sets below.
*/
if (defaultDeny &&
(hook_policies_restrictive != NIL || hook_policies_permissive != NIL))
{
rowsec_expr = NULL;
rowsec_with_check_expr = NULL;
}
So if the only policies that exist are restrictive policies from an
extension, the default-deny policy is not applied and the restrictive
policies are applied instead, which is effectively a "default-allow"
situation with each restrictive policy further limiting access to the
table.
I think this is potentially very dangerous when both kinds of policy
exist. Consider for example a situation where initially multiple
permissive policies are set up for different users allowing them
access to different subsets of the table, and users not covered by any
of those permissive policies have no access. Then suppose that later a
restrictive policy is added, applying to all users -- the intention
being to prevent any user from accessing some particularly sensitive
data. The result of adding that restrictive policy would be that all
the users who previously had no access at all would suddenly have
access to everything not prohibited by the restrictive policy.
That goes against everything I would expect from a restrictive policy
-- adding more restrictive policies should only ever reduce the number
of rows visible, not ever open up more. So I think the test above
should only disable the default-deny policy if there are any
permissive policies from the extension.
Of course that will make life a little harder for people who only want
to use restrictive policies, since they will be forced to first add a
permissive policy, possibly just one that's always true, but I think
it's the safest approach.
Possibly if/when we add proper SQL support for defining restrictive
policies, we might also add an option to ALTER TABLE ... ENABLE ROW
LEVEL SECURITY to allow a table to have RLS enabled in default-allow
mode, for users who know they only want to add restrictive policies.
However, I think that should be something the user has to explicitly
ask for, not an automatic decision based on the existence of
restrictive policies.
Thoughts?
Regards,
Dean
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Dean,
* Dean Rasheed (dean.a.rasheed@gmail.com) wrote:
In get_row_security_policies():
/*
* If the only built-in policy is the default-deny one, and hook policies
* exist, then use the hook policies only and do not apply the
* default-deny policy. Otherwise, we will apply both sets below.
*/
if (defaultDeny &&
(hook_policies_restrictive != NIL || hook_policies_permissive != NIL))
{
rowsec_expr = NULL;
rowsec_with_check_expr = NULL;
}So if the only policies that exist are restrictive policies from an
extension, the default-deny policy is not applied and the restrictive
policies are applied instead, which is effectively a "default-allow"
situation with each restrictive policy further limiting access to the
table.
Right, the idea there being that applying the default-deny would render
the restrictive policies pointless, since nothing would ever be visible,
however..
I think this is potentially very dangerous when both kinds of policy
exist. Consider for example a situation where initially multiple
permissive policies are set up for different users allowing them
access to different subsets of the table, and users not covered by any
of those permissive policies have no access. Then suppose that later a
restrictive policy is added, applying to all users -- the intention
being to prevent any user from accessing some particularly sensitive
data. The result of adding that restrictive policy would be that all
the users who previously had no access at all would suddenly have
access to everything not prohibited by the restrictive policy.That goes against everything I would expect from a restrictive policy
-- adding more restrictive policies should only ever reduce the number
of rows visible, not ever open up more. So I think the test above
should only disable the default-deny policy if there are any
permissive policies from the extension.Of course that will make life a little harder for people who only want
to use restrictive policies, since they will be forced to first add a
permissive policy, possibly just one that's always true, but I think
it's the safest approach.
Requiring a permissive policy which allows the records first, to avoid
the default-deny, makes a ton of sense.
Possibly if/when we add proper SQL support for defining restrictive
policies, we might also add an option to ALTER TABLE ... ENABLE ROW
LEVEL SECURITY to allow a table to have RLS enabled in default-allow
mode, for users who know they only want to add restrictive policies.
Perhaps... I'm not sure that's really better than simply requiring a
'create policy p1 on t1 using (true);' to be done.
However, I think that should be something the user has to explicitly
ask for, not an automatic decision based on the existence of
restrictive policies.
Agreed. I'm happy to commit that change and back-patch it to 9.5,
barring objections. Given that the only way to have restrictive
policies currently is using hooks, I don't believe there's any
documentation update required either; of course, I'll update the comment
to reflect this discussion/decision and make any necessary changes to
test_rls_hooks.
Thanks!
Stephen
Dean, all,
* Stephen Frost (sfrost@snowman.net) wrote:
Agreed. I'm happy to commit that change and back-patch it to 9.5,
barring objections. Given that the only way to have restrictive
policies currently is using hooks, I don't believe there's any
documentation update required either; of course, I'll update the comment
to reflect this discussion/decision and make any necessary changes to
test_rls_hooks.
Patch attached to make this change, with appropriate comment updates and
fixes to the test_rls_hooks modules.
Comments?
Thanks!
Stephen
Attachments:
rls-restrictive-hook.patchtext/x-diff; charset=us-asciiDownload
From 173db8f942636e92f20145844b7dadd04ccac765 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 3 Aug 2015 10:59:24 -0400
Subject: [PATCH] RLS: Keep deny policy when only restrictive exist
Only remove the default deny policy when a permissive policy exists
(either from the hook or defined by the user). If only restrictive
policies exist then no rows will be visible, as restrictive policies
shouldn't make rows visible. To address this requirement, a single
"USING (true)" permissive policy can be created.
Update the test_rls_hooks regression tests to create the necessary
"USING (true)" permissive policy.
Back-patch to 9.5 where RLS was added.
Per discussion with Dean.
---
src/backend/rewrite/rowsecurity.c | 14 ++++++++++----
.../modules/test_rls_hooks/expected/test_rls_hooks.out | 7 +++++++
src/test/modules/test_rls_hooks/sql/test_rls_hooks.sql | 8 ++++++++
src/test/modules/test_rls_hooks/test_rls_hooks.c | 5 +++++
4 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index 562dbc9..5a81db3 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -225,12 +225,18 @@ get_row_security_policies(Query *root, CmdType commandType, RangeTblEntry *rte,
}
/*
- * If the only built-in policy is the default-deny one, and hook policies
- * exist, then use the hook policies only and do not apply the
+ * If the only built-in policy is the default-deny one, and permissive hook
+ * policies exist, then use the hook policies only and do not apply the
* default-deny policy. Otherwise, we will apply both sets below.
+ *
+ * Note that we do not remove the defaultDeny policy if only *restrictive*
+ * policies exist as restrictive policies should only ever be reducing what
+ * is visible. Therefore, at least one permissive policy must exist which
+ * allows records to be seen before restrictive policies can remove rows
+ * from that set. A single "true" policy can be created to address this
+ * requirement, if necessary.
*/
- if (defaultDeny &&
- (hook_policies_restrictive != NIL || hook_policies_permissive != NIL))
+ if (defaultDeny && hook_policies_permissive != NIL)
{
rowsec_expr = NULL;
rowsec_with_check_expr = NULL;
diff --git a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out
index 3a7a4c3..4587eb0 100644
--- a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out
+++ b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out
@@ -13,6 +13,11 @@ CREATE TABLE rls_test_restrictive (
supervisor name,
data integer
);
+-- At least one permissive policy must exist, otherwise
+-- the default deny policy will be applied. For
+-- testing the only-restrictive-policies from the hook,
+-- create a simple 'allow all' policy.
+CREATE POLICY p1 ON rls_test_restrictive USING (true);
-- initial test data
INSERT INTO rls_test_restrictive VALUES ('r1','s1',1);
INSERT INTO rls_test_restrictive VALUES ('r2','s2',2);
@@ -109,6 +114,8 @@ RESET ROLE;
-- Create "internal" policies, to check that the policies from
-- the hooks are combined correctly.
CREATE POLICY p1 ON rls_test_permissive USING (data % 2 = 0);
+-- Remove the original allow-all policy
+DROP POLICY p1 ON rls_test_restrictive;
CREATE POLICY p1 ON rls_test_restrictive USING (data % 2 = 0);
CREATE POLICY p1 ON rls_test_both USING (data % 2 = 0);
SET ROLE r1;
diff --git a/src/test/modules/test_rls_hooks/sql/test_rls_hooks.sql b/src/test/modules/test_rls_hooks/sql/test_rls_hooks.sql
index ece4ab9..3071213 100644
--- a/src/test/modules/test_rls_hooks/sql/test_rls_hooks.sql
+++ b/src/test/modules/test_rls_hooks/sql/test_rls_hooks.sql
@@ -17,6 +17,12 @@ CREATE TABLE rls_test_restrictive (
data integer
);
+-- At least one permissive policy must exist, otherwise
+-- the default deny policy will be applied. For
+-- testing the only-restrictive-policies from the hook,
+-- create a simple 'allow all' policy.
+CREATE POLICY p1 ON rls_test_restrictive USING (true);
+
-- initial test data
INSERT INTO rls_test_restrictive VALUES ('r1','s1',1);
INSERT INTO rls_test_restrictive VALUES ('r2','s2',2);
@@ -101,6 +107,8 @@ RESET ROLE;
-- the hooks are combined correctly.
CREATE POLICY p1 ON rls_test_permissive USING (data % 2 = 0);
+-- Remove the original allow-all policy
+DROP POLICY p1 ON rls_test_restrictive;
CREATE POLICY p1 ON rls_test_restrictive USING (data % 2 = 0);
CREATE POLICY p1 ON rls_test_both USING (data % 2 = 0);
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index d76b17a..b96dbff 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -119,6 +119,11 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
/*
* Return restrictive policies to be added
+ *
+ * Note that a permissive policy must exist or the default-deny policy
+ * will be included and nothing will be visible. If no filtering should
+ * be done except for the restrictive policy, then a single "USING (true)"
+ * permissive policy can be used; see the regression tests.
*/
List *
test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
--
1.9.1
On 3 August 2015 at 16:09, Stephen Frost <sfrost@snowman.net> wrote:
Dean, all,
* Stephen Frost (sfrost@snowman.net) wrote:
Agreed. I'm happy to commit that change and back-patch it to 9.5,
barring objections. Given that the only way to have restrictive
policies currently is using hooks, I don't believe there's any
documentation update required either; of course, I'll update the comment
to reflect this discussion/decision and make any necessary changes to
test_rls_hooks.Patch attached to make this change, with appropriate comment updates and
fixes to the test_rls_hooks modules.Comments?
Looks good to me.
Regards,
Dean
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Dean,
* Dean Rasheed (dean.a.rasheed@gmail.com) wrote:
On 3 August 2015 at 16:09, Stephen Frost <sfrost@snowman.net> wrote:
* Stephen Frost (sfrost@snowman.net) wrote:
Agreed. I'm happy to commit that change and back-patch it to 9.5,
barring objections. Given that the only way to have restrictive
policies currently is using hooks, I don't believe there's any
documentation update required either; of course, I'll update the comment
to reflect this discussion/decision and make any necessary changes to
test_rls_hooks.Patch attached to make this change, with appropriate comment updates and
fixes to the test_rls_hooks modules.Comments?
Looks good to me.
Thanks! Pushed to master and 9.5.
Stephen