How to set default owner of objects created by EF core code first using postgresql with database credential rotation? - postgresql

I am connecting from a containerized asp.net core 3.1 application running code-first EF core to an Amazon Aurora instance with PostgreSQL compatibility and wish to perform database credential rotation. I have set up a role representing the database owner, and a role representing the current valid login credentials that we will expire and replace with new credentials.
I have followed the suggestion from this blog post:
http://davidhollenberger.com/2017/03/16/postgres-credential-rotation/, which is essentially:
create role db_owner nologin;
create role foo_a with encrypted password ...;
grant db_owner to foo_a;
alter role foo_a set role db_owner;
I understand that whenever foo_a logs in to postgres, their default role is set to db_owner. If I log into the database using psql this seems to work consistently.
However, with EF Core, when connecting using the foo_a database credentials migrating the database to a new schema the object owner of new objects is listed as foo_a.
Example:
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------------------------------------
public | test | table | foo_a
I expected the owner to be db_owner, since foo_a should always log in as db_owner.
Is there something I can do, either from EF Core, or when setting up the postgresql database that will allow us to set default ownership for all objects created by the user to the role group representing our database owner? I do not wish to make these temporary accounts some kind of 'superuser' for the instance, since we have multiple tenants in our database instance, instead I wish to have something similar to a 'dbo' role that has ownership of the database and the temporary users will always connect as the 'dbo' role.

