Non-SuperUser Database Management - postgresql

I am using the PostgreSql manual and other guides to setup my database environment.
So far things are looking good, but I am wondering if I have a problem.
I am trying to apply this:
Tip It is good practice to create a role that has the CREATEDB and CREATEROLE privileges, but is not a superuser, and then use this role for all routine management of databases and roles. This approach avoids the dangers of operating as a superuser for tasks that do not really require it.
I have already created a user for this role.
createuser --interactive --pwprompt
Enter name of role to add: Manager
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) y
Shall the new role be allowed to create more new roles? (y/n) y
...and connected to an already existing database as the new user (Manager) Or so I thought.
psql -d test
Password for user postgres:
psql (11.2)
WARNING: Console code page (437) differs from Windows code page (1252)
8-bit characters might not work correctly. See psql reference
page "Notes for Windows users" for details.
Type "help" for help.
test=# \c test Manager
Password for user Manager
WARNING: Console code page (437) differs from Windows code page (1252)
8-bit characters might not work correctly. See psql reference
page "Notes for Windows users" for details.
You are now connected to database "test" as user "Manager".
test=>
I created a table for the database "test", but on checking it,the Owner isn't Manager, but postgres.
test=> \dt
List of relations
Schema | Name | Type | Owner
--------+---------------+-------+----------
public | Data-projects | table | postgres
(1 row)
test=> \dn
List of schemas
Name | Owner
--------+----------
public | postgres
(1 row)
I am not sure if this is good. I expected the owner to be Manager.
This is my first time using these tools. Can someone guide me in the right direction, please?
I want Manager to manage all the databases.
Wouldn't that make him owner?
Thanks

Database test is not owned by Manager because it was created by user postgres. The user who created an object will be its owner.
However, a superuser can transfer ownership:
ALTER DATABASE test OWNED BY "Manager";
I'll give you some additional tips:
Only use lower case letters, numbers and _ in the names of objects and users, because otherwise you always have to user double quotes for them in SQL, like I did above. That leads to needless suffering.
Run the following to make the database more secure:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
Create a new schema that will hold the objects for your application:
CREATE SCHEMA myapp;
Set the search_path appropriately:
ALTER DATABASE test SET search_path = myapp, public;

Related

Not sure if I have PostgreSQL installed on my Mac properly for creating Flask web app

I installed PosgreSQL 10.5 on a Mac running macOS 10.13.6 using Homebrew by following this tutorial. After installation, I ran =# \du to view all users. I saw the user with my Mac's name that the tutorial says PostgreSQL creates during installation, but the "postgres" default user was not created (or at least did not appear).
My Main Issue is...
I need to login to PostgreSQL 'at the root', and I either do not understand exactly what that means, or something is wrong. In following the very first steps from the PostgreSQL wiki's First Steps documentation, it says to...
First connect/login as root:
# su - postgres
$ psql
psql (9.6.0)
Type "help" for help.
But when I open a terminal window and type in su - postgres it asks for a password. I've typed in every password I could possibly have given that role, and it just says su: Sorry.
I did some research and tried to change the password by doing this:
postgres=# \password postgres.
That prompted me to enter a password twice, and it seemed to work. But, when I go back and run: su - postgres, it just gives me the same su: sorry.
So I tried typing in: psql postgres. This at least changed the $ to postgres=#, which tells me that I am at the PostgreSQL command line, and then the same: su: postgres, but that just changed the (=) sign to a (-), so now it changed to: postgres-#
I thought that maybe this meant that I was "logged into PostgreSQL at the root, but then I ran the following:
postgres=# su - postgres
postgres-# CREATE SCHEMA test
postgres-# CREATE USER tester PASSWORD 'P#ssword1'
postgres-# GRANT ALL ON SCHEMA test TO tester
postgres-# \q
...and none of that worked. It did not create a user or a schema.
History...
I've installed/uninstalled PostgreSQL on this Mac several times
in the past for testing
I've also installed/uninstalled pdAdmin for various reasons
It is highly possible that I did something in all of that shuffle that brought about this issue with the 'postgres' role not being created during this Homebrew instal. So, I did read through the rest of that tutorial and I did type in $ createuser postgres and that did seem to create the 'postgres' role. I tried to use ALTER ROLE to give that role Create DB but I never could get it to work using the command line, so I just opened pgAdmin, saw the role, granted it Create DB, and then back in command line ran =# \du again, and Create DB did appear next to the 'postgres' role I'd created. I added everything in pgAdmin, and now it looks like this.
List of roles
Role name | Attributes | Member of
----------------+------------------------------------------------------------+-----------
MyMacsNameHere | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
postgres | Superuser, Create role, Create DB, Replication | {}
My end goal...
I am trying to follow along with this YouTube tutorial about creating a Flask web application from scratch. In the YouTube tutorial, he uses MySQL, but I want to use PostgreSQL. Needless to say, I am up against a learning curve.

