I have a table MYSCHEMA.TEST_SNOWFLAKE_ROLE_T in Snowflake created using the role CONSOLE_USER.
MYSCHEMA has a FUTURE GRANTS associated with it, which grants the following privileges to the role BATCH_USER for any table created under the schema MYSCHEMA - DELETE, INSERT, REFERENCES, SELECT, TRUNCATE, UPDATE.
The role BATCH_USER also has CREATE STAGE and USAGE privileges on the schema MYSCHEMA.
A second user belonging to the role BATCH_USER tries to insert data into the same table from a dataframe, using the following Spark SQL (Databricks), but fails with an insufficient privileges error message.
df.write.mode(op_mode) \
.format("snowflake") \
.options(**self.sfoptions) \
.option("dbtable", snowflake_tbl_name) \
.option("truncate_table", "on") \
.save
The following error message appears:
Py4JJavaError: An error occurred while calling o908.save.
: net.snowflake.client.jdbc.SnowflakeSQLException: SQL access control error
: Insufficient privileges to operate on table 'TEST_SNOWFLAKE_ROLE_T')
The role CONSOLE_USER has ownership rights on the table, hence the role BATCH_USER would not be able to drop the table, but adding the option option("truncate_table", "on") should have prevented automatic overwrite of the Table schema.
I've gone through the available Snowflake and Databricks documentation several times, but can't seem to figure out what is causing the insufficient privilege issue.
Any help is much appreciated!
I figured it out eventually.
The error occured because the table was created by the role CONSOLE_USER, which retained ownership privileges on the table.
The Spark connector for Snowflake uses a staging table for writing the data. If the data loading operation is successful, the original target table is dropped and the staging table is renamed to the original target table’s name.
Now, in order to rename a table or swap two tables, the role used to perform the operation must have OWNERSHIP privileges on the table(s). In the situation above, the ownership was never transferred to the role BATCH_USER, hence the error.
df.write.mode(op_mode) \
.format("snowflake") \
.options(**self.sfoptions) \
.option("dbtable", snowflake_tbl_name) \
.option("truncate_table", "on") \
.option("usestagingtable", "off") \
.save
The solution was to avoid using a staging table altogether, although going by the documentation, Snowflake recommends using one, pretty strongly.
This is a good reference for troubleshooting custom privileges:
https://docs.snowflake.net/manuals/user-guide/security-access-control-overview.html#role-hierarchy-and-privilege-inheritance
Is the second batch_user inheriting any privileges?
Check on this by asking the user in their session to see what privileges they have on the table: https://docs.snowflake.net/manuals/sql-reference/sql/show-grants.html
What are the grants listed for the Batch_user having access issues to the following:
SHOW GRANTS ON
SHOW GRANTS OF ROLE
SHOW FUTURE GRANTS IN SCHEMA { }
Was a role specified for the second batch_user when they tried to write to "dbtable"?
"When a user attempts to execute an action on an object, Snowflake compares the privileges available in the user’s session against the privileges required on the object for that action. If the session has the required privileges on the object, the action is allowed." ref:
Try: https://docs.snowflake.net/manuals/sql-reference/sql/use-role.html
3.Since you mentioned Future Grants were used on the objects created - FUTURE be ing limited to SECURITYADMIN via https://community.snowflake.com/s/question/0D50Z00009MDCBv/can-a-role-have-rights-to-grant-future-rights
Related
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.
I'm building a spring boot application. Flyway database migrations are executed at the application startup.
I decided to use two different roles: role__app (read/write rights on tables, sequences in app schema) and role__migration (advanced rights in app/migration schemas).
Flyway migrations are executed under role__migration so it becomes the owner of the created objects. I thought that the following statements would help:
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO role__app;
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT USAGE ON SEQUENCES TO role__app;
But when the new tables are added to the app schema the user__app (belongs to the role__app) doesn't have access to the tables.
Is it possible to maintain such a flow (with app, migrattion users/roles) by Postgres or by any other means?
As a side note I should mention that I run the following statements on the target database:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON DATABASE myDb FROM PUBLIC;
Update 1
I added the FOR ROLE clause, yet I'm still getting the permission denied message for a created table (app.property) in app schema for user user__app. The owner of the table is user__mig.
Update 2
After logging in as postgres user in dbeaver we can see that user__mig has all necessary permissions ticked whereas the user__app has no permissions on the app.property table at all:
Here is a gist to reproduce the problem: https://gist.github.com/happygrizzly/849a6a791f028ba5b191f73180ae35d1
You should write
ALTER DEFAULT PRIVILEGES FOR USER role__migration ...
If you omit the FOR USER clause, the privileges are only granted on objects created by the user who ran ALTER DEFAULT PRIVILEGES.
With the above statement, the privileges are granted when role__migration creates an object. That does not extend to members of the role role__migration.
I'm building a spring boot application. Flyway database migrations are executed at the application startup.
I decided to use two different roles: role__app (read/write rights on tables, sequences in app schema) and role__migration (advanced rights in app/migration schemas).
Flyway migrations are executed under role__migration so it becomes the owner of the created objects. I thought that the following statements would help:
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO role__app;
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT USAGE ON SEQUENCES TO role__app;
But when the new tables are added to the app schema the user__app (belongs to the role__app) doesn't have access to the tables.
Is it possible to maintain such a flow (with app, migrattion users/roles) by Postgres or by any other means?
As a side note I should mention that I run the following statements on the target database:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON DATABASE myDb FROM PUBLIC;
Update 1
I added the FOR ROLE clause, yet I'm still getting the permission denied message for a created table (app.property) in app schema for user user__app. The owner of the table is user__mig.
Update 2
After logging in as postgres user in dbeaver we can see that user__mig has all necessary permissions ticked whereas the user__app has no permissions on the app.property table at all:
Here is a gist to reproduce the problem: https://gist.github.com/happygrizzly/849a6a791f028ba5b191f73180ae35d1
You should write
ALTER DEFAULT PRIVILEGES FOR USER role__migration ...
If you omit the FOR USER clause, the privileges are only granted on objects created by the user who ran ALTER DEFAULT PRIVILEGES.
With the above statement, the privileges are granted when role__migration creates an object. That does not extend to members of the role role__migration.
Yesterday I created a user to make backups from PostgreSQL. I granted select to this user and then I noticed that the name was not well written. The problem is that I tried to erase the user using the command line and the response was, due to the grants that I made a few moments back:
ERROR: role "dump_user" cannot be dropped because some objects depend on it
Long story short, I erased this user using pgadmin and now I have problems because when I want to create a new table, it tells:
ERROR: role 313898229 was concurrently dropped
I cheked and 313898229 was the oid of this dump_user in the pg_authid table, I tried to create a new user and assign this oid, but postgres says that I can't modify system id "oid".
Is there a way that I can permanently erase this user?
If all you wanted was a different name:
ALTER ROLE dump_user RENAME TO better_name;
Too late for that now. Before deleting the role you should have run:
REASSIGN OWNED BY pg_dump TO postgres; -- postgres being default superuser role
Read details here:
Find objects linked to a PostgreSQL role
Your error message:
ERROR: role 313898229 was concurrently dropped
is defined in the source code here. Looks like a race condition between two transactions. But you omitted relevant details.
I need to restrict a user, access only on a particualr schema tables only.So I tried following query and login as user1_gmail_com. But I got following error when I try to browse any schema table.
My Query:
SELECT clone_schema('my_application_template_schema','user1_gmail_com');
CREATE USER user1_gmail_com WITH PASSWORD 'myloginpassword';
REVOKE ALL ON ALL TABLES IN SCHEMA user1_gmail_com FROM PUBLIC;
GRANT SELECT ON ALL TABLES IN SCHEMA user1_gmail_com TO user1_gmail_com;
SQL error:
ERROR: permission denied for schema user1_gmail_com at character 46
In statement:
SELECT COUNT(*) AS total FROM (SELECT * FROM "user1_gmail_com"."organisations_table") AS sub
Updated Working Query:
SELECT clone_schema('my_application_template_schema','user1_gmail_com');
CREATE USER user1_gmail_com WITH PASSWORD 'myloginpassword';
REVOKE ALL ON ALL TABLES IN SCHEMA user1_gmail_com FROM PUBLIC;
GRANT USAGE ON SCHEMA user1_gmail_com TO user1_gmail_com;
GRANT SELECT ON ALL TABLES IN SCHEMA user1_gmail_com TO user1_gmail_com;
You need to grant access not only to the tables in the schema, but also to the schema itself.
From the manual:
By default, users cannot access any objects in schemas they do not own. To allow that, the owner of the schema must grant the USAGE privilege on the schema.
So either make your created user the owner of the schema, or grant USAGE on the schema to this user.
This confused me. Still not sure I'm handling it correctly. Run \h grant for the syntax within psql. Here is how I managed to get my other users and groups to work as I needed:
GRANT ALL PRIVILEGES ON SCHEMA foo TO GROUP bar;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO GROUP bar;
I kept getting this error when using flyway to deploy database changes. I do some manual setup first, such as creating the database, so flyway wouldn't need those super-admin permissions.
My Fix
I had to ensure that the database user that flyway job used had ownership rights to the public schema, so that the flyway user could then assign the right to use the schema to other roles.
Additional setup Details
I am using AWS RDS (both regular and Aurora), and they don't allow super users in the databases. RDS reserves super users for use by AWS, only, so that consumers are unable to break the replication stuff that is built in. However, there's a catch-22 that you must be an owner in postgres to be able to modify it.
My solution was to create a role that acts as the owner ('owner role'), and then assign both my admin user and the flyway user to the owner role, and use ALTER scripts for each object to assign the object's owner to the owner role.
I missed the public schema, since that was auto-created when I created the database script manually. The public schema defaulted to my admin role rather than the shared owner role. So when the flyway user tried to assign public schema permissions to other roles, it didn't have the authority to do that. An error was not thrown during flyway execution, however.