Skip to content

Commit

Permalink
Fix "generate" command to have username to be granted.
Browse files Browse the repository at this point in the history
Fix to improve error checking.
  • Loading branch information
snaga committed Aug 4, 2015
1 parent e10d5c6 commit 0fda93b
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 50 deletions.
24 changes: 17 additions & 7 deletions bin/pt-privilege-autogen
Expand Up @@ -66,6 +66,10 @@ class GrantRevokeAutogen:
rs = self.psql.execute_query(query)
log.debug(rs)

if len(rs) == 0:
log.error("Could not drop the access statistics table.")
return False

if rs[0][0] == 'DROP TABLE':
log.info("Collecting access statistics stopped.")
return True
Expand All @@ -79,7 +83,7 @@ class GrantRevokeAutogen:

self.output = self.output + s + "\n"

def revoke_and_grant(self):
def revoke_and_grant(self, username):
if self.is_table_existing("public", "temp_pg_stat_user_tables") is False:
log.error("Collecting access statistics has not started. Start before generating.")
return False
Expand All @@ -90,7 +94,7 @@ class GrantRevokeAutogen:
# revoke on database
self.add_output("REVOKE ALL ON DATABASE \"%s\" FROM \"%s\";" % (self.psql.dbname, 'public'))
# grant on database
self.add_output("GRANT CONNECT,TEMP ON DATABASE \"%s\" TO \"%s\";" % (self.psql.dbname, self.psql.username));
self.add_output("GRANT CONNECT,TEMP ON DATABASE \"%s\" TO \"%s\";" % (self.psql.dbname, username));
self.add_output("")

# revoke on schema
Expand All @@ -102,7 +106,7 @@ class GrantRevokeAutogen:

for r in rs[1:len(rs)-1]:
self.add_output("REVOKE ALL ON SCHEMA \"%s\" FROM \"%s\";" % (r[0], 'public'))
self.add_output("GRANT USAGE ON SCHEMA \"%s\" TO \"%s\";" % (r[0], self.psql.username));
self.add_output("GRANT USAGE ON SCHEMA \"%s\" TO \"%s\";" % (r[0], username));

self.add_output("")

Expand All @@ -113,7 +117,7 @@ class GrantRevokeAutogen:
rs = self.psql.execute_query(self.query)

for r in rs[1:len(rs)-1]:
self.add_output("REVOKE ALL ON TABLE \"%s\".\"%s\" FROM \"%s\";" % (r[0], r[1], self.psql.username))
self.add_output("REVOKE ALL ON TABLE \"%s\".\"%s\" FROM \"%s\";" % (r[0], r[1], username))

