AWS RDS Postgres/Iam Authentication/ and Row Level Security - All In One. Is this possible? - postgresql

I have an app that will have many users at various levels of privileges on what they can "See/Select".
The users form a hierarchy. Level1--> Level2--Level3 etc. Level1 users may have many level2 users, similarly Level2 users may have many level3 users . Each user can see anything that belongs to them or anyone directly below them. For example: A level 2 user can see all level 3 users information that rolls up to her but cannot see , any level 3 users that rolls up to other level 2 users.... You get the idea.
All userids are unique.
I am thinking of implementing Row Level Security with policies to restrict based on the userid. This is working at the database level by implementing Row level security and policies.
However, I would like to know how this can be achieved with IAM roles and IAM based authentication?
I read the documentation. It states, that while I can create a IAM roles and assign them privileges at the db level, and individual users can be assigned to these IAM roles to access the database using authtokens, it does not state how I can track each of the users at the database level to ensure that they can only see their data?
Any insights appreciated.
S

If you google "SaaS Multi-tenant Storage Isolation" You'll find a number of resources on this topic. The short answer is that you can achieve what you are trying to do (pool isolation enforced by IAM policies) with DynamoDB. But with RDS you have to rely on database users and PostgeSQL RLS features.
If you look at the IAM documentation for DyanmoDB and RDS condition keys, you'll see that with DynamoDB you can filter actions based on things like "dynamodb:LeadingKeys" or "dynamodb:Attributes". Where as RDS you do not have filters that get as granular as individual indicies or attributes.
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonrds.html#amazonrds-policy-keys
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazondynamodb.html#amazondynamodb-policy-keys
Here's some addtional material on the topic worth looking at:
https://www.youtube.com/watch?v=fuDZq-EspNA (includes examples at ~35mins)
https://d1.awsstatic.com/whitepapers/Multi_Tenant_SaaS_Storage_Strategies.pdf
https://aws.amazon.com/blogs/database/multi-tenant-data-isolation-with-postgresql-row-level-security/

Related

PostgreSQL: create a personalized role for any customer

I am new to Postgres, sorry if the question is basic:)
I need to create a personalized role for any customer already existing in the DB.
Role name must be client_{first_name}_{last_name} (without curly brackets).
Also, this customer can only access his own data in "table_1" and "table_2" tables.
I took ALICE STEWART (id 51).
What I did:
I created role Customer with Select privilege. Then tried to create role for ALICE STEWART and I get an infinite recursion error.
But how to create role for one customer so that he could access only his info in 2 tables?
How to do that properly?
There is nothing wrong with personalized database users, but I would only consider that if you don't have very many users. I wouldn't want to deal with a pg_authid that contains 100000 users.
I would not play this with permissions, but with row level security. The exact way in which that would work depends on your data. The easiest way is to have and owner column that lists the user that can see the data.
Watch out for overly complicated policies, as they will make your queries slow.

Designing a role based access on DB level

I am working on designing role based access for an application. Here, there are various department like HR, Finance , Developer ,etc. I am planning to have department level accesses on their respective related table like Finance user can access Payroll table...
I have done some R&D and came up with following approach.
Currently I have thought to have Department level user roles.
I have planned 3 roles Viz. super admin ,admin & user. So lets suppose if HR user makes a request to write data on employee we can check if user is from HR and then we grant this access.
Problem is that I am not able to design how to place an access table which can have collection of all accesses like employee_read_write or payroll_read_write ,etc.
Should I be creating a new access & map it somehow to user roles & department OR map the different tables that can be accessed on department level like Finance department has payroll accesses.
Since, I am new to RBAC kindly let me know if this is the right approach that I am planning or there is some better way. Appreciate your inputs !!

Snowflake data steward discovery based on role hierarchy

Snowflake follows the role-based access control (RBAC) paradigm. Best practice for RBAC is, to have functional and access roles managing either user and clients or access privileges. This creates in worst-case a variety of roles that inherits permissions from and to each other. By nature, one can easily lose sight.
In snowflake, grants to roles and users are stored in ACCESS_USAGE.GRANTS_TO_ROLES and ACCESS_USAGE.GRANTS_TO_USERS. What is a proper approach to identify the data stewards/owner of a role automatically (if not labeled explicitly in a 3rd party tooling)?
Options I thought of:
recursive lookup of OWNERSHIP privileges of roles of roles (will generate a lot of false positives)
recursive discovery of a service account that has advanced permission to a role and lookup the service account owner
lookup over usage pattern of executed queries (might be actually more consumers than producers)
A couple of options:
Populate the role’s comment field with the relevant Data Steward information
Use Tags (in public preview)

How to implement complex permission based data access in Postgres with Postgraphile or alternatives

