Postgresql schema "public" does not exist - postgresql

When I was working on postgresql database, I delete some users using command
=>set role "test-admin" ;
SET
=> drop owned by "test-admin" cascade;
DROP OWNED.
=> drop user "test-temp";
DROP ROLE
but when I do
\dn
List of schemas
Name | Owner
------+-------
(0 rows)
The public schema does not exist anymore. I can still see a bunch of users when run \du, I can also see names of database when do \l.
The error I saw is: "Error: could not find schema 'public' while looking for owner".
Looks like public schema was either dropped or not accessible. I did not drop schema explicitly.
My questions are:
why does public schema disappear?
will drop owner of schema public also drop public schema?
how can I bring it back?
Should I manually recreate it?
Since I can still see databases, how can I associate the database with public schema again?
I tried all the approaches I can think of (such as login as users with different privileges), the public schema is still no available.
Thanks for the help in advance.

Related

Replacing schema name when sharing sql script with other users

When collaborating with colleagues I need to change the schema name every time I receive a SQL script (Postgres).
I am only an ordinary user of a corporate database (no permissions to change anything). Also, we are not allowed to create tables in PUBLIC schema. However, we can use (read-only) all the tables from BASE schema.
It is cumbersome for the team of users, where everybody is creating SQL scripts (mostly only for creating tables), which need to be shared amongst others. Every user has its own schema.
Is it possible to change the script below, where I will share the script to another user without the need for the other user to find/replace the schema, in this case, user1?
DROP TABLE IF EXISTS user1.table1;
CREATE TABLE user1.table1 AS
SELECT * FROM base.table1;
You can set the default schema at the start of the script (similar to what pg_dump generates):
set search_path = user1;
DROP TABLE IF EXISTS table1;
CREATE TABLE table1 AS
SELECT * FROM base.table1;
Because the search path was change to contain user1 as the first schema, tables will be searched in that schema when dropping and creating. And because the search path does not include any other schema, no other schema will be consulted.
If you
However the default search_path is "$user", public which means that any unqualified table will be searched or created in a schema with the same name as the current user.
Caution
Note that a DROP TABLE will drop the table in the first schema found in that case. So if table1 doesn't exist in the user's schema, but in the public schema, it would be dropped from the public schema. So for your use-case setting the path to exactly one schema might be more secure.

Altering view/access permissions for a schema in DB2

I am working around a workaround to a "feature" in IBM DB2.
This fancy database has a "feature" in it which if I try to use a CREATE TABLE statement and it doesn't find the schema, it will create this schema for me, even if I don't want it to. This bug has caused me a lot of hours in debugging, because my code right now exists with the expectation that it won't create the schema if it doesn't exist
My question is -- how do I change the permissions of a particular schema (or even during the create schema phase) which a particular user does not have access to view?
I checked out this doc..
It seems with GRANT, there are the following three permissions:
ALTERIN
Grants the privilege to alter or comment on all objects in the
schema. The owner of an explicitly created schema automatically
receives ALTERIN privilege.
CREATEIN
Grants the privilege to create
objects in the schema. Other authorities or privileges required to
create the object (such as CREATETAB) are still required. The owner of
an explicitly created schema automatically receives CREATEIN
privilege. An implicitly created schema has CREATEIN privilege
automatically granted to PUBLIC.
DROPIN
Grants the privilege to drop
all objects in the schema. The owner of an explicitly created schema
automatically receives DROPIN privilege
With only ALTERIN, CREATEIN, and DROPIN, I don't see anything relevant to view access permissions :/
EDIT:
I checked out our Dash DB database for this particular table which has these special permissions for particular users using the following SQL:
SELECT * FROM SYSIBMADM.PRIVILEGES WHERE OBJECTSCHEMA = 'FAKE_SCRATCH';
This is the result:
EDIT 2:
I tried the following to emulate Dash DB's permissions for that user for that schema:
GRANT ALTERIN, CREATEIN, DROPIN ON SCHEMA FAKE_SCRATCH TO USER TEST_USER;
Still doesn't work :/
The following SQL query executed in DB2 fixed the problem:
REVOKE IMPLICIT_SCHEMA ON DATABASE FROM PUBLIC

Change owner of Postgres table automatically?

I have a database shared by many users, all the users are in a group "example" and the vast majority of objects in the database are owned by "example". Very occasionally a user will create a new table - that table gets assigned to the user who created it and so the other users are unable to alter the new table.
Is there a way to have the ownership of a table automatically set to the group "example" and not the user who created the table or a way to set up a trigger that happens after a CREATE TABALE or a way to set up group/permissions such that all users will be considered owners of objects regardless of who actually created them?
You could change the default privileges this way:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO PUBLIC;
or to give write access:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO PUBLIC;
https://www.postgresql.org/docs/9.0/static/sql-alterdefaultprivileges.html
You probably want to use an EVENT TRIGGER
This is doable in all versions of Pg from 9.3 forward but depending on your version might require different approaches since the structures for event triggers have improved significantly.
In earlier versions you could look through the table catalogs for items owned by the current user. In newer versions you can use pg_event_trigger_ddl_commands to get the information you need. you want to run the command at ddl end.

Locking down Public Group Role in PostgreSQL

