From f499c6f58c86035eea590c170c4f3747eae002ba Mon Sep 17 00:00:00 2001 From: barnold Date: Mon, 10 Oct 2022 09:06:38 +0100 Subject: [PATCH] Make safer use of postgres roles... by separating ownership of the catalog database from its routine use. --- INSTALL | 58 +++++++++++++++++++++++++++++++++++-------- Makefile.orig | 26 +++++++++++++------ README | 19 ++++---------- bin/load-gutenberg.pl | 2 +- create-tables.sql | 2 ++ t/00-author.t | 3 ++- t/01-books.t | 3 ++- t/02-failures.t | 3 ++- 8 files changed, 80 insertions(+), 36 deletions(-) diff --git a/INSTALL b/INSTALL index 5a92a02..0b07534 100644 --- a/INSTALL +++ b/INSTALL @@ -1,24 +1,63 @@ +0. Preliminary configuration for postgresql -0. Ensure you can connect to your default postgresql database. - I.e. that if you run +These are one-time things to do, in that you can recreate and reload +the catalog database any number of times without having to do these +steps again. - psql +Create a user to own the tables and a role to use the tables. (The +connection limits are merely suggestions.) - it connects and lets you run SQL. To create the tables, run + # su - postgres + $ createuser --connection-limit=1 --createdb --echo pgc_owner + $ createuser --connection-limit=5 --no-login pgc_user - make -f Makefile.orig create-tables +Configure postgres to allow connection to the catalog database by your +postgres username, e.g. "irulan". This is for the case that the +postgres server runs on the same host. Consult postgres's excellent +documentation for other cases. - To load (most of) the Gutenberg catalog, run +In pg_ident.conf, add two map lines so that the end of the file resembles this: - make -f Makefile.orig load-gutenberg + # MAPNAME SYSTEM-USERNAME PG-USERNAME + irulanmap irulan irulan + irulanmap irulan pgc_owner -1. To install the perl modules, run (for example) +In pg_hba.conf, modify the second "local" line, the one following the +"postgres" line, so that it has a map option on the end. + + local all all peer map=irulanmap + +Tell postgres about these edits. + + # systemctl reload postgres + +At this point "irulan" has privilege to create and drop the catalog +database. Routine use of the database is more safely done by a +username with lesser privilege, i.e. only the "pgc_user" role. E.g. + + $ psql + postgres=# grant pgc_user to fenring; + postgres=# \q + +1. As the operating system user "irulan", you should now be able to +use any of the targets in Makefile.orig to create and load the catalog +database. + + $ make -f Makefile.orig PGC_DANGEROUS=1 rebuild-db + $ make -f Makefile.orig load-catalog + +At this point, "irulan" should be able to run the tests successfully +with e.g. + + $ prove -l + +2. To install the perl modules, run (for example) perl Makefile.PL INSTALL_BASE=~/.local make test make install -2. To use these modules from your program, assuming the INSTALL_BASE +3. To use these modules from your program, assuming the INSTALL_BASE suggested above, declare -x PERL5LIB="$HOME/.local/lib/perl5" @@ -27,4 +66,3 @@ ). - diff --git a/Makefile.orig b/Makefile.orig index 3cc5fef..76ad4ce 100644 --- a/Makefile.orig +++ b/Makefile.orig @@ -1,13 +1,23 @@ -.PHONY: drop-tables create-tables delete-rows load-gutenberg +.PHONY: dangerous drop-db rebuild-db -drop-tables: - psql --command="DROP TABLE IF EXISTS book, author;" +dangerous: +ifndef PGC_DANGEROUS + $(error Refusing to continue without PGC_DANGEROUS set.) +endif -create-tables: drop-tables - psql --file="create-tables.sql" +drop-db: dangerous + dropdb --if-exists --username="pgc_owner" pg_book_catalog -delete-rows: - psql --command="TRUNCATE TABLE book, author;" +rebuild-db: drop-db + createdb --username="pgc_owner" pg_book_catalog \ + "Tables for an import of the book catalog from Project Gutenberg." + psql --dbname="pg_book_catalog" --username="pgc_owner" \ + --command="\set ON_ERROR_STOP" \ + --command="BEGIN TRANSACTION;" \ + --file="create-tables.sql" \ + --command="COMMIT;" -load-gutenberg: delete-rows +load-catalog: + psql --username="pgc_owner" pg_book_catalog \ + --command="TRUNCATE TABLE book, author;" bin/load-gutenberg.pl pg_catalog.csv diff --git a/README b/README index 38b87f9..9adfdf2 100644 --- a/README +++ b/README @@ -1,18 +1,8 @@ ABOUT -This is a small project using DBIx::Class and Test2::Suite to provide -some of the gutenberg.org catalog in a relational database (PostgreSQL). - -A script creates the tables with SQL, I didn't attempt to use DBIx for -that as yet. The SQL and the make-schema script are for postgres -since that was expedient for me. It also assumes the simplest case -where you have a default database that postgres will connect you to if -you don't name one. - -The script bin/load-gutenberg.pl loads from the catalog file available -from gutenberg.org, providing thousands of authors and book titles. -Run it from the command line or via 'make -f Makefile.orig' load-gutenberg'. - +This is a small project to provide some of the gutenberg.org catalog +in a relational database (PostgreSQL). It has no affiliation with +Project Gutenberg. COPYING @@ -22,5 +12,6 @@ Gutenberg project release their catalogs into the public domain. Otherwise, you may redistribute under the same terms as perl itself or under the GPL V3 or a later version, at your option. -barnold +Comments are welcome at . + diff --git a/bin/load-gutenberg.pl b/bin/load-gutenberg.pl index 567874b..75f24e8 100755 --- a/bin/load-gutenberg.pl +++ b/bin/load-gutenberg.pl @@ -61,7 +61,7 @@ printf("Count authors: %d\n", $count_auth); # Connect to postgres. my $dbh_pg = DBI->connect( - "dbi:Pg:", undef, undef, + "dbi:Pg:dbname=pg_book_catalog", "pgc_owner", undef, { AutoCommit => 0, RaiseError => 1, PrintError => 1 }, ) or die $DBI::errstr; diff --git a/create-tables.sql b/create-tables.sql index 5f19fbc..d531301 100644 --- a/create-tables.sql +++ b/create-tables.sql @@ -21,3 +21,5 @@ row in the author table.'; CREATE INDEX book_authid ON book (author_id); CREATE INDEX book_title ON book (title); + +GRANT SELECT ON author, book TO pgc_user; diff --git a/t/00-author.t b/t/00-author.t index 6a8e7cf..3fdd595 100755 --- a/t/00-author.t +++ b/t/00-author.t @@ -10,9 +10,10 @@ use lib "$FindBin::Bin/../lib"; # DBIx::Class is used implicitly via a 'Schema': use Book::Schema; use Test2::V0; +use Test2::Plugin::BailOnFail; # Connect. -my $schema = Book::Schema->connect('dbi:Pg:'); +my $schema = Book::Schema->connect('dbi:Pg:dbname=pg_book_catalog', 'pgc_owner'); isa_ok($schema, ["Book::Schema"], "Acquired our Book::Schema object."); # Acquire ResultSet for Author. diff --git a/t/01-books.t b/t/01-books.t index 4876c4a..99817ab 100755 --- a/t/01-books.t +++ b/t/01-books.t @@ -7,9 +7,10 @@ use lib "$FindBin::Bin/../lib"; # DBIx::Class is used implicitly via a 'Schema': use Book::Schema; use Test2::V0; +use Test2::Plugin::BailOnFail; # Connect. -my $schema = Book::Schema->connect('dbi:Pg:'); +my $schema = Book::Schema->connect('dbi:Pg:dbname=pg_book_catalog', 'pgc_owner'); isa_ok( $schema, ["Book::Schema"], "Acquired our Book::Schema object." diff --git a/t/02-failures.t b/t/02-failures.t index 95cc83c..72a3216 100755 --- a/t/02-failures.t +++ b/t/02-failures.t @@ -6,9 +6,10 @@ use FindBin; use lib "$FindBin::Bin/../lib"; use Book::Schema; use Test2::V0; +use Test2::Plugin::BailOnFail; # Connect and acquire an author. -my $schema = Book::Schema->connect('dbi:Pg:'); +my $schema = Book::Schema->connect('dbi:Pg:dbname=pg_book_catalog', 'pgc_owner'); my $rset_author = $schema->resultset('Author'); my $charles = $rset_author->find({ name => "Charles Dickens" });