Is "postgres" a default and special user of PostgreSQL?

Chapter 21. Database Roles lists the default roles of PostgreSQL. But I don't find user postgres there,
which has been created by default in PostgreSQL. Is postgres a
default role? Does the manual miss it or do I misunderstand?
In PostgreSQL, is postgres a special user, or a regular user just
like one created manually? Does the PostgreSQL server need the user postgres? Will removing it cause some trouble to the server or something else?
The following two commands run in psql provide default roles or
usernames, which both include postgres. Why do they differ?
# select usename from pg_catalog.pg_user;
usename
----------
postgres
(1 row)
# select rolname from pg_catalog.pg_roles;
rolname
----------------------
postgres
pg_monitor
pg_read_all_settings
pg_read_all_stats
pg_stat_scan_tables
pg_signal_backend
(6 rows)
postgres is not a default role.
When you create the PostgreSQL database cluster with initdb, you can specify the name of the installation superuser with the -U option. If you omit that option, the name of the superuser will be the same as the name of the operating system user you are using.
Since it is customary to have initdb PostgreSQL run by an operating system user postgres, the superuser is usually called postgres too, but that isn't in any way required.
postgres is just a normal superuser like any other.
You will have trouble dropping it because it owns all the system objects, and you cannot easily modify those objects. You are advised not to try.
pg_read_all_settings and the others don't show up in pg_user because they are not login roles.
postgres is the first user that is available after an installation. it is a super user. But, it is possible to define your own super users which will have equivalent permissions to the postgres user.
A user is a role that has the ability to log in.
Roles without login privilege are used for various system level uses and are sometimes also used to manage access control rules through inheritance (e.g. you may have a role analysts and a user hal that is granted membership to the analysts role)
Thus pg_user only returns those roles that are able to log into the database.

How can I change the owner of the public schema in databases created via the Google Console?

