Using Postgres PGCrypto encryption requires superuser to run view queries - postgresql

Using: Postgres 9, CentOS 7,
Postgres Data directory not in default location but used RSync to make sure permissions were correct. And yes appropriate .config files were changed.
When I try to query a view containing an encrypted item as a NON superuser (Testuser), I get this error:
ERROR: must be superuser to read files CONTEXT: PL/pgSQL function
decrypt_data(bytea) line 13 at assignment
If I run that same query using POSTGRES superuser, the query completes fine.
This seems to be a file system read permission error when trying to read the Key files. Everything I see using encryption seem to not mention how to run without being superuser.
I have already run the following grants for Testuser:
GRANT ALL PRIVILEGES ON DATABASE xxx_db to Testuser;
GRANT SELECT ON ALL TABLES IN SCHEMA xxxxx TO Testuser;
GRANT ALL ON ALL TABLES IN SCHEMA xxxxx TO Testuser;
The test user can create tables, views, basically anything within that db.. just not read encryption keys.
The permissions on the keys are 775 right now, I even tried 777 without luck.
Any Ideas?

pgcrypto is a PostgreSQL extension described here:
https://www.postgresql.org/docs/current/static/pgcrypto.html
but it doesn't provide a decrypt_data(bytea) function.
This function seems to be custom code that happens to open a server-side file, with pg_read_file() or a similar method.
These methods are restricted to superusers to avoid normal users to read on the server's filesystem, no matter what are the Unix rights of the particular file they want to read.
You can verify this in the source of decrypt_data(bytea), which can be obtained with:
select pg_get_functiondef('decrypt_data(bytea)'::regprocedure);
or \df+ decrypt_data(bytea) from within psql.

I found the issue. I need to grant the user with function permissions.
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA xxxxx TO yyyyyyyyy;

Related

How do I resolve a "permission denied for schema public" error for PostgreSQL on GitHub Actions?