Pooled connections are reset using the DISCARD ALL statement, which in turn resets the session and current user identifiers to be the originally authenticated user name. In other words:
Pooled connection reset (https://www.npgsql.org/doc/performance.html#pooled-connection-reset)
Runs DISCARD ALL (https://www.postgresql.org/docs/current/sql-discard.html)
Which in turn runs SET SESSION AUTHORIZATION DEFAULT (https://www.postgresql.org/docs/8.1/sql-set-session-authorization.html)
During a db migration, this sets the owner of any objects created to the user instead of the dbo role that he automatically inherits by ALTER ROLE... SET ROLE...
Options to resolve this issue will depend on your needs. Here are a few options we considered to resolve this question:
Make the db owner a member of the db user. Supplement this with a script that runs as part of our database/user provisioning and rotation strategy that sets all object ownership to the owner instead of the user. This requires zero code changes for the .net core app, but does seem messy from the perspective of object ownership.
In .Net use an IDBCommandInterceptor to set the appropriate role when we reuse a connection from the pool. This is a more invasive solution affecting your .net core project, but if your requirements involve credential rotation for one or only a few projects it may be practical.
Append the option No reset on close=true to the npgsql connection string. However, be aware that this risks leaking session state if you are using connection pooling. Reference: https://www.npgsql.org/doc/connection-string-parameters.html#performance
Other options, such as running a proxy are also worthy of consideration.

Related

How to set or change role upon login automatically in postgres?

I have an existing postgres 11 database called host_db and we have an existing application called host_app that has been using this database for a long time. This service uses superuser host_app_user to connect to database and do all the transactions. Hence, all the database objects are owned by this database superuser.
Now, we want to create db_admin superuser role too in our database whose credentials will be maintained by Vault. But to not mix up database ownership, I was thinking that whenever db_admin logs in to the database, it assumes the role of host_app_user. That way whatever changes the logged admin does will all be done as host_app_user.
My question is: Is there a way I can automatically set the role of logged in user in postgres at the time of logging in?
Use:
alter role db_admin set role host_app_user;
db_admin's role will be set to host_app_user on login.
Note though that db_admin must be a member of host_app_user.
I think the answer is no. But you could do this:
grant db_admin to host_app_user;
Then host_app_user will have all the permissions that db_admin has.

How to block update to the postgresql database

We have a production postgres database which is accessible by all team members.
We use pgadmin to administer the database.
For safety reasons, I am willing to make the database readonly. So that, only data can be viewed and cannot be modified
(blocking any update operation to the database).
If any database update is required, then I can make the database to readwrite mode, make the modification
and change to readonly again.
There are ROLES AND PRIVILEGES options which can be used for achieving this functionality.
But I am wondering if there is any Pgadmin UI options for making the database readonly.
Thanks in advance.
Why don't you use Roles and Privileges ??
create multiple users
master_user
readonly_user
etc
Once you have users created, you can grant access on database/ schema or even table level.
Share the readonly user with the team and keep the master user for admins / applications etc
More info on postgres roles and privileges: https://www.postgresql.org/docs/current/user-manag.html

Azure PostgreSQL cant Assign BYPASSRLS to a ROLE

I am trying to create a role in Azure PostgreSQL that is allowed to bypass row level security so I can run backups which do not fail when row level security is enabled for all users apart from my backup user:
ALTER TABLE jobschedule.jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE jobschedule.jobs FORCE ROW LEVEL SECURITY;
When I try and assign the role using the admin supplied by Azure I get the following error message:
ALTER ROLE srvdevadmin BYPASSRLS;
ERROR: must be superuser to change bypassrls attribute
I checked the privileges and it seems that it is not possible in Azure PostgreSQL to assign superuser to a user. Any ideas how I can assign BYPASSRLS to users?
As an update to any one who is trying to do this, I contacted Azure support and they confirmed at the present time it is not possible in Azure PostgreSQL to assign BYPASSRLS to a role and the product team has no plans to implement this.
https://feedback.azure.com/forums/597976-azure-database-for-postgresql/suggestions/34044541-enable-the-ability-to-assign-bypassrls-to-postgres
I created a suggestion on their feedback site so if you would like this functionality it is probably worth up-voting it.

Application Roles in PostgreSQL

On this site SQLDude talks about Application roles for MSSQL Server.
A more secure approach you could use for this is called "Application Roles". When connecting from an application you assume a particular role and only that role is granted privileges required in the database. So all apps connect via this mechanism and don’t give out SQL or NT logins for any unauthorised use. You will have to call sp_setapprole in your application with a password, once the connection is established. Once this call succeeds then the connection gets the privileges of the application role and loses privileges of the actual user, which is what we want. So if someone tried to connect to the database from SSMS or SQLCMD, they will access the DB using their credentials, which won’t have the required permissions on the tables, since only the application role has the rights on the tables. This is more secure & reliable approach, but one that requires application code change and as a DBA you will have to create the application role in SQL Server.
However i can't find the equivalent for PostgreSQL?
Is there something like this available in PostgreSQL?

Postgres ACL for Schemas

I'm not a DBA and I have got some questions around access controls for schemas. Let's say I have a Postgres server running a several databases. The admin user is postgres. I have another user tmpUser with which I could log in to the remote server using pgadmin3 client.
I now create a database called myDatabase which is by default owned by the postgres user. I then use my admin client to remotely log in to this myDatabase using the tmpUser account.
I now create a new schema inside this myDatabase called myDbSchema. I created a new role called myDbRole and did a grant usage, grant all on myDatabase, myDbSchema to the myDbRole.
The question now is how should I control access to this myDatabase. I tried to log in to the remote server using the tmpUser and when I tried to execute select * from myTable where myTable is a table in myDatabase, it came back with a permission denied sql message. So I changed the owner of the table to the tmpUser which I really do not want to!
Is there a guide or something on how I should go about creating and organizing roles with schemas in postgres?
It is not entirely clear what your problem is (for instance, what is role "myDbRole" for, is that a group role (NOLOGIN) or a user role (LOGIN)?) but in general you could follow this pattern of permission management:
Create a specific role to own a database and all or most of the objects in it. This should be a group role (NOLOGIN) for security reasons. Do not use the postgres user; if you need to login as that role often to do regular database work, you are doing something wrong. Any superuser (or other user role that has that role granted to it) can "impersonate" that owner role using SET SESSION AUTHORIZATION to do necessary maintenance. In a production environment this should be hardly ever necessary; during development you might want to consider making the role with LOGIN permission for ease of use.
The owner creates all the schemas, tables, views, functions, etc. that you need for your application. By default, all of those objects are only available to the database owner, with the exception of functions.
Define a number of group role profiles, each having specific requirements of the database. You could have, for instance sales_staff, product_managers, accounting and senior_management for a company, or web_user, web_admin, app_developer and app_manager for a web site. The database owner then GRANTs access to the database (CONNECT), schemas (USAGE), tables, views and functions (EXECUTE), as needed. I usually REVOKE ALL ON FUNCTION x() TO public, for security reasons.
Assign group role membership to user roles, as needed: GRANT sales_staff TO jane. The user roles should have LOGIN INHERIT such that they can log in and inherit the permission of group roles that they are a member of. That includes the permission to connect to a database and usage rights on schemas. Note that a single user role can have membership in multiple group roles.
Lastly, update your pg_hba.conf file to enable remote access to the database.