Postgres restore missing privileges - postgresql

I am running through some very basic tests to confirm a backup/restore process is working on a local environment.
the issue I am running into is that it doesn't look as though pg_dump/pg_restore/psql is restoring a database to the same state.
A sample of what I am doing below from start to finish.
CREATE DATABASE testdb WITH ENCODING='UTF8' CONNECTION LIMIT=-1;
CREATE TABLE a
(
a INT
);
INSERT INTO a(a)
SELECT 1 UNION ALL
SELECT 2;
SELECT * FROM a;
GRANT ALL PRIVILEGES ON DATABASE testdb TO testuser;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO testuser;
Then running the pg_dump
pg_dump -Fc -v --host=localhost --username=postgres --dbname=testdb -f C:\test\testdb.dump
creating a side by side restore for this example
CREATE DATABASE testdb_restore WITH ENCODING='UTF8' CONNECTION LIMIT=-1;
pg_restore -v --host=localhost --username=postgres --dbname=testdb_restore C:\test\testdb.dump
Now when I right click on testdb in pgadmin and click "Create Script" I get the following
-- Database: testdb
-- DROP DATABASE testdb;
CREATE DATABASE testdb
WITH
OWNER = postgres
ENCODING = 'UTF8'
LC_COLLATE = 'English_Australia.1252'
LC_CTYPE = 'English_Australia.1252'
TABLESPACE = pg_default
CONNECTION LIMIT = -1;
GRANT ALL ON DATABASE testdb TO postgres;
GRANT TEMPORARY, CONNECT ON DATABASE testdb TO PUBLIC;
GRANT ALL ON DATABASE testdb TO testuser;
When I click on the perform the same on testdb_restore, I get the following
-- Database: testdb_restore
-- DROP DATABASE testdb_restore;
CREATE DATABASE testdb_restore
WITH
OWNER = postgres
ENCODING = 'UTF8'
LC_COLLATE = 'English_Australia.1252'
LC_CTYPE = 'English_Australia.1252'
TABLESPACE = pg_default
CONNECTION LIMIT = -1;
As you can see I am missing the extra privileges from the original database.
I'm sure this is a very simple thing but I am currently lost on this one. I have also tried using methods and also pg_dump create database option added in and no difference.
Please note: I am extremely new to postgres and coming from a SQL Server background.

Roles and permissions are stored and managed per cluster, not per database, which is why pg_dump is not dumping them. You should use pg_dumpall if you are happy to have a dump of the whole cluster.
Alternatively, you can use pg_dumpall -r to dump roles only, and then pg_dump your database, and apply both scripts.

Unfortunately the privileges for a database are not included in a pg_dump. You'd have to use pg_dumpall for that, but that dumps all databases.
I know this is annoying. It is a bug of long standing that nobody has fixed yet.

Related

Revoke CONNECT permission to new DB by default

this is happening on newly created Postgres 13 instance on GCP's Cloud SQL.
I would like to disallow users to CONNECT to newly created databases. So I am modifying template database:
REVOKE ALL ON DATABASE template1 FROM public;
Then, I create new Database:
CREATE DATABASE mydb TEMPLATE template1;
Then I am checking CONNECT permissions for existing user:
SELECT datname
FROM pg_database
WHERE has_database_privilege('someuser', datname, 'CONNECT')
datname
---------------
cloudsqladmin
postgres
template0
mydb
So as you can see someuser has CONNECT permission to mydb.
Why is this happening? How can I prevent users to connect to newly created databases?
The permissions on a database are not copied from the template database during CREATE DATABASE. Rather, all new databases have the same default permissions: CONNECT and TEMP for PUBLIC, and all permissions for the owner.
There is no way to change that default, short of modifying the PostgreSQL code.

Accidentally restored a another database to the 'postgres' database how to correct

I accidentally restored another database as the default postgres database, how do I correct this?
postgres v10 on ubuntu.
To be specific. Log into a database other then postgres.
Then:
DROP DATABASE postgres;
CREATE DATABASE postgres; --You don't need to specify template1 it is the default.
Then do your restore. If you are using pg_restore make sure you use -C to have the database CREATEd properly.

Cannot drop database — conflicting evidence on number of users accessing the database

