I am mucking around with postgres row level security for multi tenant applications. I want achieve this via a policy which separates rows based on the tenant_name which is a column in my tables. I have roles for each tenant. However, I am maintaining a connection pool by connection via a superuser. This is so that i can have only one connection pool. Once i have a query from a tenant, i want to drop privileges to that tenant first and then execute the query.
So I connect to the database as a superuser, and then i do "set session authorization tenant_role". This sets the session_user and current_user variables. However, the problem is that this tenant user can himself do a "set session authorization some_other_tenant" and then Row security doesn't matter. I am guessing that this happens because the DB login context is the superuser.
So how do i achieve this ? Once i do "set session authorization" or "set role" to some user , that user should not be able to run the same thing again.
Thanks
You may want to read this, for your answer.
Essentially, create a no-privilege user and login to the pool via that (instead of connection pooling as a supervisor role). Once logged in, then escalate the role to the actually connected user. The URL above tells you how to do that.
What I am unable to understand is that if this is an uncontrolled environment, then even with this solution, a user can escalate to someone else's role and still play havoc. So although even if this answers the question, it may still not be what you want to eventually do!
Related
I'm trying to understand the initial steps of PostgREST tutorial.
In the mentioned tutorial, it is recommended to create two different roles named web_anon and authenticator as below:
create role web_anon nologin;
grant usage on schema api to web_anon;
grant select on api.todos to web_anon;
create role authenticator noinherit login password 'mysecretpassword';
grant web_anon to authenticator;
As far as I know, the the PostgREST server receives Rest API requests from the clients, without any information about the user (role). And also, as far as I know, nologin roles can't do login to database. (can they send queries?)
So the questions are:
why do we need two different roles? What is the role of web_anon and what is the role of authenticator?
What can a nologin role do in postgres?
When PostgREST receives a rest API query, which user does it use to send and execute that query to the database?
To question 1:
A NOLOGIN role can be seen as a user group. The idea is to attach all privileges to a group rather than to individual users, which has several advantages:
It is possible to drop the user, because it does not have any privileges.
It is less work to add a user to a group or remove a user from a group than to grant or revoke lots of permissions whenever you have to add a user or change its privileges.
There is no danger of having so many individual ACL entries attached to a single database object that it becomes impossible to add more permissions (the whole metadata row has to fit into a single 8kB block).
This whole exercise only makes sense if you have many users in the database, otherwise it is silly. But it is a good idea to have different users for different purposes.
To question 2:
A NOLOGIN role can either be a group that carries privileges that users can inherit.
Another use is that you can use SET ROLE to assume the identity of the role.
To question 3:
I guess whatever user you use in the PostgreSQL connect string.
We saw PostgreSQL roles in class this year. Our teacher told us that it is more secure to use different roles with custom rights for every table or even column if necessary.
We have a project in which we have to use PostgreSQL to build a website with restricted access for connected users, who can be of different types (admin, employee, client). To follow the teacher's recommendations, we created different roles with different rights (one for each type of user).
We decided to use Go for our back end (with token auth) but I can't figure it out how to use our roles, which are more groups than users. I read in the doc that you "open" the connection to the DB once for all but to do so you have to give a PostgreSQL role. I didn't find a way to change the connected role without closing and reopening the DB. If I run the application without changing connected roles, how can PostgreSQL control if a user has the right to access tables he needs for the requests.
You can change roles on the fly in PostgreSQL. If you are logged in as nobody, and nobody is a member of role cleve, you can become role admins with
SET ROLE cleve;
But using that during authentication is problematic, because there is nothing that keeps the user from running the statement
RESET ROLE;
to become nobody again and then impersonating somebody else.
Typically, there are two ways how you can use the role system to leverage database permissions:
You have a personalized database user for every user of the application.
That is of course only feasible if the set of users is fairly constant and limited.
Then the individual users have no permissions at all, and there are certain roles like admin, reader, accountant and so on. The login roles are assigned permissions by becoming members of one or more of these roles, and they inherit their permissions.
You don't have personalized database users.
Then you only have one login role per set of permissions, say accountant, admin, viewer and so on.
The application has to decide as which user it should connect before establishing the database connection. If you need database queries for this decision, you perform those as a nobody database user with very limited permissions. For example, it may call a function that verifies a user-supplied password.
You can use the set role command to change the role while the session is open.
I have a server that will manage multiple Firebird databases. My users are allowed to have full access on all the objects for a single database but they are not allowed to create new database and no access to other databases in the same server. How do I configure for this scenario?
Since Firebird 3, users need to have an explicit privilege to create databases (Database DDL Privileges). So as long as you don't grant that privilege to a user, they cannot create a database (unless they have and apply the RDB$ADMIN role).
Giving a user access to everything in a database is harder to do. You'll need to define the access for each database object individually. The preferred way to do that, is to grant the necessary access to a role, and grant that role to the user. See SQL Privileges for details.
In Firebird 3 and earlier, users do not assume the rights of a role unless they explicitly specify that role on connect. Firebird 4 will introduce default roles, which will always be applied. It might be possible to use Firebird 3 privilege mapping to define a default role as well, but I'm not sure if that works.
Firebird does not provide a way to disallow a user to connect to a database: almost all rights are stored per database, so a user has to connect before the server knows which rights they have. If you want to disallow users to connect, you will need to create a custom ON CONNECT trigger to raises an exception for users that shouldn't be allowed to connect.
I know there are other threads that are similar, but I am not sure if they are relevant to Postgres.
I am reading the PostgreSQL documentation which it reads as follows:
Note: As explained in Chapter 20, PostgreSQL actually does privilege
management in terms of "roles". In this chapter, we consistently use
database user to mean "role with the LOGIN privilege".
Does this basically mean a role is a database user? Or is there a difference between a role and a user? Do users have the potential to not have full privileges while roles are users who always do have full privileges?
Previous versions of Postgres, and some other DB systems, have separate concepts of "groups" (which are granted access to database objects) and "users" (who can login, and are members of one or more groups).
In modern versions of Postgres, the two concepts have been merged: a "role" can have the ability to login, the ability to "inherit" from other roles (like a user being a member of a group, or a group being a member of another group), and access to database objects.
For convenience, many tools and manuals refer to any user with login permission as a "user" or "login role", and any without as a "group" or "group role", since it is useful and common practice to keep roughly to that structure. This is entirely a convention of terminology, and to understand the permissions, you need only understand the options available when creating roles and granting them access.
Again purely for convenience, Postgres still accepts commands using the old terminology, such as CREATE USER and CREATE GROUP which are both aliases for CREATE ROLE. If you write CREATE USER, the LOGIN permission will be added to the new role by default, to emulate the old behaviour when that was a separate command.
I found this link pretty useful.
The final goal is that some user/role can readwrite, some rule/user can be only read.
https://aws.amazon.com/blogs/database/managing-postgresql-users-and-roles/#:~:text=Users%2C%20groups%2C%20and%20roles%20are,to%20log%20in%20by%20default.&text=The%20roles%20are%20used%20only,grant%20them%20all%20the%20permissions.
Users, groups, and roles
Users, groups, and roles are the same thing in PostgreSQL, with the only difference being that users have permission to log in by default. The CREATE USER and CREATE GROUP statements are actually aliases for the CREATE ROLE statement.
enter image description here
In other relational database management systems (RDBMS) like Oracle, users and roles are two different entities. In Oracle, a role cannot be used to log in to the database. The roles are used only to group grants and other roles. This role can then be assigned to one or more users to grant them all the permissions. For more details with a focus on how to migrate users, roles, and grants from Oracle to PostgreSQL, see the AWS blog post Use SQL to map users, roles, and grants from Oracle to PostgreSQL.
I want to look further into the PIDs listed in pg_stat_activity to know what their last succesful call to SET SESSION AUTHORIZATION set their session authorization to. Which table or view do I need on PostgreSQL 9.0?
PostgreSQL doesn't expose that information, at least in 9.4 or any prior version.
The user id in pg_stat_activity is the login user; it's the user that RESET SESSION AUTHORIZATION goes back to. It won't change when you SET SESSION AUTHORIZATION or SET ROLE.
Information about the current effective session authorization and current role are internal to the backend. You can access them locally to the backend with SELECT current_user, current_role, etc, but there's no inter-process way to get at them.
It might be nice to have that, if it could be added without making it more expensive to maintain pg_stat_activity or to query it. You'd need to get into PostgreSQL's guts and develop a patch to expose the information, though.
Surprisingly, log_line_prefix doesn't seem to include format symbols to show the effective role and effective session user. Given the use of session authorization by PgBouncer that's sufficiently odd that I feel like I must have missed something.
In any case, the only way I see to do this is to dig through the logs, logging pid and session ID then associating successful SET SESSION AUTHORIZATION calls with subsequent statements.