Setting privileges on foreign table on Postgres - postgresql

How do foreign table privileges work? A simple example where both source_db and destination_db are Postgres databases.
source_db:
-- create user for user mapping
CREATE USER fdw_user WITH PASSWORD 'secret';
-- create table
CREATE TABLE data (value TEXT);
-- set privileges
GRANT ALL ON TABLE data TO fdw_user;
destination_db:
-- create extension
CREATE EXTENSION postgres_fdw;
-- create server
CREATE SERVER remote_source
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'source.domain.com', dbname 'source_db');
-- create user mapping
CREATE USER MAPPING
FOR PUBLIC
SERVER remote_source
OPTIONS (user 'fdw_user', password 'secret');
-- create foreign table
CREATE FOREIGN TABLE data_from_source(value TEXT)
SERVER remote_source
OPTIONS (table_name 'data');
Now setting privileges for any user in destination_db seems to have no effect, like
GRANT SELECT ON TABLE data_from_source TO localuser;
How can I set privileges on foreign table?

The problem was PgAdmin III. ACL of foreign table changed but PgAdmin did not show it. Psql on command line \dp+ data_from_source shows the ACL as expected.

Related

Create foreign table on file_fdw as non-superuser

I have created a file_fdw extension and a corresponding server as superuser.
CREATE EXTENSION file_fdw;
CREATE SERVER myserver FOREIGN DATA WRAPPER file_fdw;
ALTER SERVER myserver OWNER TO nonsuperuser;
I want a non-superuser nonsuperuser to use this server to create a foreign table
CREATE FOREIGN TABLE test (
a text NULL,
b text NULL
)
SERVER myserver
OPTIONS (filename '/home/me/mycsvfile.csv', format 'csv', header 'true', delimiter ';');
Executing this, leads to `only superuser can change options of a file_fdw foreign table
What can I do to enable nonsuperuser to create foreign tables? If possible I would not mind declaring the options as super user.
Only highly privileged users are allowed to access files on the database server, that's why you need high permissions to create a file_fdw foreign table.
From the error message it becomes clear that you are using an old version of PostgreSQL; on more recent versions, the error message would look like:
only superuser or a member of the pg_read_server_files role may specify the filename option of a file_fdw foreign table
So, as an alternative to dealing out superuser privileges, you may add the user to the pg_read_server_files role.
Upgrade PostgreSQL!

Granting local user permissions to a foreign db table in postgres

I set up a connection to a foreign db using dblink_connect according to the docs:
CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (hostaddr '127.0.0.1', dbname 'foreign_test_db');
CREATE USER test_user WITH PASSWORD 'secret';
CREATE USER MAPPING FOR test_user SERVER fdtest OPTIONS (user 'test_user', password 'secret');
GRANT USAGE ON FOREIGN SERVER fdtest TO regress_dblink_user;
GRANT SELECT ON TABLE foo TO test_user;
\c - regress_dblink_user
SELECT dblink_connect('myconn', 'fdtest');
SELECT * FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
The final 'GRANT SELECT' appears to infer that if it is meant to grant select permissions to local user test_user to the table foo on the fdtest foreign data wrapper. However, how I would interpret this command is that it is granting permissions to test_user to select on local table foo (which does not exist). As expected, when I run this command I get an error:
ERROR: relation "foo" does not exist
I would love to know how to actually accomplish this. I would like to be able to restrict local users to only access certain tables from a foreign data wrapper.
You'll have to connect to the remote database and run the GRANT statement there.
Of course you could do that via dblink, but then you'd have to connect with a superuser or the owner of the table.
The connection they show is a loop back connection, it just connects back to the same server and (apparently) database you are already in. This is useful for testing purposes. So granting the permission on the local server is the same thing as granting it on the remote server, as they are the same server.
They do not show the creation of the table, you can find it in the regression test contrib/dblink/sql/dblink.sql (from which the example in the doc derives) as:
CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));

PostgreSql user did not find any relations

I am trying to setup database permissions in the following manner.
1. The postgres user will be the owner of postgres and only responsible to create database and roles
2. Create a schema for the database and the make the user app_root the schema and table owner
3. Create a user api_user that will only have DML access
Here are the commands that I have executed. I do not want the apiuser to have any more privileges than SELECT/INSERT/UPDATE/DELETE and ONLY on the schema disclosures. Both app_root user and api_user should not have any public schema access.
But when I login to the database as api_user, I get a Permission Denied. I am unable to figure out:
How to grant the minimum set per permissions to the api_user
How to ensure that these permissions hold true for any new tables created
in future
Here are the commands that I've used to setup the db, schema, table and users.
Switch to user postgres and connect to database
~$ sudo su postgres
~$ psql
Create new user and database
-- Create the schema owner
CREATE USER app_root WITH PASSWORD 'approot';
-- Create database
CREATE DATABASE apps;
-- Connect to the apps database
\connect apps;
-- Create new schema for the apps
CREATE SCHEMA apps AUTHORIZATION app_root;
-- Remove ability for all users to do everything in public schema
REVOKE ALL ON SCHEMA public FROM public;
-- Ensure users can list down objects in public schema
GRANT USAGE ON SCHEMA public TO public;
Disconnect the database and now connect as the app_root user that we created to perform table operations on the database and schema.
~$ psql -hlocalhost -Uapp_root -dapps -W
(enter your database user password to login)
-- Create a table for contacts in the apps schema
CREATE TABLE apps.contacts
(
id serial,
customer_code text,
contact_name text,
contact_email text,
contact_phone text
);
-- Insert some sample data into the table
INSERT INTO apps.contacts(customer_code, contact_name, contact_email, contact_phone) VALUES('apollo', 'John Doe', 'jdoe#apollo.com', '536-847-5857');
INSERT INTO apps.contacts(customer_code, contact_name, contact_email, contact_phone) VALUES('apollo', 'David Brown', 'dbrown#apollo.com', '254-457-8452');
INSERT INTO apps.contacts(customer_code, contact_name, contact_email, contact_phone) VALUES('ryndall', 'Mary Miller', 'mmiller#ryndall.com', '235-654-7845');
INSERT INTO apps.contacts(customer_code, contact_name, contact_email, contact_phone) VALUES('ryndall', 'Tommy Smith', 'tsmith#ryndall.com', '854-965-6514');
Connect to the database using postgres user and create a new DB user with only DML (SELECT/INSERT/UPDATE/DELETE) privileges.
CREATE USER api_user WITH PASSWORD 'apiuser';
\connect apps;
GRANT USAGE ON SCHEMA apps TO api_user;
You need to grant explicitely privileges on schema tables (usage on schema is not enough):
For example:
grant all privileges on all tables in schema apps to api_user;

Schema created in Docker by postgres user does not exist

I am building a Docker container for my PostgresSQL 9.4.5 database and I'd like to create the table structures when the container starts. In the script included in my /docker-entrypoint-initdb.d/ directory is this series of commands:
#!/usr/bin/env bash
export PGUSER=postgres
echo "***CREATING DATABASE, USERS, AND ROLES***"
psql <<-EOSQL
CREATE USER vpager WITH PASSWORD '<pass>';
CREATE DATABASE vpager;
GRANT ALL PRIVILEGES ON DATABASE vpager TO vpager;
REVOKE ALL ON DATABASE vpager FROM PUBLIC;
CREATE ROLE standarduser;
CREATE USER vpageruser WITH PASSWORD '<pass>';
\connect vpager
CREATE SCHEMA ticketing;
GRANT ALL PRIVILEGES ON SCHEMA ticketing TO vpager;
GRANT CONNECT ON DATABASE vpager TO standarduser;
GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA ticketing TO standarduser;
GRANT standarduser TO vpageruser;
EOSQL
echo "***CREATING TABLE STRUCTURES***"
psql -U vpager vpager < /docker-entrypoint-initdb.d/create-vpager-tables.sql
The SQL script:
CREATE TABLE ticketing.merchant
(
merchant_id SERIAL PRIMARY KEY,
now_serving INT
);
CREATE TABLE ticketing.ticket
(
ticket_id SERIAL,
merchant_id INT REFERENCES ticketing.merchant(merchant_id),
create_ts TIMESTAMP,
PRIMARY KEY (ticket_id, merchant_id)
);
As you can see, the idea is to create a non-privileged user for doing CRUD operations. The problem is that when the create-vpager-tables.sql command runs, it can't see the schema that postgres created:
ERROR: schema "ticketing" does not exist
STATEMENT: CREATE TABLE ticketing.merchant
(
merchant_id SERIAL PRIMARY KEY,
now_serving INT
);
ERROR: schema "ticketing" does not exist
ERROR: schema "ticketing" does not exist
Yet, if I add a CREATE SCHEMA statement to the top of create-vpager-tables.sql, it says it already exists:
ERROR: schema "ticketing" already exists
How do I resolve these errors? I tried setting my search path at the top of the SQL file, but the same thing happened; it's like a "Schrodinger" schema.
I figured it out. I put the create-vpager-tables.sql in the /docker-entrypoint-initdb.d directory, and apparently the image also tries to source SQL files there. Moving it to /tmp (and granting USAGE on the schema to standarduser) fixed the problem.

Can't access data from pg_index using Foreign Data Wrapper in postgreSQL 9.3

I implement Foreign data wrapper in postgreSQL 9.3 in another postgreSQL DATABASE as below:
CREATE SERVER app_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (dbname 'postgres', host 'localhost');
CREATE USER MAPPING for postgres
SERVER app_db
OPTIONS (user 'postgres', password 'XXXX');
CREATE FOREIGN TABLE location_local
(
id integer,
name character varying
)
SERVER app_db OPTIONS (table_name 'location')
SELECT * FROM location_local;
This all works fine as location table is in public schema. but I also want to access data from pg_catalog. When I follow the same procedure to access the data than it gives me error.
ERROR: relation "public.pg_catalog.pg_index" does not exist
is there any way to access data from catalog using FDW or any other way?
You could try the schema_name option in the foreign table definition:
CREATE FOREIGN TABLE foreign_index (
-- ...
)
SERVER app_db
OPTIONS (
schema_name 'pg_catalog',
table_name 'pg_index'
);
But that might won't work, because pg_catalog is not really a schema, but a system-catalog. If that is the case, you can still use the dblink module to run queries at a foreign database.