I've been working on maintenance on this GitHub repo that has been left undeveloped for almost a year. When rerunning the GitHub Actions job that finished to completion last May, there are now issues related to permission for CREATE in the public schema in PostgreSQL. At first I suspected, this might be because of the recent PostgreSQL 15 update that made it so that users do not by default have create access on the public schema. However, for our job GitHub Actions uses Postgres 14 for Ubuntu 22.04 (postgresql_14+238), so this change to public schema access in PostgreSQL shouldn't be affecting us. Our previous passing run used Postgres 12 for Ubuntu 20.04 (postgresql-12_12.10-0ubuntu0.20.04.1), so the changed environment could still be relevant.
The job is erroring out during a step where we create a few tables within our database using <user>:
peewee.ProgrammingError: permission denied for schema public
LINE 1: CREATE TABLE IF NOT EXISTS "articles" ("id" INTEGER NOT NULL...
Before this step, we configure the PostgreSQL database, creating the <user> and granting it all permissions to the database: `
CREATE USER <user>;
GRANT ALL PRIVILEGES ON DATABASE <db_name> to <user>
To remedy this problem (while still being confused on why it arose), I tried to explicitly grant <user> permissions on the public schema before attempting any CREATEs following the suggestions from this post: https://www.cybertec-postgresql.com/en/error-permission-denied-schema-public/
GRANT ALL ON SCHEMA public TO <name>;
which seems to go through based on the returned GRANT .
Locally, I'm having no issues with permissions even without the GRANT using PostgreSQL 14, but the permission error still comes up on GitHub Actions, even after granting access to the public schema to the user (and in a desperate attempt--to all users).
I've done a bunch of sanity checks related to making sure that we are in fact using the <user> during the CREATE step, but it seems like the <user> just never ends up getting the permissions even after the GRANT. I followed postgresql - view schema privileges to view schema privileges, and locally, the <user> has permissions to the public schema even before the GRANT. However, on GitHub Actions, the <user> doesn't have permissions before nor after the GRANT, even though there is output confirmation that the GRANT completed successfully.
Does anyone know why I would be having these permission errors now on GitHub Actions, despite the code working locally and on GitHub Actions months ago? Is there any way I can grant permissions differently that might work better in this environment?
The permissions on schema public changed in v15. This change finally got rid of the insecure default setting of letting every user create objects in that schema. Now only the database owner is allowed to create objects by default.
Your GRANT statement is good to allow a user to create objects in schema public:
GRANT CREATE ON SCHEMA public TO user_that_creates_objects;
Just remember that you have to connect to the target database before running that statement. Also, the GRANT must be executed by the database owner or a superuser.
My recommendation is to leave the public schema for extension objects and create your own schema for your application objects.

How to GRANT priveleges to non-superuser to execute function pg_read_binary_file?

In PostgreSQL I have a database with a custom function witch loads binary content of the file in database table by using the system function pg_read_binary_file.
If I ran this custom funtion under a user with superuser rights, it executes successfuly. But when the user does not have superuser rights, I receive an error:
permission denied for function pg_read_binary_file
I thought that all that I need is to simply GRANT permissions to EXECUTE the funtion for such user, so I did the following:
GRANT EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint,boolean) TO someuser;
GRANT EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint) TO someuser;
GRANT EXECUTE ON FUNCTION pg_read_binary_file(text) TO someuser;
If I check the permissions by
SELECT proacl FROM pg_proc WHERE proname='pg_read_binary_file';
I get:
{postgres=X/postgres,someuser=X/postgres}
{postgres=X/postgres,someuser=X/postgres}
{postgres=X/postgres,someuser=X/postgres}
As I understand, now someuser has permission to execute the function pg_read_binary_file. But when I try to run my custom function, I still receive the same error:
permission denied for function pg_read_binary_file
So the question is how to give permission to a non-superuser to execute the function pg_read_binary_file? Maybe there are some additional permissions that must be granted, but it is not obvious.
In the documentation on Portgres system functions for pg_read_binary_file it is written that:
Restricted to superusers by default, but other users can be granted EXECUTE to run the function.
I searched for some additional information about the way how can I give such permissions, but without luck.
There are three possibilities:
You are using an old PostgreSQL version.
Before commit e79350fef2917522571add750e3e21af293b50fe, this was not governed by permissions on the functions, but by hard-coded checks in the function itself.
This doesn't seem to be your case, however, because the error messages would then read:
ERROR: must be superuser to read files
You are not someuser when you try to execute the function. Test with
SELECT current_user;
You are connected to a different database (e.g., you changed the permissions in the postgres database, but someuser connects to a different database).

Database named "postgres"

I've just set up Postgres for use by different users on my network. Every user has his own username/password/database, but when I connect to Pg I can also see a 'postgres' database (and even create tables etc). I tried to REVOKE access to that database from public but then it won't let me connect. What exactly is the postgres database and why is it needed? Can I disable it so that users only see the database(s) I've created for them?
The postgres database is created by default when you run initdb.
Quote from the manual:
Creating a database cluster consists of creating the directories in which the database data will live (...) creating the template1 and postgres databases. When you later create a new database, everything in the template1 database is copied. (...) The postgres database is a default database meant for use by users, utilities and third party applications.
There is nothing special about it, and if you don't need it, you can drop it:
drop database postgres;
You need to do that as a superuser of course. The only downside of this is that when you run psql as the postgres operating system user, you need to explicitly provide a database name to connect to
If you drop the postgres database you'll find a few things to be confusing. Most tools default to using it as the default database to connect to, for one thing. Also, anything run under the postgres user will by default expect to connect to the postgres database.
Rather than dropping it, REVOKE the default connect right to it.
REVOKE connect ON DATABASE postgres FROM public;
The superuser (usually postgres), and any users you explicitly grant rights to access the database can still use it as a convenience DB to connect to. But others can't.
To grant connect rights to a user, simply:
GRANT connect ON DATABASE postgres TO myuser;

Why can only a superuser CREATE EXTENSION hstore, but not on Heroku?

When I attempt to enable hstore on my database:
=> CREATE EXTENSION IF NOT EXISTS hstore;
ERROR: permission denied to create extension "hstore"
HINT: Must be superuser to create this extension.
My user is not a superuser, but is the owner of the database.
According to the CREATE EXTENSION docs:
Loading an extension requires the same privileges that would be required to create its component objects. For most extensions this means superuser or database owner privileges are needed. The user who runs CREATE EXTENSION becomes the owner of the extension for purposes of later privilege checks, as well as the owner of any objects created by the extension's script.
What is hstore doing that requires superuser privileges? Is it affecting parts of the cluster outside the database I'm adding it to?
Further confundity:
The DB user Heroku Postgres provides is not a superuser:
Heroku Postgres users are granted all non-superuser permissions on their database. These include SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, and USAGE.
However, that user is able to CREATE EXTENSION hstore:
To create any supported extension, open a session with heroku pg:psql and run the appropriate command:
$ heroku pg:psql
Pager usage is off.
psql (9.2.4)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
ad27m1eao6kqb1=> CREATE EXTENSION hstore;
CREATE EXTENSION
ad27m1eao6kqb1=>
(For context, I'm attempting to set up a Dokku deployment, so the comparison to Heroku is especially important.)
The hstore extension creates functions that call code from an external dynamic object, which requires superuser privilege. That's why creating the hstore extension requires superuser privilege.
As for Heroku, it is my understanding that they are running with a special extension whitelisting module, which allows users to create certain extensions even though they are not superusers. I believe it is based on this code: https://github.com/dimitri/pgextwlist. You can try to install that code yourself if you want the same functionality in your databases.
ALTER USER myuser WITH SUPERUSER;
If you run this command from a superuser, this solves your CREATE EXTENSION issue. You may check your available users with \du to find a superuser.
This is not related to heroku.
This is how I solved this issue in ubuntu 18.04.
Provide postgres super user access.
sudo su postgres
Then I run:
psql -U postgres your_database_name -c 'create extension hstore;'
Now I can alter table your_database_name and add hstore type columns in it.
Connect to your database
psql -d your_database_name -U your_user_role
And
alter table your_table_name add your_column_name HSTORE;
Though there might be saveral different ways to do it, but I solve it in this way.
Hope this will help novice users like me.

Why can I not set permissions on fresh install of PostgreSQL

A fresh installation of PostgreSQL 9.3 (according to the YUM Installation manual on the PostgreSQL wiki) on CentOS 6 (64-bit) will not grant permissions to any users.
I log in to the postgres user and open psql, then I create a role for my default user:
CREATE ROLE <name> WITH PASSWORD '<password>';
and then try to grant it privileges on the default postgres database:
GRANT ALL ON DATABASE postgres TO <user>;
which gives the expected output, but the user does not have any permissions on postgres.
The output of \dp <user> is quizically empty as well. Additional testing shows that I cannot give any users permissions. However, when I try to drop a role that has been granted these nonexistent permissions, it says
ERROR: role "<user>" cannot be dropped because some objects depend on it
DETAIL: privileges for database postgres
I am at a loss. I did also check to make sure the postgres Linux user has the appropriate file permissions on the PostgreSQL data directory.
Presumably you're expecting too much of GRANT ALL ON DATABASE postgres TO <user>;
ALL in this context means that the command is equivalent to:
GRANT CREATE,CONNECT,TEMPORARY ON DATABASE postgres TO <user>;
And the way you create the ROLE, it cannot login to any database anyway (you can check this with \du).
It could if it was created with:
CREATE ROLE name WITH LOGIN PASSWORD 'pass';
or use ALTER ROLE name WITH LOGIN later on.
Starting from this, to give the user permissions to create objects in the database, other forms of GRANT should be used.