For a new project, we're currently designing a database and an API to access this. We've already established we'll be using PostgresQL for the database, and want to access it via a GraphQL API.
To ease with maintainability, we looked at several intermediaries between client/API/database, mainly Prisma, PostGraphile and Hasura. PostGraphile stood out, because of ease of use and the focus of handling stuff "in database" as opposed to in your backend code. However, we ran into issues when figuring out how to implement this.
Allow me to expand on what we designed thus far:
Provisional database design:
users table
groups table
roles table:
u_g_r table: A user can be part of multiple groups, and can have multiple roles in each group. This table represents foreign keys for users, groups and roles, as many-to-many relations can exist in virtually all combinations.
Data Permissions:
We want users to grant others access to their personal data in several steps, preferably for each group. For example:
level 3: Yourself and only absolutely necesary people, such as account manager
level 2: Only people in group X, Y, etc
level 1: Everybody
It would be awesome if it was possible to set this for various types of data, for example grant level 2 for your phone number, but only level 1 for your physical address.
So, these levels (1, 2, 3) would accompany data in the database, like phone_number and phone_number_access_level for example. Then, in the u_g_r junction table, each combination of user/group/role would have an allowed level attached to it, which must be higher than the required level for the relevant data. Thus, if your role allowed access to data on level 2, you would be able to view data on level 1 and 2, but not level 3.
Postgres allows both column- and row level security, to let users access certain data. The PostGraphile wiki goes into some detail (here and here) how you would make this work with JWT claims instead of PostGres roles.
Our problem arrives when we want to implement the above features. It seems we want a kind of 'field level security' that does not exist, but I can't imagine others not having had the same issues.
What would you advive us to do? Please let me know if there are options we've missed, or whether there are other options that are better for us!
Implementing this outside the database, in backend code might might be the easiest way in and of itself, but it greatly impacts maintainability for us, as the main luxury of things like PostGraphile for us is removing the need to write GraphQL schema's and resolvers ourselves.
It seems that you want all users to see all table rows, but only certain columns.
You probably cannot use column permissions, because these can only allow or deny access to the column as a whole and do not respect who “owns” a certain table row.
So perhaps views can do what you want, for example:
CREATE VIEW users_view
WITH (security_barrier = true, check_option = local) AS
SELECT /* accessible to everyone */
username,
/* accessible only to certain groups */
CASE WHEN pg_has_role('x', 'USAGE') OR pg_has_role('y', 'USAGE')
THEN level2_col
ELSE NULL
END AS level2_col,
/* accessible only to admins and owner */
CASE WHEN username = current_user OR pg_has_role('admin', 'USAGE')
THEN level3_col
ELSE NULL
END AS level3_col
FROM users;
security_barrier makes sure that nobody can use functoins with side effects to subvert security, and check_option ascertains that nobody can INSERT a row that is not visible to themselves.
You can allow DML operations on the views if you define INSTEAD OF triggers.
Based on the answer of Laurenz Albe, I created an immense view for all kinds of columns. It worked, certainly, and even with several thousands of entries of mock data it was still relatively quick.
When I got back to it last week, a cleaner solution (arguably) dawned on me. Instead of using custom views like this, I'm now using separate tables with the sensitive data, link them with foreign keys and enable Row Level Security on these rows.
I haven't done any benchmarks, but it should be faster as this data isn't always requested anyways. It at least saves complicated views with a lot of boilerplate!

Why did PostgreSQL merge users and groups into roles?

From the PostgreSQL docs:
The concept of roles subsumes the concepts of "users" and "groups". In
PostgreSQL versions before 8.1, users and groups were distinct kinds
of entities, but now there are only roles. Any role can act as a user,
a group, or both.
Why did they make this change in 8.1?
Perhaps it's easier from the C coders point of view, with a single Role class (struct)?
More details:
CREATE USER is equivalent to CREATE ROLE except that CREATE USER gives the LOGIN permission to the user/role.
(I'm about to design a permission system for my webapp, hence I'm interested in this.)
The merge has many advantages and no disadvantages. For instance, you can now seamlessly convert a "user" to a "group" and vice versa by adding / removing the LOGIN privilege.
ALTER ROLE myrole LOGIN;
ALTER ROLE myrole NOLOGIN;
Or you can GRANT membership in any other login ("user") or non-login role ("group") to a role:
GRANT joe TO sue;
You can still:
CREATE USER james;
That's just a role with login privilege now. Or:
CREATE GROUP workers;
That's effectively the same as CREATE ROLE now.
The manual has it all.
I found this thread in the PostgreSQL-Hackers list, from June 6, 2003, that in the end suggests that users and groups and roles be consolidated. (Thanks Craig Ringer for suggesting that I check the pgsql-hackers list archives.)
Here are some benefits mentioned (those that I found).
allow groups to have groups as members
the ACL code would be simplified
the GRANT/REVOKE syntax and the display format for ACL lists could be
simplified, since there'd be no need for a syntactic marker as to
whether a given name is a user or a group.
In some circumstances I could see it making sense to allow logging in
directly as a group/role/whatchacallit
This would also solve the problem that information_schema views will
show only owned objects
[makes it easier to] representing privileges granted to groups [since
you'd simply reuse the role related code?]
From the manual:
The SQL standard defines the concepts of users and roles, but it
regards them as distinct concepts and leaves all commands defining
users to be specified by each database implementation. In PostgreSQL
we have chosen to unify users and roles into a single kind of entity.
Roles therefore have many more optional attributes than they do in the
standard.
Having a distinction between users and groups doesn't gain you anything.
AFAIK the motivation for changing it was to simplify uses like:
One user masquerading as another, eg a superuser simulating a reduced permissions user. With unified roles this becomes just another change of current role, no different to changing primary group.
Groups that are members of other groups to implement granular access permissions.
If you want the details, though, you're best off checking out the archives of the pgsql-hackers list for the period, and the git history (converted from CVS).