Based on information I've been reading about privileges, I've learned it was good to revoke privileges before assigning any privileges to roles.
I had 1 user I was working with called appuser and I did the following:
REVOKE ALL PRIVILEGES ON SCHEMA PUBLIC FROM GROUP PUBLIC;
GRANT SELECT
ON public.table1 TO appuser;
GRANT SELECT
ON public.table1_id_seq TO appuser;
GRANT SELECT
ON public.table2 TO appuser;
GRANT SELECT
ON public.table2_id_seq TO appuser;
I did this in the hopes of removing any privileges to attached to any newly added users automatically part of the public role membership. Instead I got an error to the effect of appuser does not have permissions to the schema. However this is my misunderstanding with this error.
1. PgAdminIII doesn't show a public role under Group Roles for this schema
2. appuser does not appear to be a member of a group called public (because it doesn't exist in the interface).
3. appuser's privileges were explicitly granted, even if it were part of the public role
So...is there some sort of implicit group role called "Public" that is affecting this user's privileges? I don't understand what's going on. I've also attempted to find out where to display the group role membership from the pgAdminIII command line with no luck there either. By the way to fix it, I simply reversed the first command (i.e. GRANT ALL PRIVILEGES ON SCHEMA PUBLIC TO GROUP PUBLIC); However that basically undoes what I was originally trying to do (i.e. simply lock down the tables).
Any ideas?
Update: I have a hunch, I discovered what the issue may be. I don't think appuser has permissions to the schema. If I'm not mistaken schema permissions must be granted before access to any objects beneath the schema can happen.
Ok, so the answer here is kind of complicated as to why things behave the way they do and it is probably worth discussing the PostgreSQL security model to some extent.
PUBLIC is not a role or a group but rather a reserved word. The way the permissions work is that access granted to current inherited roles or PUBLIC apply. I have actually been bitten by this in the past as I build frameworks that wrap PostgreSQL roles.
In general, my view is that you want to do as follows:
Don't allow everyone to log into the db.
REVOKE CONNECT ON DATABASE mydb FROM public;
You may want to revoke access to schemas and tables from public too.
What I think you have done is something else, which is to revoke permissions from the schema (but not the tables in the schema!) and therefore reserve PUBLIC access for default permissions to tables in that schema. This may or may not be what you want. At any rate as you found out you need to add back permissions to the schema to get back to where you are.
Now I am not entirely sure what you are trying to do here. If you want to fully lock down your db, you need to do the same for all tables as well. Otherwise if you:
CREATE USER foo;
GRANT USAGE ON SCHEMA PUBLIC TO foo;
Then foo will have access to all the permissions that PUBLIC has on the tables.

PostgreSQL: making a schema restricted/unchangable?

We like our production environment with a restricted/unchangable schema -- the development side can be owned by the developers and changed as they like -- and we like to vet changes as they are promoted.
I'm wondering if this may be a solution to making that happen:
postgres% create proddb with owner=postgres;
unixside% pg_restore --dbname=devdb [--schema-only] --no-owner proddb
/* grants to users on schema objects appear to remain intact */
/* here's the magic, I hope... */
postgres% revoke create on schema public from public;
postgres% grant usage on schema public to produser(s);
Some testing seems to show that a user in this new proddb can interact with tables normally (with appropriate grants) and cannot alter the schema (alter table, create table, drop table, etc). But I'm paranoid and very new to Postgres, so...
Q: Is this correct?
Q: Am I missing anything?
Thanks muchly.
Yes, that is correct. The only addition is that the owner of a table can always delete or modify it. So it may not work if you have existing tables in the schema.
Discovered a missing element: sequences.
The user was finding errors in his scripts; similar errors appeared in the logs:
ERROR: permission denied for sequence <sequence>
The production schema showed that although sequences were created, they were owned by postgres and no explicit grants were given to the users. As per the GRANT documentation:
Granting permission on a table does not automatically extend permissions to any sequences used by the table, including sequences tied to SERIAL columns. Permissions on sequence must be set separately.
Our fix (verbose for this demonstration) was to find all sequences:
unixside% pg_dump --schema-only proddb > proddb.schema
unixside% grep -i 'create sequence' proddb.schema
...and apply appropriate grants (select to prevent table scans, update to prevent the above errors):
postgres% grant select,update on <sequence> to produser(s);
So far, the user says it's working and errors to the log have stopped...
I forget what version PostgreSQL added the syntax, but one of the easiest ways to administer permissions in PostgreSQL is through the "GRANT foo, priv ON ALL something IN SCHEMA" syntax.
BEGIN;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA my_schema TO my_role;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA my_schema TO my_role;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA my_schema TO my_role;
COMMIT;
Very handy for making sure that permissions are always set correctly.
The EXECUTE for FUNCTIONS may seem spooky, but shouldn't be unless your functions were created with the SECURITY DEFINER attribute (and if you are using SECURITY DEFINER, you'd better be cautious since you're playing around with the PostgreSQL version of a "setuid" function). If you space out your TABLES across different SCHEMAS based on the expected permissions, then this becomes a pretty handy convention when used with the search_path variable.
ALTER ROLE my_role SET search_path = my_schema, auth_schema, public;
-- Avoid using the public schema (pretty please)
Where auth_schema has a collection of tables that my_role shouldn't have direct read or write privileges on. Assigning privs to GROUPS is also useful.
Here are some relevant docs:
http://developer.postgresql.org/pgdocs/postgres/sql-grant.html
Don't forget you can use "\h GRANT" in psql to easily figure out the syntax or remember what can be done on all objects in a schema (search for "IN SCHEMA").