On PostgreSQL 9.6.6, running on Amazon RDS
SELECT * FROM pg_stat_activity WHERE datname = 'my_db'
yields nothing.
However, trying to drop the database
DROP DATABASE my_db;
fails with:
ERROR: database "my_db" is being accessed by other users DETAIL:
There are 3 other sessions using the database.
I've tried to lock down the number of conns to the db with these two three:
REVOKE CONNECT ON DATABASE my_db FROM public;
ALTER DATABASE my_db CONNECTION LIMIT 0;
ALTER DATABASE my_db WITH ALLOW_CONNECTIONS false;
I do have read replication set up (however — this shouldn't block as this is reading off the WAL?) and occasional snapshotting (not during the DROP stmt is being run though).
What are these three lingering conns and how do I get rid of them?

Can't access postgres extention created in docker entrypoint file, until I manually created it in psql

I'm trying to use the timescaledb extension, and so I'm running their official docker image.
In the last line of my docker entrypoint file, I run:
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
I verify that it's available for use with \dx in psql. As soon as I try to make use of the extension, I get:
No function matches the given name and argument types. You might need to add explicit type casts.
I find I have to add it manually by execing into psql and running CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
What's wrong with my entrypoint? Why do I have to manually create the extension after the container is built and running?
Edit: here's the full entrypoint script:
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE USER test_user PASSWORD 'password123';
ALTER USER test_user WITH SUPERUSER; --needed to create timescaledb extension
CREATE DATABASE testdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE testdb TO test_user;
CREATE DATABASE tsdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE tsdb TO test_user;
ALTER USER test_user CREATEDB;
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
EOSQL
Disclaimer: I don't know docker, but this seems only related to Postgres, not Docker itself
create extension will create the extension in database psql is currently connected to. Seeing the script, this is most probably the default database postgres that you connect to.
So the extension will be created in the postgres database, not in the testdb database.
You have two options on how to change that:
1. Use the template1 database
Anything created in the template1 database will automatically be created in every database created afterwards. So if you connect to the template database and run the create extension before creating the test database, the extension will automatically be available:
psql -v ON_ERROR_STOP=1 --dbname=template1 --username "$POSTGRES_USER" <<-EOSQL
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
CREATE USER test_user PASSWORD 'password123';
ALTER USER test_user WITH SUPERUSER; --needed to create timescaledb extension
CREATE DATABASE testdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE testdb TO test_user;
CREATE DATABASE tsdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE tsdb TO test_user;
ALTER USER test_user CREATEDB;
EOSQL
Note that the extension is created before anything else. The actual order isn't that important, the only thing that is important is that it's done before creating a new database.
2. Connect to the newly created database
Switch to the newly created database from within psql before you create the extension using the \connect command in psql
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE USER test_user PASSWORD 'password123';
ALTER USER test_user WITH SUPERUSER; --needed to create timescaledb extension
CREATE DATABASE testdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE testdb TO test_user;
CREATE DATABASE tsdb OWNER test_user;
GRANT ALL PRIVILEGES ON DATABASE tsdb TO test_user;
ALTER USER test_user CREATEDB;
\connect testdb
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
EOSQL
The main difference between the two methods is that with the first, the extension will be available automatically in all databases that are created in the future. Whereas with the second method it is only available in the testdb
Unrelated, but: the newly created user does not need the superuser privilege as the extension is created using the postgres user, not the newly created one.
To chime in with the prior answer, the TimescaleDB extension is applied per database, so if you run CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; without first connecting to your desired database with \c yourdatabase it will apply the extension to the default database. See http://docs.timescale.com/v0.9/getting-started/setup for the step-by-step instructions to apply after install.

How to solve privileges issues when restore PostgreSQL Database

I have dumped a clean, no owner backup for Postgres Database with the command
pg_dump sample_database -O -c -U
Later, when I restore the database with
psql -d sample_database -U app_name
However, I encountered several errors which prevents me from restoring the data:
ERROR: must be owner of extension plpgsql
ERROR: must be owner of schema public
ERROR: schema "public" already exists
ERROR: must be owner of schema public
CREATE EXTENSION
ERROR: must be owner of extension plpgsql
I digged into the plain-text SQL pg_dump generates and I found it contains SQL
CREATE SCHEMA public;
COMMENT ON SCHEMA public IS 'standard public schema';
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
I think the causes are that the user app_name doesn't have the privileges to alter the public schema and plpgsql.
How could I solve this issue?
To solve the issue you must assign the proper ownership permissions. Try the below which should resolve all permission related issues for specific users but as stated in the comments this should not be used in production:
root#server:/var/log/postgresql# sudo -u postgres psql
psql (8.4.4)
Type "help" for help.
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------------+-------------+-----------
<user-name> | Superuser | {}
: Create DB
postgres | Superuser | {}
: Create role
: Create DB
postgres=# alter role <user-name> superuser;
ALTER ROLE
postgres=#
So connect to the database under a Superuser account sudo -u postgres psql and execute a ALTER ROLE <user-name> Superuser; statement.
Keep in mind this is not the best solution on multi-site hosting server so take a look at assigning individual roles instead: https://www.postgresql.org/docs/current/static/sql-set-role.html and https://www.postgresql.org/docs/current/static/sql-alterrole.html.
AWS RDS users if you are getting this it is because you are not a superuser and according to aws documentation you cannot be one. I have found I have to ignore these errors.
For people using Google Cloud Platform, any error will stop the import process.
Personally I encountered two different errors depending on the pg_dump command I issued :
1- The input is a PostgreSQL custom-format dump. Use the pg_restore command-line client to restore this dump to a database.
Occurs when you've tried to dump your DB in a non plain text format. I.e when the command lacks the -Fp or --format=plain parameter. However, if you add it to your command, you may then encounter the following error :
2- SET SET SET SET SET SET CREATE EXTENSION ERROR: must be owner of extension plpgsql
This is a permission issue I have been unable to fix using the command provided in the GCP docs, the tips from this current thread, or following advice from Google Postgres team here. Which recommended to issue the following command :
pg_dump -Fp --no-acl --no-owner -U myusername myDBName > mydump.sql
The only thing that did the trick in my case was manually editing the dump file and commenting out all commands relating to plpgsql.
I hope this helps GCP-reliant souls.
Update :
It's easier to dump the file commenting out extensions, especially since some dumps can be huge :
pg_dump ... | grep -v -E '(CREATE\ EXTENSION|COMMENT\ ON)' > mydump.sql
Which can be narrowed down to plpgsql :
pg_dump ... | grep -v -E '(CREATE\ EXTENSION\ IF\ NOT\ EXISTS\ plpgsql|COMMENT\ ON\ EXTENSION\ plpgsql)' > mydump.sql
Try using the -L flag with pg_restore by specifying the file taken from pg_dump -Fc
-L list-file
--use-list=list-file
Restore only those archive elements that are listed in list-file, and restore them in the order they appear in the file. Note that if filtering switches such as -n or -t are used with -L, they will further restrict the items restored.
list-file is normally created by editing the output of a previous -l operation. Lines can be moved or removed, and can also be commented out by placing a semicolon (;) at the start of the line. See below for examples.
https://www.postgresql.org/docs/9.5/app-pgrestore.html
pg_dump -Fc -f pg.dump db_name
pg_restore -l pg.dump | grep -v 'COMMENT - EXTENSION' > pg_restore.list
pg_restore -L pg_restore.list pg.dump
Here you can see the Inverse is true by outputting only the comment:
pg_dump -Fc -f pg.dump db_name
pg_restore -l pg.dump | grep 'COMMENT - EXTENSION' > pg_restore_inverse.list
pg_restore -L pg_restore_inverse.list pg.dump
--
-- PostgreSQL database dump
--
-- Dumped from database version 9.4.15
-- Dumped by pg_dump version 9.5.14
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
--
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
--
-- PostgreSQL database dump complete
--
You can probably safely ignore the error messages in this case. Failing to add a comment to the public schema and installing plpgsql (which should already be installed) aren't going to cause any real problems.
However, if you want to do a complete re-install you'll need a user with appropriate permissions. That shouldn't be the user your application routinely runs as of course.
Shorter answer: ignore it.
This module is the part of Postgres that processes the SQL language. The error will often pop up as part of copying a remote database, such as with
a 'heroku pg:pull'. It does not overwrite your SQL processor and warns you about that.
For people using AWS, the COMMENT ON EXTENSION is possible only as superuser, and as we know by the docs, RDS instances are managed by Amazon. As such, to prevent you from breaking things like replication, your users - even the root user you set up when you create the instance - will not have full superuser privileges:
http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html
When you create a DB instance, the master user system account that you
create is assigned to the rds_superuser role. The rds_superuser role
is a pre-defined Amazon RDS role similar to the PostgreSQL superuser
role (customarily named postgres in local instances), but with some
restrictions. As with the PostgreSQL superuser role, the rds_superuser
role has the most privileges on your DB instance and you should not
assign this role to users unless they need the most access to the DB
instance.
In order to fix this error, just use -- to comment out the lines of SQL that contains COMMENT ON EXTENSION
EDIT 1: As suggested by Dmitrii I., you can also omit comments when dumping: pg_dump --no-comments
For people who have narrowed down the issue to the COMMENT ON statements (as per various answers below) and who have superuser access to the source database from which the dump file is created, the simplest solution might be to prevent the comments from being included to the dump file in the first place, by removing them from the source database being dumped...
COMMENT ON EXTENSION postgis IS NULL;
COMMENT ON EXTENSION plpgsql IS NULL;
COMMENT ON SCHEMA public IS NULL;
Future dumps then won't include the COMMENT ON statements.
Use the postgres (admin) user to dump the schema, recreate it and grant priviledges for use before you do your restore.
In one command:
sudo -u postgres psql -c "DROP SCHEMA public CASCADE;
create SCHEMA public;
grant usage on schema public to public;
grant create on schema public to public;" myDBName
For me, I was setting up a database with pgAdmin and it seems setting the owner during database creation was not enough. I had to navigate down to the 'public' schema and set the owner there as well (was originally 'postgres').
Some of the answers have already provided various approaches related to getting rid of the create extension and comment on extensions. For me, the following command line seemed to work and be the simplest approach to solve the problem:
cat /tmp/backup.sql.gz | gunzip - | \
grep -v -E '(CREATE\ EXTENSION|COMMENT\ ON)' | \
psql --set ON_ERROR_STOP=on -U db_user -h localhost my_db
Some notes
The first line is just uncompressing my backup and you may need to adjust accordingly.
The second line is using grep to get rid of offending lines.
the third line is my psql command; you may need to adjust as you normally would use psql for restore.