Create foreign table on file_fdw as non-superuser - postgresql

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!

Related

Setting privileges on foreign table on Postgres

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.

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));

FlywayDB not creating extension

I have this startup script which is picked up by FlywayDB:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- clean up
DROP table IF EXISTS tenants;
-- create table
CREATE TABLE tenants (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(64) NOT NULL
);
and my spring boot config:
#FLYWAY
spring.flyway.url=jdbc:postgresql://localhost:5432/tenant?currentSchema=public
spring.flyway.user=postgres
spring.flyway.password=secret
spring.flyway.baseline-on-migrate=true
All my scripts are working fine except for "CREATE EXTENTION" bit.
I can log in the DB with the same credentials and run it manually with success. But via FlyWay: No Way. Wonder why
This should work just fine and is widely used. Make sure your user has the necessary permissions to do so.
Loading an extension requires the same privileges that would be
required to create its component objects. For most extensions this
means superuser or database owner privileges are needed. The user who
runs CREATE EXTENSION becomes the owner of the extension for purposes
of later privilege checks, as well as the owner of any objects created
by the extension's script.
read docs: CREATE EXTENSION

How to add a remote Postgresql db(linked server) to a Postgresql db?

I have a postgresql db at home and one on the cloud. I'd like to add my home db to the cloud db so I can query easily between databases. How can this be done? Without using dblink http://www.postgresonline.com/journal/archives/44-Using-DbLink-to-access-other-PostgreSQL-Databases-and-Servers.html
My home db will use a dynamic ip provider (can I add a dynamic ip address such as myhomedb.dedyn.io to postgresql settings?)
I'm stating all this in case there are any issues. My home db will only be used to update massive amount of data but isn't mission critical (as we know cloud computing isn't cheap).
Thanks in advance.
Looks like postgres-fdw is the way to go: https://www.postgresql.org/docs/current/postgres-fdw.html
First install the extension:
CREATE EXTENSION postgres_fdw;
Then create a foreign server using CREATE SERVER. In this example we
wish to connect to a PostgreSQL server on host 192.83.123.89
listening on port 5432. The database to which the connection is made
is named foreign_db on the remote server:
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '192.83.123.89', port '5432', dbname 'foreign_db');
A user mapping, defined with CREATE USER MAPPING, is needed as well
to identify the role that will be used on the remote server:
CREATE USER MAPPING FOR local_user
SERVER foreign_server
OPTIONS (user 'foreign_user', password 'password');
Now it is possible to create a foreign table with CREATE FOREIGN
TABLE. In this example we wish to access the table named
some_schema.some_table on the remote server. The local name for it
will be foreign_table:
CREATE FOREIGN TABLE foreign_table (
id integer NOT NULL,
data text
)
SERVER foreign_server
OPTIONS (schema_name 'some_schema', table_name 'some_table');
It's essential that the data types and other properties of the columns
declared in CREATE FOREIGN TABLE match the actual remote table.
Column names must match as well, unless you attach column_name options
to the individual columns to show how they are named in the remote
table. In many cases, use of IMPORT FOREIGN SCHEMA is preferable to
constructing foreign table definitions manually.

No privilege for this operation

Extracted code from documentation,
create table sales_catalog(
item_id varchar(10) not null primary key,
item_name_desc varchar(50) not null,
item_desc varchar(50));
Error after using SYSDBA as the user in Firebird SQL3.
Statement failed, SQLSTATE = 42000
unsuccessful metadata update
CREATE TABLE SALES_CATALOG failed
There is no privilege for this operation.
I did some experimenting, and the problem seems to be that if you connect to a database using ISQL without specifying a host name, it will use Firebird embedded to connect to the database (previous versions of Firebird didn't do that on Windows).
Firebird embedded does not require a username and password as it assumes that if you have direct read/write access to the database, that you are allowed to connect to it.
When you connect without specifying a username and password (eg using connect 'database.fdb' instead of connect 'database.fdb' user sysdba, Firebird embedded will use your OS username to connect.
This can be checked because ISQL reports the username when connecting:
SQL> connect 'd:\data\db\fb3\dbofnormal.fdb';
Database: 'd:\data\db\fb3\dbofnormal.fdb', User: MARK
Firebird 3 added new metadata privileges, for example creating a table in a database now requires that you are either the owner of the database (the username used in the create database statement), sysdba (or another admin user), or that you have the create table privilege. See also User Privileges for Metadata Changes. In earlier version any user would be allowed to create tables once they had access to the database.
Now on to the problem: the user (in my example MARK), does not have the create table privilege, so attempting to do so will fail:
SQL> create table testmark ( id integer generated by default as identity primary key);
Statement failed, SQLSTATE = 42000
unsuccessful metadata update
-CREATE TABLE TESTMARK failed
-There is no privilege for this operation
There are a few ways to solve this:
Specify a user with sufficient privileges in the connect statement (eg sysdba):
connect 'database.fdb' user sysdba;
Include the host name in the connect statement to connect through Firebird server instead of Firebird embedded, so that you are required to specify user name and password:
connect 'localhost:database.fdb' user sysdba password 'masterkey';
Connect once to your database as sysdba (see first item), and give the necessary privileges to the user (in my case mark):
grant create table to user mark;
From this moment forward this user can create tables (you may need to grant additional privileges, eg create view, create procedure, etc).