In Google's SQL Cloud Postgres service, when I create a database via the Web Console for a PostgreSQL instance, it automatically sets the owner of the database's default "public" schema to be cloudsqladmin. It seems I cannot change the ownership:
mydb=> \dn
List of schemas
Name | Owner
--------+---------------
public | cloudsqladmin
(1 row)
mydb=> alter schema public owner to postgres;
ERROR: must be owner of schema public
mydb=> \du
List of roles
Role name | Attributes | Member of
-------------------+------------------------------------------------+---------------------
cloudsqladmin | Superuser, Create role, Create DB, Replication | {}
cloudsqlagent | Create role, Create DB | {cloudsqlsuperuser}
cloudsqlreplica | Replication | {}
cloudsqlsuperuser | Create role, Create DB | {}
pg_signal_backend | Cannot login | {}
postgres | Create role, Create DB | {cloudsqlsuperuser}
mynewuser | Create role, Create DB | {cloudsqlsuperuser}
I also created a "mynewuser" through the web console, and cannot remove the "mynewuser" from the "cloudsqlsuperuser" group:
mydb=> alter group cloudsqlsuperuser drop user mynewuser;
ERROR: "cloudsqlsuperuser" can't be altered
If I wanted to create a database with a public schema that only a new user has access to (and owns), should I be doing this outside of the Google web ui? It seems like any databases I create are owned by cloudsqladmin, and any users I create are those "cloudsqlsuperuser" members. If I wanted to restrict permissions for a user, should I create that user normally via psql and bypass the web ui altogether?
From my experience, you seem to have to bypass the web ui / cli tool entirely.
When you create a database through the cli tool:
gcloud sql databases create DBNAME --instance INSTANCE
It assigns ownership to cloudsqlsuperuser, same as through the gui from the sounds of it.
When I have created a user specifically through the CLI tool:
gcloud sql users create USER 'host' --instance INSTANCE
Those users get the same permissions as cloudsqlsuperuser. In this case, it is possible to alter the ownership of the database. I had success through psql command connecting as the user I wanted to own the database and running:
ALTER DATABASE database OWNER TO user;
However if the user was created via psql (not glcoud cli), then the permission are not the same and the above failed.
I'd be tempted to create your instance, set the 'postgres' users password through the tool, then psql into the instance from there and do everything you need via sql commands. I think the tool does some things very nicely (as does the UI), but its a pain later on.
If anyone knows better, I'd love to hear how you can work with the default gcloud user.
Basically what happens here is that a usual CREATE DATABASE statement seems to create a new database based on the template0 database. This database is owned by cloudsqladmin. A role only Google has access to. When the gcloud or web GUI is used, it executes the following query:
CREATE DATABASE mydb TEMPLATE template1;
For template1 the owner is set to cloudsqlsuperuser a role that gets assigned to the postgres user, and other users created through the GUI.
So if you would like to create a database using sql with the appropriate privileges, just execute the statement above, and your public schema will then be owned by the cloudsqlsuperuser, and can be altered using the default postgres user, or other users created through the web GUI.
Connect to the database mydb by owner user (for exaple, it is mynewuser).
If you want to change the public schema owner, first you should make the user postgres owner of your database mydb:
mydb=> ALTER DATABASE mydb OWNER TO postgres;
After that, you can change the public schema owner:
mydb=> ALTER SCHEMA public OWNER TO postgres;
Besides, to remove your mynewuser from the cloudsqlsuperuser group (role) use:
mydb=> REVOKE cloudsqlsuperuser FROM mynewuser;
Note: The default postgres user in Google Cloud Platform's (GCP) Cloud SQL (PostgreSQL) is not a superuser of the instance. Also, all users created from the GCP web UI have cloudsqlsuperuser role by default, and the following attributes (privileges): CREATEROLE, CREATEDB and LOGIN. They don't have the SUPERUSER or REPLICATION attributes.

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.

PostgreSQL 8.3 privileges not updated - wrong usage?

I'm having trouble granting privileges to another user in PostgreSQL 8.3. While the GRANT command gives me no error, the privileges do not show up. Do I need to "flush" them?
sirprize=# CREATE DATABASE testdb;
CREATE DATABASE
sirprize=# GRANT ALL PRIVILEGES ON DATABASE testdb TO testuser;
GRANT
sirprize=# \c testdb
You are now connected to database "testdb".
testdb=# \z
Access privileges for database "testdb"
Schema | Name | Type | Access privileges
--------+------+------+-------------------
(0 rows)
testdb=#
\z Shows your table, view, and sequence permissions, for the objects contained within the Database. It does not show permissions on the database itself. If you create a table or some other object within 'testdb', it will then show up in \z's output.
You can see which Databases exist on your system with \l (or \l+ for a bit more info).
See section 9.22. of the PostgreSQL 8.3 manual for information about how to programatically determine which permissions exist for a user on a given database.