# grant on table
self.query = '''
Expand Down Expand Up @@ -161,7 +165,7 @@ SELECT CASE WHEN coalesce(seq_tup_read,0)+coalesce(idx_tup_fetch,0) > 0 THEN 'SE
for r in rs[1:len(rs)-1]:
priv = re.sub(",$", "", r[0])
if len(priv) > 0:
self.add_output("GRANT %s ON TABLE \"%s\".\"%s\" TO \"%s\";" % (priv, r[1], r[2], self.psql.username))
self.add_output("GRANT %s ON TABLE \"%s\".\"%s\" TO \"%s\";" % (priv, r[1], r[2], username))

self.add_output("")

Expand All @@ -171,7 +175,8 @@ SELECT CASE WHEN coalesce(seq_tup_read,0)+coalesce(idx_tup_fetch,0) > 0 THEN 'SE

def usage():
print ""
print "Usage: " + os.path.basename(sys.argv[0]) + " [option...] [ start | generate | stop ]"
print "Usage: " + os.path.basename(sys.argv[0]) + " [option...] [ start | stop ]"
print " " + os.path.basename(sys.argv[0]) + " [option...] generate <USERNAME>"
print ""
print "Options:"
print " -h, --host=HOSTNAME Host name of the postgres server"
Expand Down Expand Up @@ -229,7 +234,12 @@ if __name__ == "__main__":
if t.start() is False:
sys.exit(1)
elif args[0] == "generate":
if t.revoke_and_grant() is False:
if len(args) < 2:
log.error("User name to be granted not specified.")
usage()
sys.exit(1)

if t.revoke_and_grant(args[1]) is False:
sys.exit(1)
elif args[0] == "stop":
if t.stop() is False:
Expand Down
90 changes: 88 additions & 2 deletions bin/t/test-pt-privilege-autogen.sh
Expand Up @@ -16,6 +16,14 @@ function setUp()

pgbench -i -n >> setUp.log 2>&1
pgbench -t 1 -c 1 -n >> setUp.log 2>&1

if [ $_MAJORVERSION == "9.0" ]; then
CREATEUSER_OPTS="--no-superuser --no-createdb --login --no-createrole"
elif [ $_MAJORVERSION == "9.1" ]; then
CREATEUSER_OPTS="--no-superuser --no-createdb --login --no-createrole"
else
CREATEUSER_OPTS="--no-superuser --no-createdb --login --no-createrole --no-replication"
fi
}

function testPrivilegeAutogen001()
Expand All @@ -26,7 +34,8 @@ function testPrivilegeAutogen001()

cat<<EOF > ${_SHUNIT_TEST_}.expected
Usage: pt-privilege-autogen [option...] [ start | generate | stop ]
Usage: pt-privilege-autogen [option...] [ start | stop ]
pt-privilege-autogen [option...] generate <USERNAME>
Options:
-h, --host=HOSTNAME Host name of the postgres server
Expand Down Expand Up @@ -136,7 +145,7 @@ EOF
# wait for updating table access statistics.
sleep 1

pt-privilege-autogen generate > ${_SHUNIT_TEST_}.grant.out
pt-privilege-autogen generate $USER > ${_SHUNIT_TEST_}.grant.out
assertEquals 0 $?

diff -rc ${_SHUNIT_TEST_}.grant.expected ${_SHUNIT_TEST_}.grant.out
Expand All @@ -146,4 +155,81 @@ EOF
assertEquals 0 $?
}

function testPrivilegeAutogen007()
{
OUT=${_SHUNIT_TEST_}.out

createuser $CREATEUSER_OPTS "user01"
createuser $CREATEUSER_OPTS "user02"

pt-privilege-autogen -U "user01" start > $OUT 2>&1
assertEquals 0 $?

pgbench -U $USER -c 1 -t 1 >> $OUT 2>&1
# wait for updating table access statistics.
sleep 1

pt-privilege-autogen -U "user01" generate "user01" > ${_SHUNIT_TEST_}.grant.out
assertEquals 0 $?

# stoppping with different user.
pt-privilege-autogen -U "user02" stop >> $OUT 2>&1
assertEquals 1 $?

contains 'ERROR: Could not drop the access statistics table.' $OUT
assertTrue $?

pt-privilege-autogen -U "user01" stop >> $OUT 2>&1
assertEquals 0 $?

dropuser "user01"
dropuser "user02"
}

function testPrivilegeAutogen008()
{
OUT=${_SHUNIT_TEST_}.out

createuser $CREATEUSER_OPTS "user01"
createuser $CREATEUSER_OPTS "user02"

pt-privilege-autogen -U "user01" start >> $OUT 2>&1
assertEquals 0 $?

pgbench -U $USER -c 1 -t 1 >> $OUT 2>&1
# wait for updating table access statistics.
sleep 1

pt-privilege-autogen -U "user02" generate "user02" > ${_SHUNIT_TEST_}.grant.out 2>&1
assertEquals 1 $?

contains 'ERROR: Could not get access statistics of the tables.' ${_SHUNIT_TEST_}.grant.out
assertTrue $?

# stoppping with different user.
pt-privilege-autogen -U "user01" stop >> $OUT 2>&1
assertEquals 0 $?

dropuser "user01"
dropuser "user02"
}

function testPrivilegeAutogen009()
{
OUT=${_SHUNIT_TEST_}.out

pt-privilege-autogen start > $OUT 2>&1
assertEquals 0 $?

pt-privilege-autogen generate >> $OUT 2>&1
assertEquals 1 $?

contains 'ERROR: User name to be granted not specified.' $OUT
assertTrue $?

# stoppping with different user.
pt-privilege-autogen stop >> $OUT 2>&1
assertEquals 0 $?
}

. shunit2
40 changes: 21 additions & 19 deletions docs/en/pt-privilege-autogen.rst
Expand Up @@ -12,15 +12,16 @@ Usage

.. code-block:: none
pt-privilege-autogen [option...] [ start | generate | stop ]
pt-privilege-autogen [option...] [ start | stop ]
pt-privilege-autogen [option...] generate <USERNAME>
Commands
--------

.. csv-table::

``start``, Starts collecting table access statistics of the database.
``generate``, Generates REVOKE/GRANT statements from collected access statistics of the tables.
``generate``, Generates REVOKE/GRANT statements from collected access statistics of the tables. Requires user name to be granted.
``stop``, Stops collecting table access statistics of the database.

Options
Expand Down Expand Up @@ -50,33 +51,35 @@ This command shows GRANT/REVOKE statements that can be applied to the PostgreSQL
Examples
--------

This example shows how to generate REVOKE/GRANT statements which allows to run pgbench transactions with minimum privileges.
This example shows how to generate REVOKE/GRANT statements for the user ``snaga`` to be allowed to run pgbench transactions with minimum privileges.

Following procedure needs to be done by the user who already has the several permissions, like super-user. This example uses ``postgres`` super-user.

First, prepare a database for pgbench with superuser, and make sure that a regular user can't access to the tables.

.. code-block:: none
$ createdb -U postgres mydb
$ pgbench -i mydb -U postgres
$ pgbench -i -U postgres mydb
NOTICE: table "pgbench_history" does not exist, skipping
NOTICE: table "pgbench_tellers" does not exist, skipping
NOTICE: table "pgbench_accounts" does not exist, skipping
NOTICE: table "pgbench_branches" does not exist, skipping
creating tables...
100000 of 100000 tuples (100%) done (elapsed 0.68 s, remaining 0.00 s).
100000 of 100000 tuples (100%) done (elapsed 0.70 s, remaining 0.00 s).
vacuum...
set primary keys...
done.
$ pgbench -c 1 -t 1 -U snaga -n mydb
ERROR: permission denied for relation pgbench_branches
$
Second, start collecting table access statistics, and run pgbench transactions with superuser privilege.
Second, start collecting table access statistics, and run pgbench transactions.

.. code-block:: none
$ pt-privilege-autogen -d mydb start
[2015-07-30 05:57:21] INFO: Collecting access statistics started.
$ pt-privilege-autogen -U postgres -d mydb start
[2015-08-04 04:40:45] INFO: Collecting access statistics started.
$ pgbench -c 1 -t 1 -U postgres -n mydb
transaction type: TPC-B (sort of)
scaling factor: 1
Expand All @@ -86,15 +89,15 @@ Second, start collecting table access statistics, and run pgbench transactions w
number of transactions per client: 1
number of transactions actually processed: 1/1
latency average: 0.000 ms
tps = 15.284443 (including connections establishing)
tps = 19.093079 (excluding connections establishing)
tps = 14.402581 (including connections establishing)
tps = 20.464964 (excluding connections establishing)
$
Then, generate an access policy file, and apply it to the database. A regular user ``snaga`` is granted least privileges for four tables here.

.. code-block:: none
$ pt-privilege-autogen -d mydb generate
$ pt-privilege-autogen -U postgres -d mydb generate snaga
-- Database
REVOKE ALL ON DATABASE "mydb" FROM "public";
Expand All @@ -115,7 +118,7 @@ Then, generate an access policy file, and apply it to the database. A regular us
GRANT SELECT,UPDATE ON TABLE "public"."pgbench_tellers" TO "snaga";
$ pt-privilege-autogen -d mydb generate > grant.sql
$ pt-privilege-autogen -U postgres -d mydb generate snaga > grant.sql
$ psql -f grant.sql -U postgres mydb
REVOKE
GRANT
Expand All @@ -125,19 +128,18 @@ Then, generate an access policy file, and apply it to the database. A regular us
REVOKE
REVOKE
REVOKE
REVOKE
GRANT
GRANT
GRANT
GRANT
$
Finally, stop collecting access statistics, and make sure that the regular user can now run pgbench transaction on the database with the least privileges.
Finally, stop collecting access statistics, and make sure that the regular user ``snaga`` can now run pgbench transaction on the database with the least privileges.

.. code-block:: none
$ pt-privilege-autogen -d mydb stop
[2015-07-30 05:58:38] INFO: Collecting access statistics stopped.
$ pt-privilege-autogen -U postgres -d mydb stop
[2015-08-04 04:44:21] INFO: Collecting access statistics stopped.
$ pgbench -c 1 -t 1 -U snaga -n mydb
transaction type: TPC-B (sort of)
scaling factor: 1
Expand All @@ -147,6 +149,6 @@ Finally, stop collecting access statistics, and make sure that the regular user
number of transactions per client: 1
number of transactions actually processed: 1/1
latency average: 0.000 ms
tps = 11.191566 (including connections establishing)
tps = 14.290001 (excluding connections establishing)
$
tps = 33.598764 (including connections establishing)
tps = 82.182774 (excluding connections establishing)
$

0 comments on commit 0fda93b

Please sign in to comment.